目录
1.主从复制过程
从服务器在连接一个主服务器的时候,主服务器会创建一个RDB快照文件,并将该文件发送至从服务器,这是主从复制的第一步,下面列出主从复制的全部流程:
步骤 | 主服务器操作 | 从服务器操作 |
1 | 等待从服务器命令 | 连接/重连接主服务器,发送sync命令 |
2 | 接收到sync命令后,开始执行bgsave,并使用内存缓冲区记录bgsave之后执行的所有写入命令 | 根据配置选项来决定是继续使用现有的数据来处理客户端的命令请求,还是向发送请求的客户端返回错误? |
3 | bgsave执行完毕,向从服务器发送RDB快照文件,并在发送期间继续使用内存缓冲区记录被执行的写入命令 | 丢弃所有旧数据(如果有的话),开始载入主服务器发来的快照文件 |
4 | 快照文件发送完毕,开始向从服务器发送存储在缓冲区里面的写入命令 | 完成对RDB快照文件的解释操作,像往常一样开始接受客户端命令请求 |
5 | 缓冲区存储的写入命令发送完毕,从现在开始,每执行一个写入命令,就向从服务器发送相同的写入命令 | 执行主服务器发来的所有存储在内存缓冲区的写入命令,并从现在开始,接收并执行主服务器传来的每一个写入命令 |
2.设置从服务器的方式
配置某台服务器作为从服务器的方式有2种:
①在Redis.conf文件中通过slaveof host port将其设置为从服务器,然后该服务器启动时会先去载入当前任何可用的RDB文件或者AOF文件,然后再去连接主服务器并执行主从复制过程;
②向正在运行的服务器发送slaveof命令,动态将其变为从服务器,然后该服务器会立即尝试连接主服务器,并在连接成功之后,开始上面提到的主从复制过程;
注意:从服务器在与主服务器进行初始连接时,从服务器中的原有的所有数据都将丢失,并被替换成主服务器发来的数据;
3.多个从服务器连接时
当多个从服务器尝试连接同一个主服务器时,会出现下面2种情况中的一种:
步骤 | 主服务器操作 | 从服务器操作 |
1 | 等待从服务器命令 | 连接/重连接主服务器,发送sync命令 |
2 | 接收到sync命令后,开始执行bgsave,并使用内存缓冲区记录bgsave之后执行的所有写入命令 | 根据配置选项来决定是继续使用现有的数据(如果有的话)来处理客户端的命令请求,还是向发送请求的客户端返回错误? |
情况1:当步骤3尚未执行时,所有从服务器都会接收到相同的快照文件和相同的缓冲区写入命令 | ||
3 | bgsave执行完毕,向从服务器发送RDB快照文件,并在发送期间继续使用内存缓冲区记录被执行的写入命令 | 丢弃所有旧数据(如果有的话),开始载入主服务器发来的快照文件 |
情况2:当步骤3正在执行或者已经执行完毕后,当主服务器与较早进行连接的从服务器执行完复制所需的5个步骤之后,主服务器会与新连接的从服务器执行一次新的步骤1-5 | ||
4 | 快照文件发送完毕,开始向从服务器发送存储在缓冲区里面的写入命令 | 完成对RDB快照文件的解释操作,像往常一样开始接受客户端命令请求 |
5 | 缓冲区存储的写入命令发送完毕,从现在开始,每执行一个写入命令,就向从服务器发送相同的写入命令 | 执行主服务器发来的所有存储在内存缓冲区的写入命令,并从现在开始,接收并执行主服务器传来的每一个写入命令 |
4.主从链
当创建多个从服务器时可能会造成网络不可用,那是因为RDB文件是通过互联网传递,从服务器也可以拥有自己的从服务器,进而形成主从链,一环扣一环,形成长长的锁链;
从从复制与主从复制的唯一区别在于:如果从服务器X拥有从服务器Y,那么当从服务器X在执行步骤4时,服务器X会主动断开与从服务器Y的连接,进而导致从服务区Y需要重新连接并重新同步resync;
5.slaveof命令
slaveof host port
通过执行SLAVEOF命令,可以将当前服务器转变为指定服务器host的从属服务器;如果当前服务器已经从服务器,那么执行SLAVEOF host port将使当前服务器停止对旧主服务器的同步,丢弃旧数据集,转而开始对新主服务器进行同步;
host指的是主服务器的IP地址,port指的是主服务器Redis数据库端口号;
slaveof no one
将使得这个从服务器关闭复制功能,并从从服务器转变回主服务器,原来同步所得的数据集不会被丢弃;利用这个特性,可以在主服务器失败的时候,将从服务器用作新的主服务器,从而实现无间断运行;
注意:从节点只能读get,不能写set,只能从主节点同步数据;
6.主从复制与网络延迟
主从复制需要经过网络来传输,既然是通过网络来传输,可以可以配置传输方式,是有一条发一条,还是先积攒N条之后再一次性发过去呢,这里就需要参数repl-disable-tcp-nodelay,该参数取值范围如下:
①yes:redis先合并小的TCP包从而节省带宽,但会增加同步延迟(40ms发一次),从而造成master与slave数据不一致,这种方式关注带宽性能;
②no:主服务器会立即发送同步数据,没有延迟,但会造成网络带宽卡顿,这种方式关注数据一致性;
有兴趣的话,可以自己私下查查TCP_NODELAY协议;
6.1.注意
在Redis 2.8.18版本之前,主服务器先通过bgsave在磁盘上生成RDB文件,然后再把RDB文件通过网络传输到从服务器,从服务器先把文件生成到磁盘上,然后清理掉数据,然后再从磁盘加载RDB文件;
从Redis 2.8.18开始,Redis支持无盘复制,即主服务器直接通过网络套接字把RDB内容发送到从服务器上,主服务器一边遍历内存,一边将序列化的内容发送到从节点,而从节点还是跟之前一样,先把接收到的内容存储到磁盘中,然后再进行一次性加载;
- info命令中与主从复制有关的信息
Replication模块
命令 | 备注 |
role | 当前实例的角色master还是slave |
connected_slaves | slave的数量 |
master_replid | 主实例启动随机字符串 |
master_replid2 | 主实例启动随机字符串2 |
slave:ip,port,state,offset,lag | slave机器的信息、状态 |
master_repl_offset | 主从同步偏移量,此值如果和上面的offset相同说明主从一致没延迟,与master_replid可被用来标识主实例复制流中的位置 |
second_repl_offset | 主从同步偏移量2,此值如果和上面的offset相同说明主从一致没延迟 |
repl_backlog_active | 复制缓冲区是否开启 |
repl_backlog_size | 复制缓冲区大小 |
repl_backlog_first_byte_offset | 复制缓冲区里偏移量的大小 |
repl_backlog_histlen | 此值等于 master_repl_offset - repl_backlog_first_byte_offset,该值不会超过repl_backlog_size的大小 |
8.主从模式缺点
主服务器无法提供服务后,不能自动切换,需要手工切换,为了避开这种手工切换,需要Redis的哨兵模式;
9.Sentinel哨兵
从Redis2.8版本开始提供了哨兵功能,下面说一下Sentinel工作流程:
①每个Sentinel以每秒钟一次的频率向它所知的Master、Slave、其他Sentinel实例发送一个PING命令;
②如果一个实例(instance)距离最后一次有效回复PING命令的时间超过down-after-milliseconds选项所指定的值, 则这个实例会被Sentinel标记为主观下线;
③如果一个Master被标记为主观下线,则正在监视这个Master的所有Sentinel要以每秒一次的频率确认Master的确进入了主观下线状态;
④当有足够数量的Sentinel(大于等于配置文件指定的值)在指定的时间范围内确认Master的确进入了主观下线状态, 则Master会被标记为客观下线;
在Sentinel集群通过Raft算法选择一个Sentinel来作为Leader,然后由Leader完成故障转移流程。
⑤在一般情况下,每个Sentinel会以每10秒一次的频率向它已知的所有Master、Slave发送INFO命令;
⑥当Master被Sentinel标记为客观下线时,Sentinel向下线的Master的所有Slave发送INFO命令的频率会从10秒一次改为每秒一次;
Sentinel Leader向某个节点发送slaveof no one命令,让它成为独立节点,然后向其他节点发送slaveof host port(本机服务),让它们成为这个节点的子节点,故障转移完成。
⑦若没有足够数量的Sentinel同意Master已经下线,Master的客观下线状态就会被移除,若Master重新向Sentinel的PING命令返回有效回复, Master的主观下线状态就会被移除;
官网:https://redis.io/topics/sentinel
- sentinel.conf配置文件说明
参数名 | 参数说明 |
port | 哨兵sentinel实例运行的端口,默认26379 |
dir | 哨兵sentinel的工作目录 |
sentinel monitor <master-name> <ip> <redis-port> <quorum> | ①哨兵sentinel监控的redis主节点的ip、port; ②master-name可以自己命名的主节点名字,只能由字母A-z、数字0-9、这三个字符".-_"组成; ③quorum配置多少个sentinel哨兵统一认为master主节点失联,那么这时客观上认为主节点失联了; |
sentinel auth-pass <master-name> <password> | ①当在Redis实例中开启了requirepass foobared 授权密码 ,这样所有连接Redis实例的客户端都要提供密码; ②设置哨兵sentinel连接主从的密码,注意必须为主从设置一样的验证密码; |
sentinel down-after-milliseconds <master-name> <milliseconds> | 指定多少毫秒之后,主节点没有应答哨兵sentinel,此时哨兵主观上认为主节点下线,默认30秒 |
sentinel parallel-syncs <master-name> <numslaves> | 这个配置项指定了在发生failover主备切换时最多可以有多少个slave同时对新的master进行同步,这个数字越小,完成failover所需的时间就越长,但是如果这个数字越大,就意味着越 多的slave因为replication而不可用。可以通过将这个值设为1来保证每次只有一个slave 处于不能处理命令请求的状态。 |
sentinel failover-timeout <master-name> <milliseconds> | 故障转移的超时时间 failover-timeout 可以用在以下这些方面: 1. 同一个sentinel对同一个master两次failover之间的间隔时间。 2. 当一个slave从一个错误的master那里同步数据开始计算时间。直到slave被纠正为向正确的master那里同步数据时。 3.当想要取消一个正在进行的failover所需要的时间。 4.当进行failover时,配置所有slaves指向新的master所需的最大时间。不过,即使过了这个超时,slaves依然会被正确配置为指向master,但是就不按parallel-syncs所配置的规则来了 默认三分钟 |
sentinel notification-script <master-name> <script-path> | 配置当某一事件发生时所需要执行的脚本,可以通过脚本来通知管理员,例如当系统运行不正常时发邮件通知相关人员。对于脚本的运行结果有以下规则: 1.若脚本执行后返回1,那么该脚本稍后将会被再次执行,重复次数目前默认为10 2.若脚本执行后返回2,或者比2更高的一个返回值,脚本将不会重复执行。 3.如果脚本在执行过程中由于收到系统中断信号被终止了,则同返回值为1时的行为相同。 4.一个脚本的最大执行时间为60s,如果超过这个时间,脚本将会被一个SIGKILL信号终止,之后重新执行 |
sentinel client-reconfig-script <master-name> <script-path> | 客户端重新配置主节点参数脚本 当一个master由于failover而发生改变时,这个脚本将会被调用,通知相关的客户端关于master地址已经发生改变的信息。以下参数将会在调用脚本时传给脚本: <master-name> <role> <state> <from-ip> <from-port> <to-ip> <to-port> 目前<state>总是“failover”, <role>是“leader”或者“observer”中的一个。 参数 from-ip, from-port, to-ip, to-port是用来和旧的master和新的master(即旧的slave)通信的 这个脚本应该是通用的,能被多次调用,不是针对性的。 |
11.Sentinel哨兵模式缺点
主从切换的过程中会丢失数据,因为只有一个master,只能对这一个master进行get与set,没有解决水平扩容的问题。
如果数据量非常大,需要多个master-slave的group,把数据分布到不同的group中,那么,针对这些group,数据该如何均匀落到这些不同的group中?
12.Redis分布式方案
方式名称 | 说明 |
在客户端实现相关的逻辑 | Jedis客户端提供了RedisSharding的方案,并且支持连接池。使用ShardedJedis之类的客户端分片代码的优势是配置简单,不依赖于其他中间件,分区的逻辑可以自定义,比较灵活。 但是基于客户端的方案,不能实现动态的服务增减,每个客户端需要自行维护分片策略,存在重复代码。 |
把做分片处理的逻辑抽取出来,运行一个独立的代理服务,客户端连接到这个代理服务,代理服务做请求的转发 | 典型的代理分区方案有Twitter开源的Twemproxy和国内的豌豆荚开源的Codis |
基于服务端实现 | Redis Cluster |
13.Redis Cluster
Redis Cluster是在Redis3.0的版本正式推出的,用来解决分布式的需求,同时也可以实现高可用。跟Codis不一样,它是去中心化的,客户端可以连接到任意一个可用节点;