Tair的桶分布策略介绍及新的机器级位置安全优先策略实现

  Tair在其intro wiki 上介绍了其现有的桶分布策略:

  程序提供了两种生成分配表的策略, 一种叫做负载均衡优先, 一种叫做位置安全优先。

  负载均衡优先

  当采用负载优先策略的时候, config server会尽量的把桶均匀的分布到各个data server上. 所谓尽量是指在不违背下面的原则的条件下尽量负载均衡. 1 每个桶必须有COPY_COUNT份数据 2 一个桶的各份数据不能在同一台主机上;

  位置安全优先

  位置安全优先原则是说, 在不违背上面两个原则的条件下, 还要满足位置安全条件, 然后再考虑负载均衡. 位置信息的获取是通过 _pos_mask(参见安装部署文档中关于配置项的解释) 计算得到. 一般我们通过控制 _pos_mask 来使得不同的机房具有不同的位置信息. 那么在位置安全优先的时候, 必须被满足的条件要增加一条, 一个桶的各份数据不能都位于相同的一个位置(不在同一个机房).

  wiki上还针对位置安全优先策略进行了进一步的补充:

  “这里有一个问题, 假如只有两个机房, 机房1中有100台data server, 机房2中只有1台data server. 这个时候, 机房2中data server的压力必然会非常大. 于是这里产生了一个控制参数 _build_diff_ratio(参见安装部署文档). 当机房差异比率大于这个配置值时, config server也不再build新表. 机房差异比率是如何计出来的呢? 首先找到机器最多的机房, 不妨设使RA, data server数量是SA. 那么其余的data server的数量记做SB. 则机房差异比率=|SA – SB|/SA. 因为一般我们线上系统配置的COPY_COUNT是3. 在这个情况下, 不妨设只有两个机房RA和RB, 那么两个机房什么样的data server数量是均衡的范围呢? 当差异比率小于 0.5的时候是可以做到各台data server负载都完全均衡的.这里有一点要注意, 假设RA机房有机器6台,RB有机器3台. 那么差异比率 = 6 – 3 / 6 = 0.5. 这个时候如果进行扩容, 在机房A增加一台data server, 扩容后的差异比率 = 7 – 3 / 7 = 0.57. 也就是说, 只在机器数多的机房增加data server会扩大差异比率. 如果我们的_build_diff_ratio配置值是0.5. 那么进行这种扩容后, config server会拒绝再继续build新表.”

 

  我们在生产环境中使用时,起初使用的是负载均衡优先,对应的配置文件group.conf中的_build_stategy=1。但是在线上环境中,为了充分利用磁盘IO,经常会在同一台服务器上跑多个dataserver(一个磁盘对应一个dataserver),而通过cst_monitor查看桶分布表,发现wiki中提到的必须遵守的原则“2 一个桶的各份数据不能在同一台主机上”并没有得到满足,只是保证了同一个桶的各份数据不落在同一个dataserver上。这样有一个很严重的问题,如果某台服务器宕机了,就非常有可能导致一个桶的主备bucket都无法对外服务,导致config server拒绝build新的桶分布表(内存级的可能就丢数据了,磁盘级的会造成落在该台服务器上的所有的桶都会写失败)。

     

      这是个很严重的问题,我们首先想到的是复用默认的“位置安全优先策略”,将group.conf中的_pos_mask设成4294967295(0xFFFFFFFF),这样每一台机器都会被认为是不同的位置。但是在使用中发现,程序并没有按照我们预想的那样在多个机器之间分散主备bucket,而是拒绝建表。查看了建表策略的代码table_builder2.cpp 发现这个策略只适合于两个位置,即适用于集群在两个机房间的负载均衡,并不适合更多位置(>=3)的位置安全,我们简单的针对机器ip做mask是无效的。

     

      接下来,我们考虑自己实现一个新的位置安全策略,但仔细看了负载均衡优先策略的代码table_builder1.cpp 后,发现可以通过修改table_builder1的代码,实现我们想要的机器级位置安全策略。

      默认的负载均衡优先策略代码,在不同的consider级别下考虑了如下条件(is_this_node_ok()):

      1.主bucket在各实例上分布均匀;

      2.当前主备bucket在实例上分布均匀;

      3.在建表主备bucket在备实例上分布均匀;

      4.主备不在同一个实例上;

      5.主备不在同一个position上(port:ip&mask);

      负载均衡优先策略共有四个consider级别(CONSIDER_ALL\CONSIDER_POS\CONSIDER_BASE\CONSIDER_FORCE),以此考虑4个级别,满足的条件逐渐放松,直到可以成功建表。四个不同的CONSIDER级别分别满足的条件如下:

      CONSIDER_ALL: 1, 2, 4, 5

      CONSIDER_POS: 1, 3, 4, 5

      CONSIDER_BASE: 1, 3, 4

      CONSIDER_FORCE: 1, 4

      可见,默认的策略优先满足的是3(均衡),而非5(postion安全)。这样问题就很简单了,只需要把CONSIDER_BASE满足的条件由1、3、4改成1、4、5,就可以实现我们需要的机器级的位置安全优先策略,同时兼顾机器级别的负载均衡(需要自行保证不同机器的dataserver数尽量均衡,同时group.conf的_pos_mask设成4294967295)。

      给出如下patch:

@@ -50,7 +50,7 @@
         }
       }
       else {
-        if(option_level != CONSIDER_FORCE &&
+        if(option_level < CONSIDER_BASE &&
            tokens_count_in_node_now[node_id] >= tokens_per_node_min + turn &&
            max_count_now >= tokens_per_node_max_count + turn) {
           return TOOMANY_BUCKET;
@@ -64,7 +64,7 @@
           if(hash_table_dest[i][node_idx].first == node_id.first) {
             return SAME_NODE;
           }
-          if(option_level < CONSIDER_BASE) {
+          if(option_level <= CONSIDER_BASE) {
             if(hash_table_dest[i][node_idx].second == node_id.second) {
               return SAME_POS;
             }

      非常简单的修改。(我们是额外添加了一个新的table_builder3.cpp来作为这个策略的实现,因此还需要对group_info.cpp做修改,生成新策略的p_table_builder,大家可以自行修改)。

posted @ 2013-04-26 19:09  刘浩de技术博客  阅读(1813)  评论(0编辑  收藏  举报