这几天在研究如何做Redis的高可用容灾方案,查询了资料和咨询DBA同行,了解到Redis可以基于consul和sentinel实现读写分离以及HA高可用方案。本文讲述基于consul的Redis高可用方案实践。
感谢邓亚运的提示和资料协助。
Consul是HashiCorp公司基于go语言研发用于服务发现和配置共享开的分布式高可用的系统。提供内服务注册与发现框架,分布一致性协议实现,健康检查,Key/Value存储,多数据中心方案,以及Web UI支持,相比于Zookeeper,Consul不再需要依赖其他工具。
Consul提供的如下关键特性:
Consul是分布式的高可用系统,该系统中有两种角色Server 和Client。通过启动agent时指定Server或者client模式实现Consul集群中角色划分。
Consul Server:服务端用于保存Consul Cluster的状态信息, 实现数据一致性,响应RPC请求。在局域网内与本地客户端通讯, 通过广域网与其他数据中心通讯。每个Consul Cluster的Server数量推荐为3或5个。
Consul Client:客户端,只维护自身的状态, 并将HTTP和DNS接口请求转发给服务端。
注意:
Server和Client的角色和Consul Cluster上运行的应用服务无关, 是基于Consul层面的一种角色划分。
环境准备
server: 10.9.51.13
client: 10.215.20.13 10.215.20.7 10.9.141.52
再分别启动三个client节点 nohup consul agent -config-dir=/etc/consul.d > /data/consul/consul.log &
2018/05/04 12:02:23 [INFO] agent: Join LAN completed. Synced with 1 initial agents 说明client节点已经加入到了consul集群。
consul operator raft list-peers Node ID Address State Voter RaftProtocol qabb-rdsa0 93b8e2a9-1ae1-3726-2993-c4f068ffd9b4 10.9.51.13:8300 leader true 3
现在 qabb-r1db13 qabb-r1db7 上还没部署服务,所以显示为0个服务。接下来我们开始部署redis服务,构建基于Consul的Redis的高可用架构
Redis现有高可用架构sentinel遇到的问题
Consul 可以满足以上需求,配置两个DNS服务,一个是master的写服务,利用consul自身的服务健康检查和探测功能,自动发现新的master。 然后定义一个slave的读服务,基于DNS本身,能够对slave角色的redis IP做轮询,实现负载均衡的效果。
其实首先我们要在搭建一主两从的redis集群,因为本文是模拟练习,所以在client节点上部署。具体搭建过程省略,Redis的主从配置如下
master 10.215.20.13:6380
slave 10.215.20.7:6380
10.9.141.52:6380
我们需要在每个client节点的/etc/consul.d/下面服务配置文件如下:
$ ll
total 12
-rw-r--r-- 1 root root 217 May 4 18:54 client.json
-rw-r--r-- 1 root root 317 May 4 18:55 r-6380-redis-test.json
-rw-r--r-- 1 root root 320 May 4 18:54 w-6380-redis-test.json
redis 主节点的服务定义配置文件 W-6380-redis-test.json
{
"services": [
{
"name": "w-6380-redis-test",
"tags": [
"master-test-6380"
],
"address": "10.215.20.13",
"port": 6380,
"checks": [
{
"args":["sh","-c","/data/consul/shell/check_redis_master.sh 6380 "],
"interval": "15s"
}
]
}
]
}
redis 从节点的服务定义配置文件 r-6380-redis-test.json
{
"services": [
{
"name": "r-6380-redis-test",
"tags": [
"slave-test-6380"
],
"address": "10.215.20.7",
"port": 6380,
"checks": [
{
"args": ["sh","-c","/data/consul/shell/check_redis_slave.sh 6380 "],
"interval": "10s"
}
]
}
]
}
关于服务的定义文件这里做简单说明:
Consul 默认会根据names的值定义DNS域名,默认以 .service.consul 结尾。不过我们可以利用domain参数修改。
根据上面的Redis主从服务定义配置文件,Consul client节点向server集群注册后,对应有两个域名:
w-6380-redis-test.service.consul 对应Redis master服务器ip。
r-6380-redis-test.service.consul 对应两个slave服务器ip,客户端发送请求时DNS轮训随机分配一个slave ip。
其中"args": ["sh","-c","/data/consul/shell/checkredisslave.sh 6380 "]代表对redis 6380 端口进行健康检查,如果异常返回2,consul client 会通知server端对异常服务进行服务治理。
此时我们检查web-ui,
dig @10.9.51.13 -p 8600 w-6380-redis-test.service.consul
显示 10.215.20.13 对应于 w-6380-redis-test.service.consul
dig @10.9.51.13 -p 8600 r-6380-redis-test.service.consul
显示2个slave ip 10.215.20.7 ,10.9.141.52 对应 r-6380-redis-test.service.consul.
注意因为是测试,dns配置并未在我们公司的dns 域名服务器器做解析,所以日志中提示
;; WARNING: recursion requested but not available
我们需要做2种容灾演练
继续关闭其他redis slave (10.9.141.52:6380)实例
可以看到结果符合预期: 当多个从库依次关闭,dns域名后端ip发生变化,会逐步剔除关闭的实例对应的ip,所有的slave关闭之后,域名r-6380-redis-test.service.consul 后端的ip指定到redis master对应的ip上。
此时我们再检查dns 域名 主库对应的dns域名 w-6380-redis-test.service.consul.对应ip已经变为10.215.20.7
r-6380-redis-test.service.consul. 对应的ip 减少了一个,变为10.9.141.52。
从目前的结果来看 切换符合预期。 另外说一下不符合预期的地方,在老的master 重新起来之后,sentinel会将老的master设置为新的slave,但是Consul 对应的dns 并未及时更新准确,需要执行consul reload 才可以。
生产过程中要注意这点,切换之后及时更新DNS缓存。
从环境搭建以及测试结果来看,Consul这款工具使用起来十分简便,配合Redis sentinel 切换速度符合预期,上线生产环境时需要注意dns缓存时间的配置,以及DNS域名管理方面的支持。另外更多的技术知识点还是要多阅读Consul官方文档。