文章目录
- 1. 主从复制
- 1.1 定义
- 1.2 作用
- 1.3 配置策略
- 1.4 基本操作命令
- 1.5 演示案例
- 1.5.1 一主二仆
- 1.5.2 薪火相传
- 1.5.3 反客为主
- 1.6 主从复制原理和工作流程
- 1.7 主从复制的缺点
- 2. 哨兵监控
- 2.1 作用
- 2.2 演示案例
- 2.3 哨兵运行流程和选举原理
- 2.4 哨兵使用建议
- 3. 集群分片
- 3.1 定义
- 3.2 作用
- 3.3 Redis集群的slot(槽位)
- 3.4 Redis集群的分片
- 3.5 集群分片优点
- 3.6 slot槽位与redis服务器映射的3种解决方案
- 3.7 为什么redis集群的最大槽数是16384个?
- 3.8 redis集群不保证强一致性,这意味着在特定的条件下,redis集群可能会丢掉一些被系统收到的写入命令请求
- 3.9 集群分片案例演示
- 3.10集群常用操作命令和CRC16算法分析
1. 主从复制
1.1 定义
就是主从复制,master以写为主,slave以读为主,当master数据变化的时候,自动将新的数据异步同步到其他slave数据库
1.2 作用
- 读写分离
- 容灾恢复
- 数据备份
- 水平扩容支撑高并发
1.3 配置策略
- 配从(库)不配主(库)
- 从库中主要配置哪个是mater,以及访问master的密码
1.4 基本操作命令
1.4.1 info replication 可以查看复制节点的主从关系和配置信息
1.4.2 replicaof 主库ip 主库端口 :配置文件中设置,给从库设置主库
一般写入进redis.conf配置文件内
1.4.3 slaveof 主库ip 主库端口 :命令设置,给从库设置主库
每次与master断开之后,都需要重新连接,除非你配置进redis.conf文件;
在运行期间修改slave节点的信息,如果该数据库已经是某个主数据库的从数据库,那么会停止和原主数据库的同步关系转而和新的主数据库同步,重新拜码头
1.4.4 salveof no one 从库变成主库
使当前数据库停止与其他数据库的同步,转成主数据库,自立为王
1.5 演示案例
1.5.1 一主二仆
1.5.1.1 使用VMware创建三台虚拟机
- 创建一台虚拟机,安装好redis
- 完整克隆两台虚拟机。由于刚克隆出来的虚拟机ip跟之前的一样,所以需要修改ip,修改方式如下:
su root
vim /etc/sysconfig/network-scripts/ifcfg-ens33
# 重启网络
service network restart
查看ip(阿里云外网的ip是ping不通这个内网ip的):
- 更改三台虚拟机redis配置文件名称
主库:redis6379.conf,主机名为centos7-1
从库:redis6380.conf、redis6381.conf,主机名为centos7-2、centos7-3
1.5.1.2 配置文件redis.cof修改
# 策略是不同的机器,redis使用不同的端口,其实完全可以使用相同的端口,为了区分度好演示才这样做
vim /myredis/redis6379.conf
- 开启daemonize yes
- 注释掉bind 127.0.0.1 ,或者将ip修改为本机网卡所对应的真正的ip,否则别的机器识别不了127.0.0.1这个localhostip
- protected-mode no 设置为yes是保护模式,不允许其他机器访问
- (主从不同)指定端口
- 指定当前工作目录,dir
- (主从不同)pid文件名字,pidfile
- (主从不同)log文件名字,logfile
- requirepass 配置密码
- (主从不同)rdb持久化文件名字
- aof设置
- (主从不同)从机访问主机的通行密码masterauth,主机不需要设置
从库配置:
1.5.1.3 systemctl stop firewalld 关闭主库防火墙,从库不需要,不然从库连接不上主库,无法做到主从复制
1.5.1.4 主库从库启动命令
1.5.1.5 查看主从日志文件
主:/myredis/6379.log 其中包含从库的连接情况
从:/myredis/6380.log、/myredis/6381.log 其中包含跟主库的连接情况
1.5.1.6 info replication 查看主从关系信息
主:
从:
1.5.1.7 查看主从效果
主赋值:
从1可直接查到主库的值:
从2也可直接查到主库的值:
1.5.1.8 从库不可写
1.5.1.9 主从库启动顺序不同是否会造成数据不同步
1.5.1.9.1 从机切入点问题,从机启动之前的主机设置的key是否可查到
-
将从机进程杀掉
-
主机写入值
-
启动从机,查看从机能否查到master的值-可以
1.5.1.9.2 先启动从机,再启动主机,从机能否查到值
- 干掉主从机
- 先启动从机,从机仍可以正常使用,显示主机下线
- 再启动主机
- 查看此时的从机是否同步到新值-是
1.5.1.9.3 结论:主机宕机时从机依然可用,但仍是从机阶段,仍不可写;先启动主机和先启动从机,都启动好后没有区别,但是刚开始还是应该先启动主机
1.5.1.10 slaveof 主库ip 主库端口:命令式声明自己成为某台机器的从机
- 将配置文件的主机配置注释
- 启动后编程master
- slaveof 192.168.122.1 6379 指定主机
- 重启从机,查看命令式配置会不会失效-会
- 恢复配置文件
1.5.2 薪火相传
上一个slave可以是下一个slave的master,slave同样可以接收其他slaves的连接和同步请求,那么该slave作为了链条中下一个的master,可以有效减轻主master的写压力
- 现在192.168.122.2作为192.168.122.1的slave,作为192.168.122.3的master
- 由于192.168.122.2作为192.168.122.3的master,需要关闭192.168.122.2的防火墙,这也告诉我们一个道理,主从复制,其实是从向主发送请求拉数据,不然为何从不需要关闭防火墙
systemctl stop firewalld
- 配置:
在192.168.122.3中执行slaveof 192.168.122.2 6380 - 结果:
192.168.122.1:
192.168.122.2:仍然不可编辑
192.168.122.3:
1.5.3 反客为主
使当前数据库停止与其他数据库的同步,转成主数据库
- 在192.168.122.3中执行slaveof no one
slaveof no one
- 结果
192.168.122.1:
192.168.122.2:
192.168.122.3:
3. 重启6381端口的redis-server,恢复成一主二从,方便后续操作
1.6 主从复制原理和工作流程
1.6.1 slave启动,同步初请
slave启动成功连接到master后会发送一个sync命令;
slave首次全新连接master,一次完全同步(全量复制)将被自动执行,slave自身原有数据会被master数据覆盖清除
1.6.2 首次连接,全量复制
master节点收到sync命令后会开始在后台保存快照(即RDB持久化,主从复制时会触发RDB),
同时收集所有接收到的用于修改数据集命令缓存起来,master节点执行RDB持久化完后,
master将rdb快照文件和所有缓存的命令发送到所有slave,以完成一次完全同步,
而slave服务在接收到数据库文件数据后,将其存盘并加载到内存中,从而完成复制初始化
1.6.3 心跳持续,保持通信
repl-ping-replica-period 10
1.6.4 进入平稳,增量复制
master继续将新的所有收集到的修改命令自动依次传给slave,完成同步
1.6.5 从机下线,重连续传
master会检查backlog里面的offset,master和slave都会保存一个复制的offset还有一个masterId,offset是保存在backlog中的。Master只会把已经复制的offset后面的数据复制给Slave,类似断点续传
1.7 主从复制的缺点
1.7.1 复制延时,信号衰减
1.7.2 master宕机后,从机默认情况下原地待命,只可读,不会变成主机,这时候只能人为干预,重新使主机恢复正常
2. 哨兵监控
2.1 作用
无人值守运维:吹哨人巡查监控后台master主机是否故障,如果故障了根据投票数自动将某一个从库转换为新主库,继续对外服务
2.1.1 主从监控
监控主从redis库运行是否正常
2.1.2 消息通知
哨兵可以将故障转移的结果发送给客户端
2.1.3 故障转移
如果Master异常,则会进行主从切换,将其中一个Slave作为新Master
2.1.4 配置中心
客户端通过连接哨兵来获得当前Redis服务的主节点地址
2.2 演示案例
2.2.1 Redis Sentinel 架构
三个哨兵:自动监控和维护集群,不存放数据,只是吹哨人
1主2从:用于数据的读取和存放
2.2.2 sentinel.conf文件参数含义
cp /opt/redis7/redis-7.0.10/sentinel.conf /myredis/
- bind 服务监听地址,用于客户端连接,默认本机地址
- daemonize 是否以后台daemon方式运行
- protected-mode 安全保护模式
- port 端口
- logfile 日志文件路径
- pidfile pid文件路径
- dir 工作目录
- sentinel monitor <master-name> <ip> <redis-port> <quorum>
设置要监控的master服务器,quorum表示最少有几个哨兵认可客观下线,同意故障迁移的法定票数。
- sentinel auth-pass <master-name> <password> master设置了密码(连接master服务的密码)
- sentinel down-after-milliseconds
指定多少毫秒之后,主节点没有应答哨兵,此时哨兵主观上认为主节点下线
- sentinel parallel-syncs
表示允许并行同步的slave个数,当Master挂了后,哨兵会选出新的Master,此时,剩余的slave会向新的master发起同步数据
- sentinel failover-timeout
故障转移的超时时间,进行故障转移时,如果超过设置的毫秒,表示故障转移失败
- sentinel notification-script
配置当某一事件发生时所需要执行的脚本
- sentinel client-reconfig-script
客户端重新配置主节点参数脚本
2.2.3 本次案例哨兵sentinel.conf文件配置
原则上三个哨兵和三个redis-server应该在6台服务器上,由于机器硬件关系,这里的3个哨兵都同时配置进192.168.122.1这台虚拟机,哨兵法定投票人数设为2
-
sentinel26379.conf:
-
sentinel26380.conf:
-
sentinel26381.conf:
-
redis6379.cong:由于6379后续可能会变为从机,需要设置访问新主机的密码,所以需要设置masterauth
2.2.4 redis-sentinel sentinel.conf --sentinel 启动sentinel
服务使用相同的配置文件启动多次也只会有一个进程
2.2.5 查看sentinel启动后sentinel.log和sentinel.conf的内容
sentinel日志文件和配置文件都会显示启动的sentinel服务(id表示),启动的redis服务(ip表示)的主从关系
2.2.6 主机宕机,哨兵发挥作用(案例演示)
2.2.6.1 先关闭6381端口所在服务器的防火墙,因为6381有可能被选为主机
systemctl stop firewalld
2.2.6.2 6379端口redis主机宕机(会有段时间从机也不可用,等sentinel哨兵选举主机完成,剩下的机器有的甚至还需要一段时间才可用,我们要做的只能是等待了,希望你的机器性能足够好)
这时候6379会出现报错Connection refused
之前的从机们如果还没连上新主机,就会出现如下报错(broken pipe):
2.2.6.3 查看sentinel.log:显示redis主机已经切换到6380端口的机器
2.2.6.4 启动6379,发现6379和6381变成了6380的从机,查看配置文件的变化
6379端口的机器:
6380端口的机器:
6381端口的机器:
sentinel26379.conf配置文件的改变:
2.2.7 关于配置文件redis.conf和sentinel的关系
- Redis配置文件redis.conf和Sentinel配置文件sentinel.conf的内容,在运行期间会被sentinel动态进行更改(手敲命令比如slaveof是更改不了配置文件的);
- Master-Slave切换后,master_redis.conf、slave_redis.conf和sentinel.conf的内容都会发生改变,
即master_redis.conf中会多一行slaveof的配置,sentinel.conf的监控目标会随之调换
2.3 哨兵运行流程和选举原理
2.3.1 三个哨兵监控redis一主二从架构图
2.3.2 SDown主观下线(Subjectively Down)
- SDOWN(主观不可用)是单个sentinel自己主观上检测到的关于master的状态,从sentinel的角度来看,如果发送了PING心跳后,在一定时间内没有收到合法的回复,就达到了SDOWN的条件。
- sentinel配置文件中的down-after-milliseconds设置了判断主观下线的时间长度(默认30秒)
2.3.3 ODown客观下线(Objectively Down)
ODown需要一定数量(quorum数值)的sentinel,多个哨兵达成一致意见才能认为一个master客观上已经宕掉
2.3.4 选举出领导者哨兵(leader,哨兵中选出兵王)
2.3.4.1 从sentinel.log文件查看选举过程
当主节点被判断客观下线以后,各个哨兵节点会进行协商,先选举出一个领导者哨兵节点(兵王),
并由该领导者节点,也即被选举出的兵王进行failover(故障迁移)
-
sentinel26379.log
-
sentinel26380.log
-
sentinel26381.log
2.3.4.2 通过raft算法选出哨兵leader
2.3.5 由兵王开始推动故障切换流程并选出一个新master,从机改变自己的主从属性的步骤
2.3.5.1 新主登基:某个Slave被选中成为新Master,规则如下(这里的场景是只有主机宕机)
2.3.5.1.1 replica-priority(在redis.conf中配置,数字越小优先级越高,默认100)
redis7,且redis是2022年四月份出的稳定版,slave-priority应该是redis6及以下版本
2.3.5.1.2 位置偏移量offset(选取复制偏移量位置offset最大的从节点)
- 定义1:在master中,会记录给各个slave发送的同步数据的偏移量,多少个slave就有多少个记录。
在slave中,会记录master在同步数据中发送过来的偏移量。
作用:在同步数据、对比slave与master数据的差异时,用来判断slave与master是否存在差异,如果有差异,也可以由此知道该从哪个位置开始恢复数据。 - 定义2:复制偏移量是指命令的字节长度,通过对比主从节点的复制偏移量,可以判断主从节点数据是否一致。
- 查看:info replication中的master_repl_offset
2.3.5.1.3 run id(选取run id最小的从节点,字典顺序,ASCII码)
- 定义1:
概念:服务器每次运行时生成的id,用于身份识别,一台服务器每次启动时生成的运行id都是不同的。
组成:运行id由40位随机的16进制字符组成。
作用:用于服务器之前传输,做身份识别。 - 定义2:
Redis服务器的随机标识符(用于Sentinel和集群),重启后会改变。当复制时发现和之前的run_id不同时,将会对数据进行全量同步。 - 查看:
redis-cli -a 111111 -p 6380 info server 2>/dev/null | grep run_id
- 字典顺序:先按第一个字符排,第一个字符相等再按第二个字符排
2.3.5.1.4 redis新主机选举流程图
2.3.5.2 群臣俯首:剩下的从机重新选定主机
执行slaveof no one命令让选出来的从节点成为新的主节点,并通过slaveof命令让其他节点成为其从节点
- Sentinel leader会对选举出的新master执行slaveof no one操作,将其提升为master节点
- Sentinel leader向其它slave发送命令,让剩余的slave成为新的master节点的slave
2.3.5.3 旧主拜服:旧的主机重启后作为从机选定新的主机
将之前已下线的老master设置为新选出的新master的从节点,当老master重新上线后,它会成为新master的从节点
- Sentinel leader会让原来的master降级为slave并恢复正常工作。
2.3.5.4 小总结
上述的fail over(故障迁移)操作均由sentinel自己独自完成,完全无需人工干预。
2.4 哨兵使用建议
- 哨兵节点的数量应为多个,哨兵本身应该集群,保证高可用
- 哨兵节点的数量应该是奇数
- 各个哨兵节点的配置应一致
- 如果哨兵节点部署在Docker等容器里面,尤其要注意端口的正确映射
- 哨兵集群+主从复制,并不能保证数据零丢失,承上启下引出集群
3. 集群分片
3.1 定义
- 由于数据量过大,单个Master复制集难以承担,因此需要对多个复制集进行集群,形成水平扩展每个复制集只负责存储整个数据集
的一部分,这就是Redis的集群,其作用是提供在多个Redis节点间共享数据的程序集。 - Redis集群是一个提供在多个Redis节点间共享数据的程序集
- Redis集群可以支持多个Master
3.2 作用
- rdis集群支持多个master,每个master又可以挂在多个slave,支持读写分离、数据的高可用、海量数据的读写存储操作
- 由于cluster自带sentinel的故障转移机制,内置了高可用的支持,无需再去使用哨兵功能
- 客户端与redis的节点连接,不再需要连接集群中所有的节点,只需要任意连接集群中的一个可用节点即可
- 槽位slot负责分配到各个物理服务节点,由对应的集群俩负责维护节点、插槽和数据之间的关系
3.3 Redis集群的slot(槽位)
3.3.1 建议哈希槽的个数不要超过一千
3.3.2 哈希槽
- slot成为哈希槽
- 作用:
当我们向redis存入一个key value数据时,我们应该存入哪个节点呢,应该按照什么样的规则呢,取也同样:
引用哈希槽的概念,每个key通过CRC16算法得到一个数值,这个数据对16384(2的14次方)取余,这样就会得到一个0~16383之间的数值,redis集群最多可以有16384个哈希槽,这些哈希槽的编号就是0~16383,我们就将key通过计数得到的数值放入相同编号的哈希槽,通过查找各个节点与哈希槽的映射关系,将key存入对应的节点。相当于在数据与节点之间加了一层映射。数据映射哈希槽,哈希槽映射节点,一个节点下线了,只需要将这个节点的哈希槽的映射关系绑定到其他节点。 - 计算哈希槽
redisTemplate.opsForValue.set("haha", "xinliushijian");
// 计算key对应的哈希槽编号
key对应的哈希槽编号 = io.lettuce.core.cluster.SlotHash.getSlot("haha")
3.4 Redis集群的分片
使用Redis集群时我们会将存储的数据分散到多台redis机器上,这称为分片。简言之,集群中的每个Redis实例都被认为是整个数据的一个分片。
3.5 集群分片优点
3.6 slot槽位与redis服务器映射的3种解决方案
3.6.1 哈希取余分区(分母是服务器个数)
3.6.2 一致性hash算法分区(分母是2的32次方)
3.6.2.1 一致性Hash算法背景
一致性哈希算法在1997年由麻省理工学院中提出的,设计目标是为了解决分布式缓存数据变动和映射问题,某个机器宕机了,分母数量改变了,自然取余数不OK了。
3.6.2.2 作用
提出一致性Hash解决方案,目的是当服务器个数发生变动时,尽量减少影响客户端到服务器的映射关系
3.6.2.3 步骤
3.6.2.3.1 算法构建一致性哈希环
3.6.2.3.2 redis服务器IP节点映射
3.6.2.3.3 key落到服务器的落键规则
3.6.2.4 优点
3.6.2.4.1 一致性哈希算法的容错性
3.6.2.4.2 一致性哈希算法的扩展性
3.6.2.5 缺点
3.6.2.5.1 一致性哈希算法的数据倾斜问题
3.6.2.6 小总结
3.6.3 一致性hash算法分区(分母是2的14次方:16384)
3.6.3.1 定义
3.6.3.2 哈希槽计算
3.7 为什么redis集群的最大槽数是16384个?
3.8 redis集群不保证强一致性,这意味着在特定的条件下,redis集群可能会丢掉一些被系统收到的写入命令请求
3.9 集群分片案例演示
3.9.1 3主3从redis集群配置
ip | 主机端口 | 从机端口 |
---|---|---|
192.168.122.1 | 6381 | 6382 |
192.168.122.2 | 6383 | 6384 |
192.168.122.3 | 6385 | 6386 |
3.9.1.1 在三台虚拟机上创建目录/myredis/cluster
mkdir -p /myredis/cluster
3.9.1.2 在三台主机上创建六个redis.conf配置文件
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
vim /myredis/cluster/redisCluster6385.conf
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
vim /myredis/cluster/redisCluster6386.conf
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
3.9.1.3 先reboot三台主机,批量将之前哨兵启动的进程干掉,然后启动新的六个redis-server
reboot
# 重启之后别忘了再次关闭防火墙
systemctl stop firewalld
redis-server /myredis/cluster/redisCluster6381.conf
redis-server /myredis/cluster/redisCluster6382.conf
3.9.1.4 redis-cli -a 111111 --cluster create --cluster-replicas 1 构建主从关系命令
# --cluster create 以集群方式创建
# --cluster-replicas 1 表示为每个master创建一个slave节点
redis-cli -a 111111 --cluster create --cluster-replicas 1 192.168.122.1:6381 192.168.122.1:6382 192.168.122.2:6383 192.168.122.2:6384 192.168.122.3:6385 192.168.122.3:6386
上面的redis-cli命令只在192.168.122.1这一台机器上执行了(不过这并不代表在这台机器上可以以非6381/6382端口登录redis-cli),但在三台服务器上都起了作用,并生成如下文件:
3.9.1.5 以6381为切入点,查看集群状态 info replication&cluster info(此节点的信息)&cluster nodes(查看主从节点关系拓扑图)
3.9.2 3主3从redis集群读写(redis-cli -c 路由重定向)
3.9.2.1 cluster keyslot key1 查看key1对应的槽位值
3.9.2.2 在6381上执行set k1 v1报错
按照提示到6385上执行成功:
原因:set时不同的key对应不同的槽位,不同的槽位路由到不同的主机,而k1的槽位是12706,所以需要路由到6385上执行
解决办法:redis-cli 执行时加-c选型,作用是优化路由,路由重定向,如果不加,登录的节点不对,set,get都会报错