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_ALLCONSIDER_POSCONSIDER_BASECONSIDER_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: