设置多个 Redis 数据库,master 以写为主, slave 以读为主
功能概述:
那我们如何来使用呢?
info replication
命令可以查看复制结点的主从关系与配置信息replicaof 主库IP 主库端口
命令可以将我们当前的 slave 库连接到 master 库上 【写到配置文件中的】slaveof 主库IP 主库端口
命令可以建立从库与主库的临时连接关系
slaveof no one
命令可以使当前数据库停止与其他数据库的同步,转成主数据库,自立为王1️⃣ 架构说明:
2️⃣ 小口诀:
3️⃣ 修改配置文件的步骤: 【以 redis6379.conf 为例】
4️⃣ 一仆二主:
(1)方案一:采用配置文件固定写死的方式
(2)方案二:命令操作手动指定
也就是说:通过配置方式确定的主从关系更稳定,通过命令确定的主从关系只是当次生效
5️⃣ 薪火相传:
6️⃣ 客反为主:
SLAVEOF no one
命令,使当前数据库停止与其他数据库的同步,转成主数据库1、复制工作原理和工作流程
slave 启动,工作初请
首次连接,全量复制:
心跳持续,保持通信:
进入平稳,增量复制:
从机下线,重连续传:master 会检查 backlog 里面的 offset, master 和 slave 都会保存一个复制的 offset 还有一个 masterId,offset 是保存在 backlog 中的, Master 只会把已经复制的 offset 后的数据复制给 Slave,类似于断点续传
2、复制的缺点
复制延迟,信号衰弱:
master 挂了怎么办?
Redis 哨兵(sentinel)是什么?
哨兵的功能:
1️⃣ Redis Sentinel 架构
2️⃣ 重要参数说明:
bind 服务监听地址,用于客户端连接,默认本机地址
daemonize 是否以后台daemon方式运行 【守护线程】
protected-mode 安全保护模式
port 端口
logfile 日志文件路径
pidfile pid文件路径
dir 工作目录
sentinel monitor
设置要监控的 master 服务器
sentinel auth-pass
当 master 设置了密码,哨兵监控的时候就需要输入我们的 master 的密码
3️⃣ 本次案例哨兵 sentinel 文件通用配置
我们将三个哨兵都同时配置进 192.168.111.169 同一台机器
sentinel26379.conf
bind 0.0.0.0
daemonize yes
protected-mode no
port 26379
logfile "/myredis/sentinel26379.log"
pidfile /var/run/redis-sentinel26379.pid
dir /myredis
sentinel monitor mymaster 192.168.111.169 6379 2
sentinel auth-pass mymaster 111111
sentinel26380.conf
bind 0.0.0.0
daemonize yes
protected-mode no
port 26380
logfile "/myredis/sentinel26380.log"
pidfile /var/run/redis-sentinel26380.pid
dir "/myredis"
sentinel monitor mymaster 192.168.111.169 6379 2
sentinel auth-pass mymaster 111111
sentinel26381.conf
bind 0.0.0.0
daemonize yes
protected-mode no
port 26381
logfile "/myredis/sentinel26381.log"
pidfile /var/run/redis-sentinel26381.pid
dir "/myredis"
sentinel monitor mymaster 192.168.111.169 6379 2
sentinel auth-pass mymaster 111111
4️⃣ 整体测试:
1、先启动一主二从3个Redis实例,测试正常的主从复制
注意:6379后续可能会变成从机,需要设置访问新主机的密码, 请设置masterauth项访问密码为111111,不然后续可能报错 master_link_status:down
2、分别启动三台Redis客户端:
3、再启动三个哨兵完成监控:
5、问题思考:
(1)当我们master宕机后,两台从机数据还可以正常使用吗?
介绍 | |
---|---|
认识broken pipe | pipe是管道的意思,管道里面是数据流,通常是从文件或网络套接字读取的数据。当该管道从另一端突然关闭时,会发生数据突然中断,即是broken,对于socket来说,可能是网络被拔出或另一端的进程崩溃 |
解决问题 | 其实当该异常产生的时候,对于服务端来说,并没有多少影响。因为可能是某个客户端突然中止了进程导致了该错误 |
总结 Broken Pipe | 这个异常是客户端读取超时关闭了连接,这时候服务器端再向客户端已经断开的连接写数据时就发生了broken pipe异常! |
(2)是否会从剩下的 2 台机器上选出 master 呢?【我们查看一下哨兵的日志文件】
(3)谁会是新的 master,当原来的master恢复后,会不会出现双 master 的现象?
6380还是slave,只不过换了个新老大6381(6379变6381),6380还是slave
6、对比配置文件我们可以发现:
备注:
运行流程、故障切换
2️⃣ SDown主观下线(Subjectively Down)
3️⃣ ODown客观下线(Objectively Down)
4️⃣ 选取出领导者哨兵(兵王)
当主节点被判断客观下线以后,各个哨兵节点会进行协商,先选举出一个领导者哨兵节点(兵王)并由该领导者节点也即被选举出的兵王进行failover(故障迁移)
那么这个兵王是如何选出来的呢?
5️⃣ 兵王推动故障切换流程并选出一个新的 master
(1)新主登基:某个 slave 被选中成为新 master
(2)群臣俯首:所有 slave 认定新的 master
(3)旧主拜服:回来的老 master 会变成 slave
Redis 都有哪些功能
Redis 集群支持多个 Master,每个 Master 又可以挂载多个 Slave
由于 Cluster 自带的 sentinel(哨兵)的故障转移机制,内置了高可用的支持,无需再去使用哨兵功能
客户端与 Redis 的节点连接,不需要连接集群的所有节点,只需要连接集群中任意一个可用节点即可
槽位 slot 负责分配到各个物理节点,由对应集群负责维护节点、插槽和数据之间的关系
1️⃣ Redis 集群的槽位 slot:
2️⃣ Redis 集群的分片
分片是什么?
如何找到给定 key 的分片?
3️⃣ 优势:
4️⃣ 如何实现 slot 的槽位映射?
方案一:哈希取余分区
2亿条记录就是2亿个k,v,我们单机不行必须要分布式多机,假设有3台机器构成一个集群,用户每次读写操作都是根据公式:hash(key) % N个机器台数
,计算出哈希值,用来决定数据映射到哪一个节点上
优点:
缺点:
原来规划好的节点,进行扩容或者缩容就比较麻烦了,不管扩缩,每次数据变动导致节点有变动,映射关系需要重新进行计算,在服务器个数固定不变时没有问题
如果需要弹性扩容或故障停机的情况下,原来的取模公式就会发生变化:Hash(key)/3会变成Hash(key) /?。此时地址经过取余运算的结果将发生很大变化,根据公式获取的服务器也会变得不可控
某个redis机器宕机了,由于台数数量变化,会导致hash取余全部数据重新洗牌
方案二:一致性算法分区
(1)算法构造一致性哈希环
(2)Redis 服务器IP节点映射
将集群中各个节点映射到环上的某一位置
将各个服务器使用Hash进行一个哈希,具体可以选择服务器的IP或主机名作为关键字进行哈希,这样每台机器就能确定其在哈希环上的位置
假如4个节点NodeA、B、C、D,经过IP地址的哈希函数计算(hash(ip)),使用IP地址哈希后在环空间的位置如下:
(3)key 落到服务器的落键规则
当我们需要存储一个kv键值对时,首先计算key的hash值,hash(key),将这个key使用相同的函数Hash计算出哈希值并确定此数据在环上的位置,从此位置沿环顺时针“行走”,第一台遇到的服务器就是其应该定位到的服务器,并将该键值对存储在该节点上
如我们有Object A、Object B、Object C、Object D四个数据对象,经过哈希计算后,在环空间上的位置如下:根据一致性Hash算法,数据A会被定为到Node A上,B被定为到Node B上,C被定为到Node C上,D被定为到Node D上
一致性哈希算法的优点:
一致性哈希算法存在的数据倾斜问题:
对于一致性哈希算法的总结:
方案三:哈希槽分区
为了解决一致性哈希算法的数据倾斜问题,引出了我们的哈希槽,哈希槽实质就是一个数组,数组[0,2^14 -1]形成hash slot空间
哈希槽具体有什么作用呢?
那么有多少个哈希槽呢?
HASH_SLOT = CRC16(key) mod 16384
,以槽为单位移动数据,因为槽的数目是固定的,处理起来比较容易,这样数据移动问题就解决了那么哈希槽是如何计算的呢?
5️⃣ 经典面试题:
解释1:
正常的心跳数据包带有节点的完整配置,可以用幂等方式用旧的节点替换旧节点,以便更新旧的配置。
这意味着它们包含原始节点的插槽配置,该节点使用2k的空间和16k的插槽,但是会使用8k的空间(使用65k的插槽)。
同时,由于其他设计折衷,Redis集群不太可能扩展到1000个以上的主节点。
因此16k处于正确的范围内,以确保每个主机具有足够的插槽,最多可容纳1000个矩阵,但数量足够少,可以轻松地将插槽配置作为原始位图传播。请注意,在小型群集中,位图将难以压缩,因为当N较小时,位图将设置的slot / N位占设置位的很大百分比
解释2:
(1)如果槽位为65536,发送心跳信息的消息头达8k,发送的心跳包过于庞大。
在消息头中最占空间的是myslots[CLUSTER_SLOTS/8]。 当槽位为65536时,这块的大小是: 65536÷8÷1024=8kb
在消息头中最占空间的是myslots[CLUSTER_SLOTS/8]。 当槽位为16384时,这块的大小是: 16384÷8÷1024=2kb
因为每秒钟,redis节点需要发送一定数量的ping消息作为心跳包,如果槽位为65536,这个ping消息的消息头太大了,浪费带宽。
(2)redis的集群主节点数量基本不可能超过1000个。
集群节点越多,心跳包的消息体内携带的数据越多。如果节点过1000个,也会导致网络拥堵。因此redis作者不建议redis cluster节点数量超过1000个。 那么,对于节点数在1000以内的redis cluster集群,16384个槽位够用了。没有必要拓展到65536个。
(3)槽位越小,节点少的情况下,压缩比高,容易传输
Redis主节点的配置信息中它所负责的哈希槽是通过一张bitmap的形式来保存的,在传输过程中会对bitmap进行压缩,但是如果bitmap的填充率slots / N很高的话(N表示节点数),bitmap的压缩率就很低。 如果节点数很少,而哈希槽数量很多的话,bitmap的压缩率就很低。
1️⃣ 三主三从Redis集群配置
找三台真实的虚拟机,各自创建mkdir -p /myredis/cluster
创建六个独立的Redis服务实例:
vim /myredis/cluster/redisCluster6381.conf
bind 0.0.0.0
daemonize yes
protected-mode no
port 6381
logfile "/myredis/cluster/cluster6381.log"
pidfile /myredis/cluster6381.pid
dir /myredis/cluster
dbfilename dump6381.rdb
appendonly yes
appendfilename "appendonly6381.aof"
requirepass 111111
masterauth 111111
cluster-enabled yes
cluster-config-file nodes-6381.conf
cluster-node-timeout 5000
vim /myredis/cluster/redisCluster6382.conf
bind 0.0.0.0
daemonize yes
protected-mode no
port 6382
logfile "/myredis/cluster/cluster6382.log"
pidfile /myredis/cluster6382.pid
dir /myredis/cluster
dbfilename dump6382.rdb
appendonly yes
appendfilename "appendonly6382.aof"
requirepass 111111
masterauth 111111
cluster-enabled yes
cluster-config-file nodes-6382.conf
cluster-node-timeout 5000
vim /myredis/cluster/redisCluster6383.conf
bind 0.0.0.0
daemonize yes
protected-mode no
port 6383
logfile "/myredis/cluster/cluster6383.log"
pidfile /myredis/cluster6383.pid
dir /myredis/cluster
dbfilename dump6383.rdb
appendonly yes
appendfilename "appendonly6383.aof"
requirepass 111111
masterauth 111111
cluster-enabled yes
cluster-config-file nodes-6383.conf
cluster-node-timeout 5000
vim /myredis/cluster/redisCluster6384.conf
bind 0.0.0.0
daemonize yes
protected-mode no
port 6384
logfile "/myredis/cluster/cluster6384.log"
pidfile /myredis/cluster6384.pid
dir /myredis/cluster
dbfilename dump6384.rdb
appendonly yes
appendfilename "appendonly6384.aof"
requirepass 111111
masterauth 111111
cluster-enabled yes
cluster-config-file nodes-6384.conf
cluster-node-timeout 5000
bind 0.0.0.0
daemonize yes
protected-mode no
port 6385
logfile "/myredis/cluster/cluster6385.log"
pidfile /myredis/cluster6385.pid
dir /myredis/cluster
dbfilename dump6385.rdb
appendonly yes
appendfilename "appendonly6385.aof"
requirepass 111111
masterauth 111111
cluster-enabled yes
cluster-config-file nodes-6385.conf
cluster-node-timeout 5000
bind 0.0.0.0
daemonize yes
protected-mode no
port 6386
logfile "/myredis/cluster/cluster6386.log"
pidfile /myredis/cluster6386.pid
dir /myredis/cluster
dbfilename dump6386.rdb
appendonly yes
appendfilename "appendonly6386.aof"
requirepass 111111
masterauth 111111
cluster-enabled yes
cluster-config-file nodes-6386.conf
cluster-node-timeout 5000
通过 redis-cli
命令为6台机器构建集群关系
redis-cli -a 111111 --cluster create --cluster-replicas 1 192.168.111.175:6381 192.168.111.175:6382 192.168.111.172:6383 192.168.111.172:6384 192.168.111.174:6385 192.168.111.174:6386
链接进入6381作为切入点,查看并检验集群状态
2️⃣ 三主三从Redis集群读写
3️⃣ 主从容错切换迁移案例
4️⃣ 主从扩容案例:
IP:192.168.111.174+端☐6387/端☐6388
bind 0.0.0.0
daemonize yes
protected-mode no
port 6387
logfile "/myredis/cluster/cluster6387.log"
pidfile /myredis/cluster6387.pid
dir /myredis/cluster
dbfilename dump6387.rdb
appendonly yes
appendfilename "appendonly6387.aof"
requirepass 111111
masterauth 111111
cluster-enabled yes
cluster-config-file nodes-6387.conf
cluster-node-timeout 5000
bind 0.0.0.0
daemonize yes
protected-mode no
port 6388
logfile "/myredis/cluster/cluster6388.log"
pidfile /myredis/cluster6388.pid
dir /myredis/cluster
dbfilename dump6388.rdb
appendonly yes
appendfilename "appendonly6388.aof"
requirepass 111111
masterauth 111111
cluster-enabled yes
cluster-config-file nodes-6388.conf
cluster-node-timeout 5000
启动87/88两个新的节点实例,此时他们自己都是master
重新分派槽号(reshard)
5️⃣ 主从容缩案例:
将6387的槽号清空,重新分配,本例将清出来的槽号都给6381
检查集群情况第三次,6387/6388被彻底祛除B
redis-cli -a 111111 --cluster check 192.168.111.175:6381