使用哨兵模式部署redis高可用集群
文章目录
很早以前就听说过redis社区推崇一种哨兵模式的高可用集群部署模式,今天花时间研究了一下,正好记录下来。
哨兵模式
哨兵简介
哨兵模式是在Redis 2.8 版本开始引入的。哨兵的核心功能是主节点的自动故障转移。
下面是 Redis 官方文档对于哨兵功能的描述:
- 监控(Monitoring):哨兵会不断地检查主节点和从节点是否运作正常。
- 自动故障转移(Automatic failover):当主节点不能正常工作时,哨兵会开始自动故障转移操作,它会将失效主节点的其中一个从节点升级为新的主节点,并让其他从节点改为复制新的主节点。
- 配置提供者(Configurationprovider):客户端在初始化时,通过连接哨兵来获得当前 Redis 服务的主节点地址。
- 通知(Notification):哨兵可以将故障转移的结果发送给客户端。
其中,监控和自动故障转移功能,使得哨兵可以及时发现主节点故障并完成转移;而配置提供者和通知功能,则需要在与客户端的交互中才能体现。
哨兵的架构
典型的哨兵架构图如下所示:
它由两部分组成,哨兵节点和数据节点:
- 哨兵节点:哨兵系统由一个或多个哨兵节点组成,哨兵节点是特殊的 Redis 节点,不存储数据。
- 数据节点:主节点和从节点都是数据节点。
哨兵模式的部署
参考官方文档手工部署一个哨兵模式的redis集群还是挺麻烦的,网上有不少这方面的操作指引,这里就不详细介绍了。
云原生时代,这里还是介绍一个快速在kubernetes中部署哨兵模式redis集群的办法,云原生时代部署基础组件就是方便啊。
因为在本机的k8s集群测试,k8s集群里只有一个节点,因此稍微修改部署时的values.yaml:
redis-ha-values-custom.yaml
## Node labels, affinity, and tolerations for pod assignment
## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#nodeselector
## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#taints-and-tolerations-beta-feature
## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity
# Just for local develop environment
affinity: {}
然后直接部署redis-ha:
helm install --namespace test --name redis-ha stable/redis-ha -f ./redis-ha-values-custom.yaml
很快在test命名空间就会发现redis的pod都正常运行了:
$ kubectl get pod -n test
NAME READY STATUS RESTARTS AGE
redis-ha-server-0 2/2 Running 0 1h
redis-ha-server-1 2/2 Running 0 1h
redis-ha-server-2 2/2 Running 0 1h
$ kubectl -n test get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
redis-ha ClusterIP None <none> 6379/TCP,26379/TCP 2h
redis-ha-announce-0 ClusterIP 10.103.179.132 <none> 6379/TCP,26379/TCP 2h
redis-ha-announce-1 ClusterIP 10.98.58.246 <none> 6379/TCP,26379/TCP 2h
redis-ha-announce-2 ClusterIP 10.97.66.79 <none> 6379/TCP,26379/TCP 2h
总共3个pod,每个pod里有两个容器,一个是redis,一个是sentinel。整个部署方案的相关参数默认都配置得比较合理,完整的参考列表见这里。
这里有特别注意,使用哨兵模式的客户端应该要配置哨兵的访问地址,如redis-ha-announce-0.test.svc.cluster.local:26379
。有3个哨兵的访问地址,一般客户端这边会将这3个哨兵都备份下来,这样将可以避免sentinel成为单点故障。
使用哨兵模式redis集群
从架构上看,要想使用哨兵模式的redis集群,客户端必须与哨兵先通信,拿到可用redis主节点信息后,再连接redis主节点,所以对redis客户端有一些要求。
好消息是有些redis连接库已经支持了sentinel模式,如go-redis。即使有些redis库并不支持,也可以轻松加上对sentinel模式的支持,如这里。
最后看了下harbor的代码,发现它目前的代码还不支持sentinel模式,正好可以改明儿把这块功能做上,给官方发Pull Request。
bootstrap.go
// Load and run the worker pool
func (bs *Bootstrap) loadAndRunRedisWorkerPool(ctx *env.Context, cfg *config.Configuration) (pool.Interface, error) {
redisPool := &redis.Pool{
MaxActive: 6,
MaxIdle: 6,
Wait: true,
Dial: func() (redis.Conn, error) {
return redis.DialURL(
cfg.PoolConfig.RedisPoolCfg.RedisURL,
redis.DialConnectTimeout(dialConnectionTimeout),
redis.DialReadTimeout(dialReadTimeout),
redis.DialWriteTimeout(dialWriteTimeout),
)
},
TestOnBorrow: func(c redis.Conn, t time.Time) error {
if time.Since(t) < time.Minute {
return nil
}
_, err := c.Do("PING")
return err
},
}
......
遇到的坑
整个部署还是比较顺利的,只是部署完毕后,想用redis-cli连接试验一下,结果一直卡住:
# 这里会直接卡住
kubectl -n test run redis-client -t -i --image=redis:5.0.3-alpine -- redis-cli -h redis-ha-announce-0.test.svc.cluster.local -p 26379
改成下面这样就可以了:
kubectl -n test run redis-client -t -i --image=redis:5.0.3-alpine -- sh -c "sleep 3; redis-cli -h redis-ha-announce-0.test.svc.cluster.local -p 26379"
这个应该填kubernetes的bug吧。
参考
文章作者 Jeremy Xu
上次更新 2019-03-12
许可协议 © Copyright 2020 Jeremy Xu