5 Redis Sentinel
哨兵是用来解决redis高可用性的,可以监控集群中主从的变化,然后进行故障转移。
5.1 哨兵讲解
一套合理的监控机制是Sentinel节点判定节点不可达的重要保证,Redis Sentinel通过三个定时监控任务完成对各个
节点发现和监控。
周期10秒监控
每隔10秒,每个Sentinel节点会向主节点和从节点发送info命令获取最新的主从结构,该命令有3个作用:
1、通过向主节点执行info命令,获取从节点的信息,这也是为什么 Sentinel节点不需要显式配置监控从节点
2、当有新的从节点加入时都可以立刻感知出来
3、节点不可达或者故障转移后,可以通过info命令实时更新节点结构信息
周期2秒监控
每隔2秒,每个Sentinel节点会向Redis数据节点的 sentinel:hello 频道上发送该Sentinel节点对于主节点的
判断以及当前Sentinel节点的信息 ,同时每个Sentinel节点也会订阅该频道,来了解其他 Sentinel节点以及它们对主
节点的判断。
该定时任务主要有2个作用:
1、发现新的Sentinel节点:通过订阅主节点的__sentinel__:hello了解其他的Sentinel节点信息,如果是新加入的
Sentinel节点,将该Sentinel节点信息保存起来,并与该Sentinel节点创建连接。
2、Sentinel节点之间交换主节点的状态,作为后面客观下线以及领导者选举的依据。
周期1秒监控
每隔1秒,每个Sentinel节点会向主节点、从节点、其余Sentinel节点发送一条ping命令做一次心跳检测,来确认这些
节点当前是否可达,从而实现检查每个节点的健康状态。
Redis-Sentinel是用于管理Redis集群,主要执行如下任务:
1、监控(Monitoring)
Sentinel会不断地检查你的主服务器和从服务器是否运作正常;
2、提醒(Notification)
当被监控的某个Redis服务器出现问题时,Sentinel可以通过API向管理员或者其他应用程序发送通知;
3、自动故障迁移(Automatic failover)
当一个主服务器不能正常工作时,Sentinel 会开始一次自动故障迁移操作,它会将失效主服务器的其中一个从服务器升级为新的主服务器,并让失效主服务器的其他从服务器改为复制新的主服务器;当客户端试图连接失效的主服务器时,集群也会向
客户端返回新主服务器的地址,使得集群可以使用新主服务器代替失效服务器.
执行流程
哨兵来实现Redis高可用有这5个流程:
1、判断主节点是否是主观下线sdown。(主观是指当前节点判断的结果,sdown表示该节点判断该Redis宕机了)
2、一旦主节点的主观下线到了一定数量,哨兵群进行客观下线odown的判断。(客观指也有其他Sentinel节点也判断该Redis宕机了,并且数量达到了设置的值)
3、哨兵群选举一个Leader,准备对客观下线的节点进行故障转移。
4、Leader选择一个slave a,其他哨兵确认。
5、其他slave成为a的slave。
状态说明
节点状态分为:ok、主观下线、客观下线。
正常(ok):就是节点在线,能够正常响应哨兵的检测和命令。
主观下线(sdown):指单个哨兵,发现主节点在down-after-milliseconds时间内无正确响应,做出的状态判断。
客观下线(odown):指多个哨兵对一个主节点做了sdown判断后,互相使用is-master-down-by-addr命令交流后,做
出的节点已经下线的判断。
5.2 Sentinel搭建
我们这里搭建3个哨兵,采用Docker的方式搭建。
拷贝 /usr/local/server/redis-cluster 下的单节点 redis 到 /usr/local/server/redis-cluster/sentinel/
目录下,分别拷贝3分,命名为 sentinel , sentinel2 , sentinel3 ,并且修改每个目录下的配置文件
sentinel.conf ,修改 port 、监听节点信息、后台运行,配置如下:
第1台的 sentinel.conf :
port 8001
sentinel monitor mymaster 192.168.211.141 7001 2
daemonize yes
第2台的 sentinel.conf :
port 8002
sentinel monitor mymaster 192.168.211.141 7002 2
daemonize yes
第3台的 sentinel.conf :
port 8003
sentinel monitor mymaster 192.168.211.141 7003 2
daemonize yes
参数说明:
sentinel monitor mymaster 192.168.211.141 7003 2
表示执行Sentinel监控,mymaster给当前监控取个名字,可以随意取,192.168.211.141 7003,表示监听该主节点,2
表示有2个sentinel主观(sdown)认为该节点宕机了,则该节点就编程下线状态(odown)
启动:(到每台sentinel的bin目录下执行启动)
./redis-sentinel ./sentinel.conf
.3 Sentinel集群讲解
启动Sentinel后,会有很多日志信息:
我们可以测试下故障自动转移,停掉 redis-7001 节点,可以看到如下日志:
此时哨兵这边会出现如下日志,表示7001节点客观上宕机次数-1,并且将该节点添加为7005的从节点:
日志信息表:
+reset-master <instance details> :主服务器已被重置。 +slave <instance details> :一个新的从服务器已经被 Sentinel 识别并关联。 +failover-state-reconf-slaves <instance details> :故障转移状态切换到了 reconf-slaves 状态。 +failover-detected <instance details> :另一个 Sentinel 开始了一次故障转移操作,或者一个从服务器转换成 了主服务器。 +slave-reconf-sent <instance details> :领头(leader)的 Sentinel 向实例发送了 SLAVEOF 命令,为实例 设置新的主服务器。 +slave-reconf-inprog <instance details> :实例正在将自己设置为指定主服务器的从服务器,但相应的同步过程 仍未完成。 +slave-reconf-done <instance details> :从服务器已经成功完成对新主服务器的同步。 -dup-sentinel <instance details> :对给定主服务器进行监视的一个或多个 Sentinel 已经因为重复出现而被移除 —— 当 Sentinel 实例重启的时候,就会出现这种情况。 +sentinel <instance details> :一个监视给定主服务器的新 Sentinel 已经被识别并添加。 +sdown <instance details> :给定的实例现在处于主观下线状态。 -sdown <instance details> :给定的实例已经不再处于主观下线状态。 +odown <instance details> :给定的实例现在处于客观下线状态。 -odown <instance details> :给定的实例已经不再处于客观下线状态。 +new-epoch <instance details> :当前的纪元(epoch)已经被更新。 +try-failover <instance details> :一个新的故障迁移操作正在执行中,等待被大多数 Sentinel 选中 (waiting to be elected by the majority)。 +elected-leader <instance details> :赢得指定纪元的选举,可以进行故障迁移操作了。 +failover-state-select-slave <instance details> :故障转移操作现在处于 select-slave 状态 —— Sentinel 正在寻找可以升级为主服务器的从服务器。 no-good-slave <instance details> :Sentinel 操作未能找到适合进行升级的从服务器。Sentinel 会在一段时间 之后再次尝试寻找合适的从服务器来进行升级,又或者直接放弃执行故障转移操作。 selected-slave <instance details> :Sentinel 顺利找到适合进行升级的从服务器。 failover-state-send-slaveof-noone <instance details> :Sentinel 正在将指定的从服务器升级为主服务 器,等待升级功能完成。 failover-end-for-timeout <instance details> :故障转移因为超时而中止,不过最终所有从服务器都会开始复制 新的主服务器(slaves will eventually be configured to replicate with the new master anyway)。 failover-end <instance details> :故障转移操作顺利完成。所有从服务器都开始复制新的主服务器了。 +switch-master <master name> <oldip> <oldport> <newip> <newport> :配置变更,主服务器的 IP 和地址 已经改变。 这是绝大多数外部用户都关心的信息。 +tilt :进入 tilt 模式。 -tilt :退出 tilt 模式。
项目中链接Redis集群或者Redis哨兵,只需要配置一下 application.yml即可 :
spring: #Redis redis: #timeout: 50000 sentinel: nodes: 192.168.211.141:8001,192.168.211.141:8002,192.168.211.141:8003 #cluster: # nodes: 192.168.211.141:7001,192.168.211.141:7002,192.168.211.141:7003,192.168.211.141:7004,192.168. 211.141:7005,192.168.211.141:7006
6 # 5 redis集群模式部署
现状问题:
业务发展过程中遇到的峰值瓶颈
- redis提供的服务OPS可以达到10万/秒,当前业务OPS已经达到10万/秒
- 内存单机容量达到256G,当前业务需求内存容量1T
- 使用集群的方式可以快速解决上述问题
6 集群部署3主3从
集群就是使用网络将若干台计算机联通起来,并提供统一的管理方式,使其对外呈现单机的服务效果
集群作用:
1. 分散单台服务器的访问压力,实现负载均衡 2. 分散单台服务器的存储压力,实现可扩展性 3. 降低单台服务器宕机带来的业务灾难
6.1 Cluster集群结构设计
数据存储设计
haha,hash值(crc16(key))% 16384,
- 通过算法设计,计算出key应该保存的位置
- 将所有的存储空间计划切割成16384份,每台主机保存一部分
- 注意:每份代表的是一个存储空间,不是一个key的保存空间
- 将key按照计算出的结果放到对应的存储空间
- 增强其可扩展性
slot
集群内部通讯设计
- 各个数据库相互通信,保存各个库中槽的编号数据
- 一次命中,直接返回
- 一次未命中,告知具体位置
6.2 Cluster集群结构搭建
搭建方式
1. 配置服务器(3主3从)
2. 建立通信(Meet)
3. 分槽(Slot)
4. 搭建主从(master-slave)
Cluster配置:
- 是否启用cluster,加入cluster节点
cluster-enabled yes|no
- cluster配置文件名,该文件属于自动生成,仅用于快速查找文件并查询文件内容
cluster-config-file filename
- 节点服务响应超时时间,用于判定该节点是否下线或切换为从节点
cluster-node-timeout milliseconds
- master连接的slave最小数量
cluster-migration-barrier min_slave_number
Cluster节点操作命令:
- 查看集群节点信息
cluster nodes
2. 更改slave指向新的master ```bash cluster replicate master-id
- 发现一个新节点,新增master
cluster meet ip:port
- 忽略一个没有solt的节点
cluster forget server_id
- 手动故障转移
cluster failover
redis-cli命令
- 创建集群
redis-cli –-cluster create masterhost1:masterport1 masterhost2:masterport2 masterhost3:masterport3 [masterhostn:masterportn …] slavehost1:slaveport1 slavehost2:slaveport2 slavehost3:slaveport3 ––cluster-replicas n
master与slave的数量要匹配,一个master对应n个slave,由最后的参数n决定
master与slave的匹配顺序为第一个master与前n个slave分为一组,形成主从结构
- 添加master到当前集群中,连接时可以指定任意现有节点地址与端口
redis-cli --cluster add-node new-master-host:new-master-port now-host:now-port
- 添加slave
redis-cli --cluster add-node new-slave-host:new-slave-port master-host:master-port --cluster-slave --cluster-master-id masterid
- 删除节点,如果删除的节点是master,必须保障其中没有槽slot
redis-cli --cluster del-node del-slave-host:del-slave-port del-slave-id
- 重新分槽,分槽是从具有槽的master中划分一部分给其他master,过程中不创建新的槽
redis-cli --cluster reshard new-master-host:new-master:port --cluster-from srcmaster-id1, src-master-id2, src-master-idn --cluster-to target-master-id --cluster-slots slots
将需要参与分槽的所有masterid不分先后顺序添加到参数中,使用,分隔
指定目标得到的槽的数量,所有的槽将平均从每个来源的master处获取
- 重新分配槽,从具有槽的master中分配指定数量的槽到另一个master中,常用于清空指定master中的槽
redis-cli --cluster reshard src-master-host:src-master-port --cluster-from srcmaster-id --cluster-to target-master-id --cluster-slots slots --cluster-yes
6.3 docker实战部署
# 创建网卡 docker network create redis --subnet 172.38.0.0/16 # 通过脚本创建6个redis配置 for port in $(seq 1 6); \ do \ mkdir -p /mydata/redis/node-${port}/conf touch /mydata/redis/node-${port}/redis.conf cat << EOF >/mydata/redis/node-${port}/conf/redis.conf port 6379 bind 0.0.0.0 cluster-enabled yes cluster-config-file nodes.conf cluster-node-timeout 5000 cluster-announce-ip 172.38.0.1${port} cluster-announce-port 6379 cluster-announce-bus-port 16379 appendonly yes EOF done docker run -p 637${port}:6379 -p 1637${port}:16379 --name redis-${port} -v /mydata/redis/node-${port}/data:/data -v /mydata/redis/node-${port}/conf/redis.conf:/etc/redis/redis.conf -d --net redis --ip 172.38.0.1${port} redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf # 启动redis docker run -p 6371:6379 -p 16371:16379 --name redis-1 -v /mydata/redis/node-1/data:/data -v /mydata/redis/node-1/conf/redis.conf:/etc/redis/redis.conf -d --net redis --ip 172.38.0.11 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf docker run -p 6372:6379 -p 16372:16379 --name redis-2 -v /mydata/redis/node-2/data:/data -v /mydata/redis/node-2/conf/redis.conf:/etc/redis/redis.conf -d --net redis --ip 172.38.0.12 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf docker run -p 6373:6379 -p 16373:16379 --name redis-3 -v /mydata/redis/node-3/data:/data -v /mydata/redis/node-3/conf/redis.conf:/etc/redis/redis.conf -d --net redis --ip 172.38.0.13 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf docker run -p 6374:6379 -p 16374:16379 --name redis-4 -v /mydata/redis/node-4/data:/data -v /mydata/redis/node-4/conf/redis.conf:/etc/redis/redis.conf -d --net redis --ip 172.38.0.14 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf docker run -p 6375:6379 -p 16375:16379 --name redis-5 -v /mydata/redis/node-5/data:/data -v /mydata/redis/node-5/conf/redis.conf:/etc/redis/redis.conf -d --net redis --ip 172.38.0.15 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf docker run -p 6376:6379 -p 16376:16379 --name redis-6 -v /mydata/redis/node-6/data:/data -v /mydata/redis/node-6/conf/redis.conf:/etc/redis/redis.conf -d --net redis --ip 172.38.0.16 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf # 创建集群 [root@iZwz9gcg5lpw0sp5r86b4dZ ~]# docker exec -it 038e7082bc80 /bin/sh /data # redis-cli --cluster create 172.38.0.11:6379 172.38.0.12:6379 172.38.0.13:6379 172.38.0.14:6379 172.38.0.15:6379 172.38.0.16:6379 --cluster-replicas 1 >>> Performing hash slots allocation on 6 nodes... Master[0] -> Slots 0 - 5460 Master[1] -> Slots 5461 - 10922 Master[2] -> Slots 10923 - 16383 Adding replica 172.38.0.15:6379 to 172.38.0.11:6379 Adding replica 172.38.0.16:6379 to 172.38.0.12:6379 Adding replica 172.38.0.14:6379 to 172.38.0.13:6379 M: 10ace5a4f2a36504adccef1c4470b9e286ef8da1 172.38.0.11:6379 slots:[0-5460] (5461 slots) master M: 7b1aa1d177aabe07f1a44e2139b584398ec965fb 172.38.0.12:6379 slots:[5461-10922] (5462 slots) master M: d48eed0b198ac9acd9aab054d22f4b1127130276 172.38.0.13:6379 slots:[10923-16383] (5461 slots) master S: dca1b6f5ba61f1f2455f936a66ac6c276b602799 172.38.0.14:6379 replicates d48eed0b198ac9acd9aab054d22f4b1127130276 S: e649283604139748551c55344a95d3fdc27b69f1 172.38.0.15:6379 replicates 10ace5a4f2a36504adccef1c4470b9e286ef8da1 S: d785767af99564c5d481db41483740078b53d423 172.38.0.16:6379 replicates 7b1aa1d177aabe07f1a44e2139b584398ec965fb Can I set the above configuration? (type 'yes' to accept): yes >>> Nodes configuration updated >>> Assign a different config epoch to each node >>> Sending CLUSTER MEET messages to join the cluster Waiting for the cluster to join ... >>> Performing Cluster Check (using node 172.38.0.11:6379) M: 10ace5a4f2a36504adccef1c4470b9e286ef8da1 172.38.0.11:6379 slots:[0-5460] (5461 slots) master 1 additional replica(s) M: 7b1aa1d177aabe07f1a44e2139b584398ec965fb 172.38.0.12:6379 slots:[5461-10922] (5462 slots) master 1 additional replica(s) M: d48eed0b198ac9acd9aab054d22f4b1127130276 172.38.0.13:6379 slots:[10923-16383] (5461 slots) master 1 additional replica(s) S: d785767af99564c5d481db41483740078b53d423 172.38.0.16:6379 slots: (0 slots) slave replicates 7b1aa1d177aabe07f1a44e2139b584398ec965fb S: e649283604139748551c55344a95d3fdc27b69f1 172.38.0.15:6379 slots: (0 slots) slave replicates 10ace5a4f2a36504adccef1c4470b9e286ef8da1 S: dca1b6f5ba61f1f2455f936a66ac6c276b602799 172.38.0.14:6379 slots: (0 slots) slave replicates d48eed0b198ac9acd9aab054d22f4b1127130276 [OK] All nodes agree about slots configuration. >>> Check for open slots... >>> Check slots coverage... [OK] All 16384 slots covered.