一、问题出现
Redis集群本身已经具备高可用特性了,即使其中一个或多个节点挂掉,Redis Cluster会实时故障自动转移。但是如果发生了机房故障(断电、断网等极端情况),如果应用方降级或者容错机制做的不好甚至业务本身不能降级,或者会丢失重要数据,或者可能瞬间会跑满应用的线程池造成服务不可用,对于一些重要的服务来说是非常致命的。
为了应对像机房故障这类情况,保证应用方在这种极端情况下,仍然可以正常服务(系统正常运行、数据正常),所以需要给出一个Redis跨机房的方案。
二、实现思路和方案
1、你可能会想,把节点分散到不同的机房不就可以了吗?这种方案理论上是可以,但是延时会很大,此方案不可行。
2、我试图用主从的方式,A机房的节点去拉取B机房的节点,但是Redis集群模式已经不再支持主从的,单实例确实可以通过主从去同步数据,此方案也不可行。
3、网上搜了一些解决方案,Codis方案虽然在负载和横向动态扩容方面做了优化,但是并没有提供底层数据同步问题,而且也有缺陷(负载不会取最近,延迟最低的实例),我们后续再对codis细说。此方案不可行。
4、如果要自动研发一款底层数据同步,确实比较费劲,需要花费大量的时间成本。
5、很多大型公司有现成的开源工具。比如唯品会的一款开源工具redis-migrate-tool还不错。
redis-migrate-tool 具有以下特点:
快速。
多线程。
基于redis复制。
实时迁移。
迁移过程中,源集群不影响对外提供服务。
异构迁移。
支持Twemproxy集群,redis cluster集群,rdb文件 和 aof文件。
过滤功能。
当目标集群是Twemproxy,数据会跳过Twemproxy直接导入到后端的redis。
迁移状态显示。
完善的数据抽样校验(-C redis_check)。
划重点 实时迁移迁移过程中,源集群不影响对外提供服务
原理是将源redis的数据复制到目标Redis,且支持多种策略:
从单一实例迁移数据到twemproxy集群(single to twemproxy)
从twemproxy集群迁移数据到redis集群(twemproxy to redis cluster)
从一个redis集群迁移数据到另一个集群(redis cluster to another redis cluster)
从.rdb文件导入数据到redis集群(rdb file to redis cluster)
保存redis集群的数据到.rdb(redis cluster to rdb file)
从.aof文件导入数据到redis集群(aof file to redis cluster)
从redis集群迁移数据到单一实例(redis cluster to single)
从单一实例迁移数据到redis集群(single to redis cluster)
三、安装
1、先安装依赖
#yum -y install automake libtool autoconf bzip2
2、下载并安装redis-migrate-tool
#mkdir /usr/local/software
#cd /usr/local/software
#git clone https://github.com/tanruixing88/redis-migrate-tool.git
(如果提示git未安装,请先安装git:yum -y install git)
#cd redis-migrate-tool
#autoreconf -fvi
#./configure
#make
#cp src/redis-migrate-tool /usr/local/bin/redis-migrate-tool
Ok,到此安装就算成功了
接下来就算配置文件了(/usr/local/software/ redis-migrate-tool/rmt.conf)
#vim /usr/local/software/ redis-migrate-tool/rmt.conf
修改为以下内容:
[source]
type: redis cluster
servers:
- 172.16.40.210:7000
- 172.16.40.210:7001
- 172.16.40.210:7002
- 172.16.40.210:7003
- 172.16.40.210:7004
- 172.16.40.210:7005
[target]
type: redis cluster
servers:
- 172.16.54.6:7000
- 172.16.54.6:7001
- 172.16.54.6:7002
- 172.16.54.6:7003
- 172.16.54.6:7004
- 172.16.54.6:7005
[common]
listen: 0.0.0.0:8888
3、运行
#/usr/local/bin/redis-migrate-tool -c /usr/local/bin/redis-migrate-tool/rmt.conf -o /usr/local/bin/redis-migrate-tool/log -d
(注意:-d指定为后台运行,如果再次运行可能需要杀死占用当前端口的进程。netstat -tnulp查看找到redis-migrate-tool的端口号,kill -9 [端口号]杀死再运行。)
4、查看日志,并验证是否启动成功
查看运行日志:
#tail -f /usr/local/bin/redis-migrate-tool/log
输出如下表示启动没问题:
5、数据校验:
#/usr/local/bin/redis-migrate-tool -c /usr/local/software/redis-migrate-tool/rmt.conf -o /usr/local/software/redis-migrate-tool/log -C redis_check
5、校验数据同步问题
如图可以看出40段机房的Redis集群的数据已经同步到54段机房的Redis集群
6、如果要做跨机房双向同步,则必须在A机房和B机房都安装redis-migrate-tool,修改对应配置文件的源和目标。
四、扩展
1、配置文件(rmt.conf)说明:
配置文件包含三部分:[source], [target] 和 [common]
迁移工具的来源(source)可以是:单独的redis实例,twemproxy集群,redis cluster,rdb文件,aof文件。迁移工具的目标(target)可以是:单独的redis实例,twemproxy集群,redis cluster,rdb文件。
[source]/[target]:
type:single:单独的redis实例;twemproxy:twemproxy集群;redis cluster:redis集群;rdb file:.rdb文件;aof file:.aof文件
servers:redis地址组,如果type:twemproxy,则为twemproxy配置文件,如果type:rdb file,则为rdb文件名。
redis_auth:连接redis服务的认证auth。
timeout:读写redis服务的超时时间(ms),默认为120000ms
hash:哈希方法名。仅当type:twemproxy有效。可以为one_at_a_time、md5、crc16、crc32、crc32a、fnv1_64、fnv1a_64、fnv1_32、fnv1a_32、hsieh、murmur、jenkins。
hash_tag:用来哈希的关键key的两个字符,例如"{}" 或 "$$"。仅当type:twemproxy有效。只要标签内的关键key是相同的,能够将不同的键映射到同一服务器。
distribution:键的分布模式。仅当type:twemproxy有效。可以为 ketama、modula、random。
[common]:
listen:监听的地址和端口。默认为127.0.0.1:8888
max_clients:可监听端口的最大连接数。默认为100
threads:工具可用的最多线程数。默认为cpu内核数。
step:解析请求的步数。默认为1,数字越大,迁移越快,需要越多的内存。
mbuf_size:请求的缓存大小(M),默认为512M
noreply:是否检查目标组的回复,默认为false
source_safe:是否保护源组机器的内存安全。默认为true,工具将允许在源组的同一台机器同时只有一个redis生成.rdb。
dir:工作目录。用来存储文件,例如rdb文件,默认为当前目录。
filter:过滤不符合表达式的Key,默认为NULL,支持通配符为glob-style风格
? :1个任意字符。例如 h?llo 匹配 hello, hallo , hxllo
* :0个或多个任意字符。例如 h*llo 匹配 hllo , heeeello
[characters]:匹配任意一个方括号内的字符,比如[abc],要么匹配a,要么匹配b,要么匹配c。例如 h[ae]llo 匹配 hello , hallo, 但不匹配 hillo。
[^character]:排除方括号内的字符。例如h[^e]llo 匹配 hallo, hbllo, ... 但不匹配 hello。
[character-character]:表示2个字符范围内的都可以匹配,如[a-z],[0-9]。例如h[a-b]llo 匹配 hallo 和 hbllo。
\用来转移特殊字符。