目标是实现redis集群的无感知弹性扩容
关键点
1是无感知,即对redis集群的用户来说服务ip和port保持不变
2.弹性扩容,指的是在需要时刻可以按照业务扩大redis存储容量。
最原始的twemproxy+redis集群架构如下图1所示
其中twemproxy-A代理后面接了3个redis实例,作为集群使用,如果1个redis示例有10G存储能力,那么
目前这个架构具有10G*3=30G的存储能力。
当业务猛增,存储空间不够时,最简单的扩容方案如下图2所示:
这个方案最大的问题有2个
1.后端新增一个redis实例之后,虽然有一致性hash保证大部分数据还会走原先的路由,但仍有小部分旧的数据会被
路由到新的redis-4中,即丢失一小部分旧的数据
2.扩容效果不理想,一开始时,redis-4的已用存储是0,理想最好的方式是旧的数据还走之前的路由,新的数据路由到redis-4中
为了解决上述方案的不同,我提出了一个twemproxy二级代理的方案,如下图3所示:
这个方案有1个关键点,即怎么实现旧的数据走之前的路由,新的数据走redis-4的路由,这就用到了
hash_tag的预分配(即提前占坑的思想),使用hash_tag作为二级twemproxy的路由标示,具体操作如下:
1.twemproxy-C的hash_tag 设置为(),twemproxy-A和twemproxy-B的hash_tag设置为{}
2.插入形如key_(0)_{1},key_(1)_{1}的2个key,假设key_(0)_{1}路由到了twemproxy-A,key_(1)_{1}路由到了twemproxy-B
3.那么旧的服务插入数据的标示就是key_(0)_{xxxx},新的数据插入的标示就是key_(1)_{xxxx}
注意点如下:
1.一开始可以预先分配多一些二级代理,以备不时只需
2.一开始需要测试清楚,哪些()标示走哪些对应的二级代理。
这个方案实现了弹性扩容,但是没有实现无感知,即需要重启twemproxy-C,为了实现无感知所以需要使用vip
,如图4所示:
无感知的解决类似”双buffer交换“的思路,即上图的twemproxy-C和twemproxy-D,当需要重启一级代理时
1.vip只访问到twemproxy-C
2.更改twemproxy-D使用最新的配置,重启
3.vip切换服务到只访问twemproxy-D
当需要重启1级代理时,以此循环。