Apache Geode/GemFire 数据分区和路由机制浅析

本篇文章主要讲解Apache Geode/GemFire 是如何进行数据分区的。

GemFire和大多数分布式系统一样都采用 Hash 的方式对数据进行分区,将 Entry 数据分布到 PartitionedRegion 当中,大家都知道 Entry 数据主要保存在 ConcurrentHashMap 中,ConcurrentHashMap存放在 Bucket 中,在 PR 服务器启动后会为 PartitionedRegion创建相应的Bucket 来保存这个ConcurrentHashMap。因此它们三者的映射关系如下所示:

Entry—> ConcurrentHashMap—> Bucket—> Region

如何进行数据分区?

当前端应用对Entry 进行操作后,Entry 会按照如下的步骤分区到PR 服务器上。

1.Entry 在插入到分布式集群的某台节点服务器过程中,会放到 PR 创建的 Bucket 中。

2.在进行 Put 操作时, 会产生一个EntryOperation 事件,在这个 Event 事件中可以找到PartionedRegion,和要进行 Put 操作的 Key。这个路由的对象就是一般的 POJO 操作类。

3.在获得路由对象上,从条目操作中获得 Key 键,在通过 Key 键来得到相关的对象Object。

4.接下来再通过 Key来获得bucketId, 再通过bucketId获得 PR,给定一个key/routing对象, 运行hashCode()生成一个 long 值, 然后用这个值与 bucket size 取模得到bucketId值。

   * 为了更好地进行哈希key分布, 使用MD5、SHA或其他的 ID 生成方法.

详见PartionedRegionHelper 的getHashKey方法.

private static int getHashKey(EntryOperation event, PartitionedRegion pr,

      Operation operation, Object key, Object value, Object callbackArgument) {

    // avoid creating EntryOperation if there is no resolver

    if (event != null) {

      pr = (PartitionedRegion)event.getRegion();

      key = event.getKey();

      callbackArgument = event.getCallbackArgument();

    }

    PartitionResolver resolver = getResolver(pr, key, callbackArgument);

    Object resolveKey = null;

    if (pr.isFixedPartitionedRegion()) {

      String partition = null ;

      if (resolver instanceof FixedPartitionResolver) {

        Map<String, Integer[]> partitionMap = pr.getPartitionsMap();

        if (event == null) {

          event = new EntryOperationImpl(pr, operation, key, value,

              callbackArgument);

        }

        partition = ((FixedPartitionResolver)resolver).getPartitionName(

            event, partitionMap.keySet());

        if (partition == null) {

          Object[] prms = new Object[] { pr.getName(), resolver };

          throw new IllegalStateException(

              LocalizedStrings.PartitionedRegionHelper_FOR_REGION_0_PARTITIONRESOLVER_1_RETURNED_PARTITION_NAME_NULL.toLocalizedString(prms));

        }

        Integer[] bucketArray = partitionMap.get(partition);

        if (bucketArray == null) {

          Object[] prms = new Object[] { pr.getName(), partition };

          throw new PartitionNotAvailableException(

              LocalizedStrings.PartitionedRegionHelper_FOR_FIXED_PARTITIONED_REGION_0_FIXED_PARTITION_1_IS_NOT_AVAILABLE_ON_ANY_DATASTORE.toLocalizedString(prms));

        }

        int numBukets = bucketArray[1];

        resolveKey = (numBukets == 1) ? partition : resolver.getRoutingObject(event);

      }

      else if (resolver == null) {

        throw new IllegalStateException(

            LocalizedStrings.PartitionedRegionHelper_FOR_FIXED_PARTITIONED_REGION_0_FIXED_PARTITION_RESOLVER_IS_NOT_AVAILABLE.toString(pr.getName()));

      }

      else if (!(resolver instanceof FixedPartitionResolver)) {

        Object[] prms = new Object[] { pr.getName(), resolver };

        throw new IllegalStateException(

            LocalizedStrings.PartitionedRegionHelper_FOR_FIXED_PARTITIONED_REGION_0_RESOLVER_DEFINED_1_IS_NOT_AN_INSTANCE_OF_FIXEDPARTITIONRESOLVER.toLocalizedString(prms));

      }

      return assignFixedBucketId(pr, partition, resolveKey);

    }

    else {

      // Calculate resolveKey.

      if (resolver == null) {

        // no custom partitioning at all

        resolveKey = key;

        if (resolveKey == null) {

          throw new IllegalStateException("attempting to hash null");

        }

      }

      else {

        if (event == null) {

          event = new EntryOperationImpl(pr, operation, key, value,

              callbackArgument);

        }

        // 通过 Entry 操作, 获得一个路由对象, 得到resolveKey, 在通过 resolveKey进行Hash计算

        resolveKey = resolver.getRoutingObject(event);

        if (resolveKey == null) {

          throw new IllegalStateException(

              LocalizedStrings.PartitionedRegionHelper_THE_ROUTINGOBJECT_RETURNED_BY_PARTITIONRESOLVER_IS_NULL.toLocalizedString());

        }

      }

      // Finally, calculate the hash.

      return getHashKey(pr, resolveKey);

    }

  }

如何进行数据感知路由?

 

GemFire 开发了一个Function
Service 模块能够让客户端和服务器节点一起来处理提交的任务。如果数据跨多个节点分区,GemFire能够透明地路由数据执行行为到待处理数据的节点,这样避免了数据跨网络移动,这被称为“数据感知功能路由”。带有数据感知路由功能的应用根本不需要管理数据。

 

GemFire路由数据的执行行为而不是数据本身,GemFire直接路由数据执行行为到需要做并行处理,或汇聚结果的节点。这个特性使得GemFire从根本上降低了执行复杂任务的时间。分布式并行处理活动被抽象出来,与应用调用端无关。

 

 

