复制
- 基于RDB实现初始化,也就是同步操作,使用AOF实现同步复制,也就是命令传播
- 缺点:不支持自动扩容,没有高可用,可能产生数据不一致的问题
REPLICAOF
通过 命令可以把一个服务设置为另一个服务的从服务器
设置为从服务器之后会把原数据清空,主服务器会进行一次RDB,然后将数据进行全量同步
从服务器默认不可写,但可以通过replica-read-only <yes|no> 的设置来将从服务器变为可写
ROLE
- 角色,通过role命令可以查看当前服务器的角色
主服务角色信息
表示角色是master
复制偏移量是602
有两个从服务 分别是 6801 6802 ,他们的复制偏移量都是602,表示主从是同步的
从服务角色信息
数据同步
redis的数据同步分为同步 和 命令传播 两种操作
同步 :将从服务器的状态同步到主服务的状态 ,一般在从建立初始化,下线后重新上线
命令传播 : 在主服务器发生变化的时候,主服务通知从服务器,让主从一致
完整同步
在收到replicaaof请求后,主服务会执行一次bgsave 命令,生成一个rdb文件,并且将在这后产生的变化记录到缓冲区内
在完成rdb之后,会将rdb文件传输到从服务器上,从服务器加载这个rdb文件,就获得了在bgsva时主服务的数据
在加载完成之后,就开始接受命令同步请求,主服务器就会把之前存储在缓冲区的命令发送给从服务器执行
在这个过程中 rdb文件会有重用,并不是每一个从同步请求就rdb一次
在线更新 命令传播
- 在主从同步完成后,当主服务执行了写命令后,主从就不一致了。所有当主服务执行了写命令后,就会把这个命令发送到从服务执行。这样主从就重新回到一致
- 这个更新是异步的,所以是有可能出现主从不一致的情况的
部分同步
- 当一个服务成为主服务的时候,会把执行的写命令放入一个特定长度队列中,当从服务断开之后,在次重连的时候,会把使用复制偏移量来检查是否可以通过队列命令来完成同步,否则的话,就会进行一次完整的同步
- 队列默认是1M大小
无须硬盘的复制
默认的情况下,是需要主在主服务器的硬盘建立rdb文件
通过repl-diskless-sync命令,可以在复制的时候,不在主服务建立rdb文件,而是在从服务建立rdb文件,之后的流程是完全一致的
如何降低不一致
- 可以设置主服务器只会在从服务器的数量大于等于min-replicas-to-write选项的值,并且这些从服务器与主服务器最后一次成功通信的间隔不超过min-replicas-max-lag选项的值时才会执行写命令
脚本复制
脚本复制分为两种
脚本复制模式
命令复制模式
脚本复制模式
直接把脚本复制到从服务器上进行执行,为了保持主从一致,所以脚本里面的随机元素,都会进行处理
命令复制模式
将脚本的产生的所有写命令用事务进行包装,然后将事务复制到从服务进行执行,这样可以去除脚本的副作用
心跳检测
在命令传播的阶段,从服务器会每秒1次向主服务器发送心跳请求 ,用来:
检测主从服务器的网络连接状态
辅助实现min-slaves配置选项,主服务会检测从服务器最少多少个,延迟多少的时候才写入数据。
检测命令丢失
哨兵
基于主从复制,可以自动实现切换主从结构
哨兵由一个或者多个组成哨兵集群
哨兵检测主从所有的节点
当主节点挂掉的时候,哨兵会从其中一个从节点挑选一个作为主节点,当挂掉的主节点从新上线后,会降级当前主节点的从节点。
redis-sentinel和redis-server之间的关系
- Redis Sentinel实际上就是一个运行在特殊模式下的Redis服务器
新主服务器的挑选规则
当Sentinel需要在多个从服务器中选择一个作为新的主服务器时,首先会根据以下规则从候选名单中剔除不符合条件的从服务器:
1)否决所有已经下线以及长时间没有回复心跳检测的疑似已下线从服务器。
2)否决所有长时间没有与主服务器通信,数据状态过时的从服务器。
3)否决所有优先级为0的从服务器。
然后根据以下规则,在剩余的候选从服务器中选出新的主服务器:
1)优先级最高的从服务器获胜。
2)如果优先级最高的从服务器有两个或以上,那么复制偏移量最大的那个从服务器获胜。
3)如果符合上述两个条件的从服务器有两个或以上,那么选出它们当中运行ID(运行ID是服务器启动时自动生成的随机ID,这条规则可以确保条件完全相同的多个从服务器最终得到一个有序的比较结果)最小的那一个。
集群
快速搭建集群
- 使用redis/utils/create-cluster 的工具类 ,创建6个节点
创建集群,默认配置 可以看到:
Master[0] 的槽分配是 0 - 5460 Master[1] 的槽分配是 5461 - 10922 等等
将6个服务器分配为 3对 主从关系
- 此时的集群结构
命令转向
当redis客户端对集群发起访问的时候,如果当前命令不在本服务器上的话,则会返回一个转向指示,指引访问正确的服务器
集群中的16384个槽可以分别指派给集群中的各个节点,每个节点都会记录哪些槽指派给了自己,而哪些槽又被指派给了其他节点。
节点在接到一个命令请求时,会先检查这个命令请求要处理的键所在的槽是否由自己负责,如果不是的话,节点将向客户端返回一个MOVED错误,MOVED错误携带的信息可以指引客户端转向至正在负责相关槽的节点。
使用了跳跃表来保存槽和键之间的关系
hash tag
该功能会找出键中第一个被大括号{}包围并且非空的字符串子串(sub string),然后根据子串计算出该键所属的槽。这样一来,即使两个键原本不属于同一个槽,但只要它们拥有相同的被包围子串,那么程序计算出的散列值就是一样的,因此Redis集群就会把它们存储到同一个槽中。
在Cluster执行lua脚本的时候,会有一定的问题,因为Redis要求执行lua的脚本都在一个节点上面,如果你的lua脚本包含多个节点,就会报错,解决方法是在key中增加{},如果key中包含{}, 就会使用第一个{}内部的字符串作为hash key,这样就可以保证拥有同样{}内部字符串的key就会拥有相同slot。
重新分片
重新分片: 将节点A的槽数据至节点B,Redis使用了redis-trib来实现。
过程:1. 通知A做好准备,2,通知B做好准备 3,获取n个键值 4,发送migrate命令,将选中的进行迁移 5,重复直到复制完成 6,将指派信息通知集群。
ask错误:如果节点A正在迁移槽i至节点B,那么当节点A没能在自己的数据库中找到命令指定的数据库键时,节点A会向客户端返回一个ASK错误,指引客户端到节点B继续查找指定的数据库键。
从服务的读权限
- 集群从节点默认不处理任何请求,即时有请求,也会会返回命令转向到主节点
其他知识
Redis集群中的节点分为主节点(master)和从节点(slave),其中主节点用于处理槽,而从节点则用于复制某个主节点,并在被复制的主节点下线时,代替下线主节点继续处理命令请求。
实际上辅助和哨兵至是实现了Redis的高可用,但是其每一个机器都是存储完整数据,资源浪费很严重
节点通过握手来将其他节点添加到自己所处的集群当中。
集群的整个数据库被分为16384个槽(slot),数据库中的每个键都属于这16384个槽的其中一个,集群中的每个节点可以处理0个或最多16384个槽。