分布式系统,涉及到一个非常关键的问题:单点问题
如果某个服务器程序,只有一个节点,就会出现:
- 可用性问题(这个服务器挂了,服务中断)
- 性能/支持的并发量有限
引入分布式系统,主要也是为了解决上述的单点问题
在分布式系统中,希望有多个服务器来部署redis服务,从而构成一个redis集群,此时就可以让这个集群给整个分布式系统中其它的服务,提供更稳定/高效的数据存储功能
下面有三种redis的部署方式:
主从模式 主从+哨兵 集群模式
此处来讲解主从模式
1. 配置
参与复制的Redis实例划分为主节点(master)和从节点(slave)。每个从结点只能有⼀个主节点, ⽽⼀个主节点可以同时具有多个从结点。
复制的数据流是单向的,只能由主节点到从节点,改变主节点的内容,同步到从节点
从节点的数据时刻和主节点保持一致,因此其它的客户端从从节点这里读取数据,和从主节点这里读取数据,没有区别
从节点数据只能读取,不允许修改
之前只是单个redis服务器节点,此时这个机器挂了,整个redis就挂了,引入主从结构,就不太可能一锅端了
主从模式,主要如果主节点挂了,无法写数据,只能读,从节点挂了,无影响
主从模式针对"读操作"进行并发量,可用性提高
那可以引入多个主节点嘛?
不可以,一山不容二虎,谁听谁呢
建立复制
此时在一个云服务器主机上,运行多个redis-server进程
让新启动的redis-server使用其它端口
1.在配置⽂件中设定端口
- 在redis-server 启动时,通过命令行指定端口 --port选项
下面一个主节点,两个从节点:
按c进行修改,ctrl+c进行退出修改界面,:wq保存退出
表示可以按照后台方式进行运行
当前这几个节点并没有构成主从结构,下面需要进一步配置:
1.在配置⽂件中加⼊slaveof{masterHost}{masterPort}随Redis启动⽣效。
-
在redis-server 启动命令时加⼊--slaveof{masterHost}{masterPort}⽣效。
-
直接使⽤redis命令:slaveof{masterHost}{masterPort}⽣效
修改之后,重新启动,生效
这种停止redis-server的方式,kii之后,redis-server进程能够自动启动
而如果使用service redis-server start这种方式启动,必须使用service redis-server stop停止
从节点启动之后就会和主节点建立tcp连接.主节点相当于服务器,从节点相当于客户端
此时主节点这里的数据进行修改,从节点能立即感知到:
从节点无法写:
主从节点复制过程
1)查看主节点复制状态信息:
主节点会收到源源不断的修改数据请求,从节点就需要从主节点这里同步这些修改请求
从节点和主节点之间的数据同步,不是瞬间完成的
offset:相当于同步数据的进度
lag:表示延迟,网络有可能延迟情况
master_replid:主节点的身份标识,从节点会记录
repl:积压缓冲区,支持部分同步机制的实现
2)查看从节点复制状态信息:
断开复制
slaveof no one命令
从节点断开主从关系后,就不属于其它节点了,但里面已有的数据不会抛弃
此时让6380作为6381的从节点:
此时,6381看起来是个主节点,但实际上仍然是从节点,不能修改数据
虽然刚才通过slaveof命令修改了主从结构,但是此处的修改是临时性的,重新启动redis服务器,仍然会按照最初在配置文件中设置的内容建立主从关系
安全性
对于数据⽐较重要的节点,主节点会通过设置requirepass参数进⾏密码验证,需要配置从节点的masterauth参数与主节点密码保持⼀致,这样从节点才可以正确地连接到主节点并发起复制流程
只读
从节点不允许修改
传输延迟
主从节点之间通过网络传输(tcp)
TCP内部支持nagle算法(默认开启):
开启,就会增加传输延迟,节省网络带宽
关闭,就会减少传输延迟,增加网络带宽
2. 拓扑
一主一从
如果写数据请求太多,此时会给主节点造成压力
可以通过关闭主节点的AOF,只在从节点开启AOF
但是,这种设定方式,会有一个严重的缺陷:主节点一旦挂了,不能让他自动重启(如果自动重启,没有AOF文件,就会丢失数据,进一步的主从同步,会把从节点的数据也删了)
改进:主节点挂了后,让主节点从从节点获取AOF文件,再启动
一主多从
主节点上的数据发生改变,就会把改变的数据同时同步给所有的从节点,网络延时小
随着从节点个数的增加,同步一条数据,需要传输多次
改进:
树状主从
此时,主节点就不需要那么高的网卡带宽了
但是一旦数据修改了,同步的延时更长
3. 原理
主从节点建⽴复制流程图
数据同步psync
redis提供了psync命名,完成数据同步的过程,分为:全量复制和部分复制
- 全量复制:⼀般⽤于初次复制场景,Redis早期⽀持的复制功能只有全量复制,它会把主节点全部数据⼀次性发送给从节点,当数据量较⼤时,会对主从节点和⽹络造成很⼤的开销。
- 部分复制:⽤于处理在主从复制中因⽹络闪断等原因造成的数据丢失场景,当从节点再次连上主节点后,如果条件允许,主节点会补发数据给从节点。因为补发的数据远⼩于全量数据,可以有效避免全量复制的过⾼开销
不需要手动执行,redis服务器会在建立好主从同步关系之后,自动执行
从节点负责执行psync,从节点从主节点这边拉取数据
语法:
psync replicationid offset
①replicationid/replid (复制id)
是主节点启动时生成的
即使是同一个主节点,每次重启生成的replicationid都是不同的
从节点晋升为主节点,也会生成
主从关系建立时,从节点就会从主节点这边获取到replicationid
一般情况下,replid2用不上
举个例子:
有一个主节点A,从节点B
在A和B通信过程中出现了网络抖动
B就可能认为A挂了
B就会自己成为主节点,给自己生成一个repid,此时B也会记得之前旧的replid,即replid2
后续网络稳定了,B还可以根据replid2重新恢复之前的状态
②offset(偏移量)
主节点和从节点都会维护整个偏移量(整数)
主节点的偏移量:主节点会收到很多修改操作的命令,每个命令都要占据几个字节,主节点会把这些命令,每个命令的字节数进行累加
从节点的偏移量:描述了现在从节点这里的数据同步到哪里了
如果从节点的偏移量和主节点一样,就赶上"直播"了
从节点每秒上报自身的复制偏移量给主节点
总结:
replicationid和offset共同描述了一个"数据集合",
如果两个机器的这两个变量都一样,就可以认为这两个redis机器上存储的数据完全一样
psync运行流程
psync可以从主节点获取全量数据,还是获取一部分,主要看offset这里的进度
offset=-1,就是获取全量数据
offset写具体的正整数,则是从当前偏移量位置来进行获取
获取所有数据,是最稳妥的,但是比较低效,如果从节点之前以及把主节点这里复制过一部分数据了,就只需要把没复制的数据搞来就可
当然,不是从节点索要哪部分,主节点就一定给哪部分,主节点会自行判定,看当前是否方便给部分数据,不方便就给全量
全量复制
什么时候全量复制
1.首次和主节点进行数据同步
2.主节点不方便进行部分复制
全量复制的流程
流程描述:
- 从节点发送psync命令给主节点进⾏数据同步,由于是第⼀次进⾏复制,从节点没有主节点的运⾏ID和复制偏移量,所以发送psync?-1。
- 主节点根据命令,解析出要进⾏全量复制,回复+FULLRESYNC响应。
- 从节点接收主节点的运⾏信息进⾏保存。
- 主节点执⾏bgsave进⾏RDB⽂件的持久化。
- 从节点发送RDB⽂件给从节点,从节点保存RDB数据到本地硬盘。
- 主节点将从⽣成RDB到接收完成期间执⾏的写命令,写⼊缓冲区中,等从节点保存完RDB⽂件 后,主节点再将缓冲区内的数据补发给从节点,补发的数据仍然按照rdb的⼆进制格式追加写⼊到收 到的rdb⽂件中.保持主从⼀致性。
- 从节点清空⾃⾝原有旧数据。
- 从节点加载RDB⽂件得到与主节点⼀致的数据。
- 如果从节点加载RDB完成之后,并且开启了AOF持久化功能,它会进⾏bgrewrite操作,得到最近的AOF⽂件。
注意:
- 在主节点生成rdb文件和传输rdb文件的过程中,还会继续收到很多新的修改操作.新修改的数据,也必须同步给从节点,当从节点收完了主节点发来的rdb之后,主节点就会把这些新修改的操作发送给从节点
- 如果从节点,已经开启了AOF,在上述的加载数据过程中,从节点就会产生很多的AOF日志,由于当前收到的是大批量的数据,此时产生的AOF日志,整体来说会存在一定的冗余信息,因此要针对AOF日志进行整理
全量复制的无硬盘模式
主节点,进行全量复制的时候,也支持"无硬盘模式":
就是主节点生成的rdb的二进制数据,不直接保存在文件中,而是直接进行网络传输,省下了一系列读硬盘和写硬盘的操作
从节点也是先把收到的rdb数据,写入硬盘中,然后再加载,现在就可以省略这个过程,直接把收到的数据进行加载了
即使引入了无硬盘模式,整个操作仍然比较耗时,网络传输是不能省的,相比于网络传输,读写硬盘是小事
runid和replid
在一个redis服务器上,两者是都存在的,但是不一样
主节点:
info replication:
info server:
从节点:
run_id是每个节点都不相同的
replid则是具有主从关系的节点,是相同的
官方文档上,明确说了此处使用replicationid
部分复制
什么时候部分复制
从节点之前已经从主节点复制过数据,因为网络抖动或者从节点重启了,从节点需要重新同步数据,看看能不能只同步一部分(大部分数据一致)
但网络抖动,一般都是暂时的,恢复后就可以重新建立联系,此时就需要进行数据的同步
部分复制的流程
psync带有具体的replid和offset
主节点就要根据psync的参数进行判定进行什么复制
流程:
- 当主从节点之间出现⽹络中断时,如果超过repl-timeout时间,主节点会认为从节点故障并终端复制连接。
- 主从连接中断期间主节点依然响应命令,但这些复制命令都因⽹络中断⽆法及时发送给从节点,所 以暂时将这些命令滞留在复制积压缓冲区中。
- 当主从节点⽹络恢复后,从节点再次连上主节点。
- 从节点将之前保存的replicationId和复制偏移量作为psync的参数发送给主节点,请求进⾏部分复制。
- 主节点接到psync请求后,进⾏必要的验证。随后根据offset去复制积压缓冲区查找合适的数据, 并响应+CONTINUE给从节点。
- 主节点将需要从节点同步的数据发送给从节点,最终完成⼀致性。
积压缓冲区:
是一个内存中的简单队列,会记录最近一段时间修改的数据,总量有限,随着时间的推移,就会把之前的旧数据删除
主节点看这个进度是否在当前的积压缓冲区之内,如果在,就可以进行部分复制,把最近这段时间的数据复制过去即可
如果已经超出积压缓冲区的范围,就得全量复制了
实时复制
主从节点在建⽴复制连接后,主节点会把⾃⼰收到的修改操作,通过tcp⻓连接的⽅式,源源不断的传 输给从节点.从节点就会根据这些请求来同时修改⾃⾝的数据.从⽽保持和主节点数据的⼀致性.
这样的⻓连接,需要通过⼼跳包的⽅式来维护连接状态
心跳包机制
主节点:默认,每隔10s给从节点发送一个ping命令,从节点收到就返回pong
从节点:默认,每隔1s就给主节点发起一个特定的请求,就会上报当前从节点复制数据的进度offset
如果主节点发现从节点通信延迟超过repl-timeout配置的值(默认60秒),则判定从节点下线,断 开复制客⼾端连接。从节点恢复连接后,⼼跳机制继续进⾏
从节点晋升为主节点的问题
从节点和主节点断开的情况:
1.slave no one 这个时候,可以晋升
2.主节点挂了 这个时候,从节点不会晋升,必须通过人工干预的方式恢复主节点,脱离掌控
可以通过service redis-server stop模拟一下(简,后续再修改):
1.停止之前的redis服务器
2.删除之前工作目录下,已经生成的AOF文件,或者也可以通过chown命令修改AOF文件所属的用户
3.给从节点创建出新的目录,作为从节点的工作目录,并且修改从节点的配置文件,设定为新的目录为工作目录
4.启动服务器