Table of Contents
在 这篇blog 里面提到2种扩容:
这里考虑第二种思路.
简单可依赖
总之, 就算redis3.0 的cluster 成熟以后, 还是需要这样的一套迁移方案.
mysql 的主从同步是基于binlog, redis主从是一个op buf, mongo主从同步是oplog.
redis里的aof就是类似binlog, 记录每个操作的log
所以, 我们可以利用aof, 把它当作binlog, 用于做迁移, 具体的迁移我们在mysql, mongo里面都多次用过了, 分三步:
redis的aof包含了基准数据和增量, 所以我们只需要把旧集群中redis实例上的aof重放到新集群, 重放追上时修改上层, 把入口换为新集群即可.
aof不像binlog那样可以重做 redolog, binlog 记录的操作是 幂等(idempotent) 的, 意味着如果失败了, 可以重做一次.
这是因为binlog记录的是操作的结果, 比如:
op log --------------------------- set x 0 x = 0 incr x x = 1 incr x x = 2
但是redis的aof记录的是操作:
op log --------------------------- set x 0 x = 0 incr x incr x incr x incr x
这就是说, 如果我们在重放aof的过程中出错(比如网络中断):
只能清除目标集群的数据重新迁移一次 ( redis-mgr 里面有 clean-keys 命令按照前缀清除)
不过, 好在redis单实例的afo数据都不大, 一般10G左右, 重放大约20min就能完成, 出错的概率也很小. (这也是redis可以这样做, 而其他持久存储比如mysql, mongo必须支持断点同步的原因)
前面说的步骤是:
追aof是一个动态的过程, 追上后, 新的写操作马上就来, 所以这里追上的意思是说, 新的写入马上会被消化掉.
但是考虑这样一种场景:
假设client上做对x做两次set(一个机器上做两次, 或者两个app-server上分别做):
client old_cluster new_cluster ----------------------------------------------- set x 1(a) set x 1(客户操作) -----------------------------------------------> 切流量到new_cluster set x 2(b) set x 2 (客户操作) set x 1 (b 操作被重放到 new_cluster)
a操作还没同步到new_cluster, 流量就已经切到了new_cluster, 这时候对同一个key的更新, 会被老集群上的操作覆盖掉.
解决:
有两份代码:
原理就是不断的看aof文件是否有更新, 有更新的话写到目标集群, 支持 按前缀过滤, 加前缀, 换前缀之类的操作.
redis-mgr 里面集成了一个命令来方便操作:
#从cluster1迁移到cluster5 ./bin/deploy.py cluster1 replay_aof cluster5 'prefix_'