应用即能够在单点执行,也能在一个小集群并行执行,甚至能够跨整个分布式集群并行执行。

GemFire的并行模型非常类似于Google的Map-Reduce模型。数据感知路由最适合于执行迭代查询或汇聚数据条目的操作。通过数据并处和并行计算,系统的吞吐量显著提升。最重要的是,计算的延迟与并行计算的节点数成反比。

 

单节点的Function执行类似于关系型数据库的Stored
Procedure执行。

 

并行计算之后,结果通过Function中的结果收集器,把处理完的结果会调用ResultCollector统一收集回来。相当于Map-Reduce模型中的输出收集器。

时间: 2024-11-02 20:42:25

Apache Geode/GemFire 数据分区和路由机制浅析的相关文章

Apache Geode/GemFire功能特性简介(1)

  区域   复制区域 在区域中所有的数据被复制到每一个缓存服务器节点.复制区域使用了'multiple masters'复制组织结构.当数据区域被复制(没有分区),对于每一个数据条目没有指定的管理者,来自任意成员的初始更新并发地传播到每一个节点.一旦成功处理了这个事件,ACK作为一个回应发送回初始成员.初始成员接到返回的ACK之后,做出相应地数据更新调用处理.   每一个缓存服务器节点都维护了一份数据的拷贝.所以复制区域模式适合于系统中有大量读操作,少量写操作的情况下.   分区区域 在区域中

Apache Geode/GemFire入门(1)-基本概念和模块

在这个入门中我们将走一遍GemFire应用程序代码,学习GemFire Enterprise基本的特性.这个应用详解了GemFire怎么在VMs宕机情况下并不中断服务.当应用运行时动态地添加更多的存储,并且提供更小的延迟来访问你的数据. 入门概览 主要的概念 本入门涵盖了以下概念: GemFire Distributed System 运行在GemFire上的VMs组成了分布式系统.每一个MV都作为一个GemFire对等体存在.启动GemFire对等体,在每个VM对等体上你创建了一个缓存.每一个

Apache Geode/GemFire入门(2)-基本概念和模块

使用持久化 GemFire支持无共享存储持久化.每一个VM写入他们的region data到自己的磁盘文件中. People region来说,每一个region将要写入整个的region到自己的磁盘文件中.而post region每一份拷贝都将要存在两个不同的peer中.   当你重启持久化成员,你需要调用cacheserver start并行地在每个服务器. 原因是GemFire保证了你完整的数据被在VM重启的时候被恢复.每一个VM只能持久化他自己的post部分.每一个GemFire VM等

Apache Geode 毕业为 Apache 顶级项目

2016年11月21日,Apache软件基金会(the Apache Software Foundation,ASF)宣布 Apache Geode已从Apache孵化器毕业成为顶级项目(Top-Level Project),表明该项目的社区和产品已根据ASF的精英流程和原则得到良好管理. 2016年11月21日,Apache软件基金会(the Apache Software Foundation,ASF)宣布 Apache Geode已从Apache孵化器毕业成为顶级项目(Top-Level

Apache Mesos和数据中心操作系统的崛起

本文讲的是Apache Mesos和数据中心操作系统的崛起,[编者的话]本文是Mesosphere公司的工程师对他们公司产品DCOS的介绍,也顺带介绍了Mesos的架构和功能以及Mesos的init框架Marathon和Cron框架Chronos. 罗杰伊尼亚齐奥是Mesosphere的基础设施自动化工程师和"Mesos实践"的作者. 感谢曼宁出版的团队的慷慨,SysAdvent读者在在https://manning.com/books/mesos-in-action使用代码"

Zend Framework框架路由机制代码分析_php实例

本文分析了Zend Framework框架路由机制代码.分享给大家供大家参考,具体如下: 在框架中,有关路由的调用关系为: 1.apache的mod_rewrite模块把请求路由到框架的启动脚本,一般是index.php: 2.前端控制器Zend_Controller_Front通过dispatch函数进行请求分发: 3.路由器Zend_Controller_Router_Rewrite通过route函数处理路由,对路由器中已有的路由规则,按照加入顺序的逆序(类似于栈,后进先出)对每个route

Apache Mesos 和数据中心操作系统的崛起

Apache Mesos 和数据中心操作系统的崛起 容器和应用程序编排是热门话题,因为组织和工程团队试图尽可能快地部署应用程序和基础设施的更改,同时提高数据中心的整体效率.当你读到容器的文章时,提到Apache Mesos(论文)通常都不会太遥远.你可能想知道Mesos是什么,以及如何将它用于管理大规模应用程序. 在这篇文章中,我将提供Mesos的介绍,总结一些Linux内核和Mesos之间的比较,以帮助你了解它是如何工作的.我将覆盖两个开源项目,这两个项目让工程团队能快速,轻松地部署在集群上的

Excel表格数据分区密码怎么设置

  大家在使用office2010制作Excel表格的时候不知道office2010怎么设置Excel表格数据分区密码,其实方法很简单哦,只要在office2010Excel表格里新建区域然后选中分区就可以进行密码设置了哦,下面就和小编一起来看看吧. office2010设置Excel表格数据分区密码方法: 第一步:首先打开office2010 Excel表格,输入数据.   第二步:点击主菜单上的审阅,点击允许用户编辑区域.   第三步:点击新建区域,选中所选区域,并设置密码123(密码自己随

ASP.NET MVC的路由机制:命名路由

首先看一下命名路由和没有命名的差别: 命名路由: routes.MapRoute( name: "Test", // Route name url: "code/p/{action}/{id}", // URL with parameters defaults: new { controller = "Section", action = "Index", id = UrlParameter.Optional } // Par