接下来继续介绍Redis中的主从复制~
在分布式系统中,涉及到一个和关键的问题:单点问题。
如果某个服务器程序只有一个节点(只搞一个服务器来部署这个服务器程序)就会出现一些问题:
- 可用性问题:如果这个服务器挂了,就意味着服务中断了。
- 性能/支持的并发量是有限的。
引入分布式系统也是为了解决上述的单点问题!
在分布式系统中,往往希望用多个服务器部署redis服务,从而构成一个redis集群,此时就可以让这个集群给整个分布式系统中的其他服务提供更稳定和高效的数据存储功能~
主从模式
在分布式系统中,存在三个redis的部署方式:
- 主从模式
- 主从+哨兵模式
- 集群模式
本章就先来介绍主从模式
在若干个redis节点中,有的是“主节点”,有的是“从节点”;加入有三个物理服务器(称为三个节点)分别部署了redsi-server进程,此时就可以把其中一个节点当作“主节点”,另外两个当作“从节点”;从节点要听主节点的(从节点的数据跟随主节点的变化而变化,从节点数据跟主节点数据要保持一致)并且redis的主从模式中,从节点上的数据只能读取数据,是不可以修改的!!!
此时再来看单点问题:
可用性问题:之前是一个节点,服务器挂了,整个redis就挂了,而现在有多个机器,不太可能出现同时挂了的场景,并且考虑到更高的可用性,会把这些机器放到不同机房,防止机房被一锅端的情况(异地多活)。
性能/并发量有限的问题:因为从节点的数据时刻都跟主节点数据保持一直,所以其他客户端从从节点这里读取数据跟从主节点这里读取数据没什么区别,后面客户端来读取数据,就可以随机选一个节点给客户端提供读取数据服务;因为引入了更多的计算机资源,自然能够支撑的并发量也就大幅提高了。
Redis主从复制的问题
其实更准确地说,redis的主从复制主要是针对“读操作”进行并发量和可用性的提高;而写操作的话,无论是可用性还是并发量,都是非常依赖主节点的;如果挂了某个从节点是没啥影响的,客户端仍然可以从主节点/其他从节点读取,但要是挂了主节点的话,客户端就只能读取数据了,没地方写入数据。
配置Redis主从结构
想要配置主从结构有三种方式:
masterHost是主节点ip,masterPort则是主节点端口;配置文件中的daemonize要改为yes(按照后台程序方式来运行)。
注意redis服务器的配置文件改完了之后,需要重新启动才能生效。
还有一点,用kill -9停止redis-server的方式和直接运行redis-server方式相搭配的(kill -9杀掉进程之后,redis-server进程可以自动启动);而用service redis-server start方式启动的,必须使用service redis-server stop的方式来停止哦~
主从复制
主从复制过程
下面是主从复制的流程图
- 先保存主节点的ip跟端口。
-
从节点(slave)内部通过每秒运⾏的定时任务维护复制相关逻辑,当定时任务发现存在新的主节 点后,会尝试与主节点建⽴基于 TCP 的⽹络连接。如果从节点⽆法建⽴连接,定时任务会限重试直到连接成功或者⽤⼾停⽌主从复制
-
发送 ping 命令。连接建⽴成功之后,从节点通过 ping 命令确认主节点在应⽤层上是⼯作良好的。如果 ping 命令的结果 pong 回复超时,从节点会断开 TCP 连接,等待定时任务下次重新⽴连接
-
权限验证。如果主节点设置了 requirepass 参数,则需要密码验证,从节点通过配置 masterauth参数来设置密码。如果验证失败,则从节点的复制将会停⽌。
-
同步数据集。对于⾸次建⽴复制的场景,主节点会把当前持有的所有数据全部发送给从节点,这步操作基本是耗时最⻓的,所以⼜划分称两种情况:全量同步和部分同步。
6. 命令持续复制。当从节点复制了主节点的所有数据之后,针对之后的修改命令,主节点会持 续的把 命令发送给从节点,从节点执⾏修改命令,保证主从数据的⼀致性。可以通过info replication命令查看复制相关状态
数据同步psync
redis提供了psync命令,完成数据同步的过程;注意!是从节点负责执行psync,从节点从主节点这边拉取数据。
psync的语法格式:psync replicationid offset.
如果replicationid设为? offset设为-1,此时就是在尝试进行全量复制。
如果replicationid offset设为具体的数值,则是尝试进行部分复制。
replication/replid(复制id)
主节点启动的时候会生成。从节点晋升到主节点的时候,也会生成,同一个主节点每次重启后生成的replicationid是不同的;从节点和主节点建立了复制关系,就会从主节点这边获取到replicationid
可以看到除了replid1还有个replid2;在某种情况下才会用到replid2,比如a和b通信过程出现了网络抖动,导致b认为a挂了,b就会自己成为主节点(给自己生成一个replid),但也会记得旧的replid,就是通过replid2;后面网络稳定了,b仍然可以成为a的从节点。
offset偏移量
主节点和从节点上都会维护偏移量(整数),主节点的偏移量:主节点会收到很多修改操作的命令,每个命令都会占几个字节,主节点会把这些修改操作的命令的字节数进行累加。
从节点的偏移量:就描述了从节点现在数据同步到哪里了。
从节点每秒会上报自身的偏移量给主节点。
psync运行流程
- 从节点发送psync命令给主节点,replid和offset的默认值是?和-1
- 主节点根据psync参数和自身数据情况决定响应结果。
- 如果回复+fullresync,则从节点需要进行全量复制数据。
- 如果回复+contineu,从节点进行部分复制流程。
- 如果回复-err,说明redis主节点版本过低,不支持psync命令,从节点可以用sync命令进行全量复制。
全量复制
什么时候进行全量复制:
1.首次跟主节点进行数据同步。
2.主节点不方便进行部分复制的时候。
全量复制流程:
- 从节点发送psync命令给主节点进行数据同步,由于是第一次进行复制,从节点没有主节点的运行id跟offset,所以发送?和-1。
- 主节点根据命令,解析出要进行全面复制,回复+FULLRESYNC响应。
- 从节点接受主节点的运行信息进行保存。
- 主节点执行bgsave进行RDB文件的持久化。
- 主节点发送RDB文件给从节点,从节点保存RDB数据到本地硬盘中。
- 主节点将从生成RDB到接收完毕期间执行的写命令,写入到缓冲区中,等从节点保存完RDB文件后,主节点再将缓冲区内的数据补发给从节点,补发的数据仍然按照rdb二进制的格式追加写入到收到的rdb文件中,保持主从一致性。
- 从节点清空自身原有的旧数据。
- 从节点加载RDB文件得到与主节点一样的数据。
- 如果从节点加载完RDB完成之后,并且开启了AOF持久化功能,它会进行bgrewrite操作,得到最后的AOF文件(由于当前收到的是大批量的数据,此时产生的aof日志会有一定的冗余信息,所以对aof日志进行整理是必要的)。
主节点进行全量复制的时候也支持“无硬盘模式”:
主节点生成的rdb二进制数据不直接保存到文件,而是直接进行网络传输。
从节点把收到的rdb数据不写入硬盘了,而是直接把收到的数据进行加载。
部分复制
什么时候用部分复制:
从节点本身已经持有了主节点的绝大部分数据,这个时候就可以用部分复制。
部分复制流程图:
-
当主从节点之间出现⽹络中断时,如果超过 repl-timeout 时间,主节点会认为从节点故障并终端复制连接。
-
主从连接中断期间主节点依然响应命令,但这些复制命令都因⽹络中断⽆法及时发送给从节点,所以暂时将这些命令滞留在复制积压缓冲区中。
-
当主从节点⽹络恢复后,从节点再次连上主节点。
-
从节点将之前保存的 replicationId 和 复制偏移量作为 psync 的参数发送给主节点,请求进⾏部分复制。
-
主节点接到 psync 请求后,进⾏必要的验证。随后根据 offset 去复制积压缓冲区查找合适的数据,并响应 +CONTINUE 给从节点。
-
主节点将需要从节点同步的数据发送给从节点,最终完成⼀致性。
复制挤压缓冲区
就是一个内存中简单的队列,会记录最近一段时间修改的数据,总量有限,随着时间推移,会删除之前旧数据。
如果replicationid一样,对offset判定,offset表示从节点之前同步数据进度如何,主节点就看这个进度是否在当前的积压缓冲区之内,在的话直接进行部分复制,不在的话进行全量复制。
实时复制
复制状态
主节点的复制状态过程:
127.0.0.1:6379> info replication# Replicationrole:masterconnected_slaves:1slave0:ip=127.0.0.1,port=6380,state=online,offset=100,lag=0//offset就是主节点和从节点之间同步数据的进度master_replid:2fbd35a8b8401b22eb92ff49ad5e42250b3e7a06master_replid2:0000000000000000000000000000000000000000master_repl_offset:100second_repl_offset:-1repl_backlog_active:1repl_backlog_size:1048576repl_backlog_first_byte_offset:1repl_backlog_histlen:100
断开复制
可以在从节点执行slaveof no one来断开与主节点的复制关系,但断开之后并不会丢失原有数据,只是无法再从主节点获取数据。
但是如果是通过修改配置文件建立的主从关系,即使断开连接,如果重启了redis服务器,仍然会按照配置文件中的内容来简历主从关系~
传输延迟
主节点和从节点之间通过网络来传输(TCP)
TCP内部支持nagle算法(默认开启),开启了就会增加tcp的传输延迟,节省了网络带宽;关闭了就会减少tcp的传输延迟,增加了网络带宽。目的和tcp的捎带应答是一样的(针对小的tcp数据报进行合并,减少了包的个数)
拓扑结构
一主一从结构
如果写数据要求太多,此时就会给主节点造成一些压力~可以关闭主节点的aof,只在从节点上开启aof。但是这种方式有一个很大的问题:主节点一旦挂了,不能让他自动重启(如果自动重启了,此时没有aof文件,就会丢失数据,进一步的主从同步,就会把从节点的数据也给删了)。
一主多从结构
树形主从结构
这种结构主节点就不需要那么高的网络带宽了,但一旦数据进行了修改,同步的延时是比刚才更长的,因为同步一条数据需要传输多次。
主从断开连接的情况
1.从节点主动和主节点断开连接 slave no one(这时候,从节点就晋升为主节点)。
2.主节点挂了(从节点不会生成主节点,必须人工干预的方式恢复主节点)。
关于redis主节点无法重启的问题
原因:aof文件是redis服务器启动时去加载的,但redis server需要按照可读可写的方式打开这个aof文件,但这个文件对于root之外的用户只有读权限,所以service redis-server start启动redis服务器无法打开这个aof文件。
解决方案:把几个redis服务器生成的文件和工作目录给区分开。
1.停止之前的redis服务器。
2.删除之前工作目录下已经生成的aof文件,也可以通过chown命令修改aof文件所属的用户。
3.给从节点创建出新的目录用来作为从节点的工作目录,并且修改从节点的配置文件,设定新的目录为工作目录。
4.启动redis服务器。