Redis集群-主从架构
作者:互联网
1.为什么需要集群?
互联网思维一向讲究的是三高,即高并发,高可用,高性能。高并发:系统能够同时并行处理的请求,主要度量指标有响应延时,吞吐量,每秒查询处理,每秒事务处理,并发用户等;高可用:当系统某些节点故障时,系统依然可以对外提供服务,正常处理请求;高性能:程序的处理速度快,资源消耗最低(CPU、内存占用率低)的情况下利用率也要足够高【比如:当线程因为IO阻塞时,CPU空闲】。通常情况下集群可以对这三高起到积极的作用,如:通过增加节点数量,系统整体能并行处理的请求数变多(高并发);当某个节点故障时,其他节点依然可以将故障节点的流量进行处理(高可用);如果单个节点的系统吞吐量已经到达瓶颈了。增加节点的数量,等量的请求到达系统时,每个节点分得的流量变少了,处理的时间就会缩短,在外部看来,自然就更快了(高性能)。
2.主从架构可以解决什么问题?
主从架构师集群的一种模式,它侧重于解决系统的高可用问题,即当主节点故障时,可以快速通过从节点对外进行恢复。比如:Kafka中分区的副本;MySQL的主从;Redis的主从等等。
3.Redis如何实现主从?
一般来说实现主从最重要的就是主从之间的数据一致性问题该如何解决,而且必须控制数据一致性的延时在一定的范围之内,延时越小宕机恢复后数据丢失就越小。Redis使用了全量和增量复制的机制来让从节点的数据能尽量快的与主节点保护一致。
3.1全量复制与增量复制
全量复制:Redis的全量复制其实就是通过将主节点的RDB快照将全量数据发送给从节点,从而让从节点可以最快的与主节点中的内存数据一致。
生成RDB快照的时候,主节点的主线程仍然是可以继续接受客户端的请求执行命令,这一部分也叫作增量数据,而这些增量数据如果不能及时的同步给从节点,就会造成数据不一致的问题。
增量复制:Redis的增量复制其实是通过复制积压缓冲区实现的。当从节点加载完RDB快照时,就会不停的向主节点发送数据偏移量,主节点就会从复制积压缓冲区中的增量数据发送给从节点,从而达到增量数据的同步。
3.2复制积压缓冲区(repl_backlog_buffer)
复制积压缓冲区的底层数据结构是一个环形队列,它的作用是保存Redis主节点最近执行的所有写命令,方便从节点增量同步。复制积压缓冲区的大小可以通过配置repl_backlog_size进行设置,默认1M,生产环境最好是将它改成跟自己业务体量相匹配的大小。
复制积压缓冲区的工作原理:Redis的开启主从模式后,内存里会有一个自增的偏移量对应每一条写命令,每一条写命令都会写到aof-buffer(AOF日志)和repl_backlog_buffer(积压缓冲区)。当从节点向主节点发起同步请求时会携带自己最大的偏移量,主节点收到该同步请求后,就会先向复制积压缓冲区里边判断该偏移量是否还存在。如果不在了,主节点就会向从节点执行全量复制,即执行一个RDB快照并发送给从节点;如果还在就会将执行增量复制,即将该偏移量之后的命令发送给从节点。
3.3复制风暴
什么情况下会导致,从节点最大偏移量的数据不在复制积压缓冲区呢?最根本的原因就是因为主节点的接受到的写命令太多,直接将复制积压缓冲区的旧数据给覆盖了,而导致这种现象的原因就比较多了。如:1.复制积压缓冲区设置过小;2.从节点执行数据同步慢;3.网络原因。当复制积压缓冲区被写满,主节点只能执行RDB快照并发送给从节点进行同步,而生成RDB之后,需要经过内核拷贝到客户端缓冲区经过网络IO,最终从节点经过网络IO又发生一次内核拷贝才能进行数据的恢复,成本很高,消耗的时间也比较大。在这区间如果从节点还没执行完成这次的全量复制,而主节点的复制积压缓冲区又再次被覆写了上一次的数据偏移量,这就意味着从节点又需要开始进行全量复制了,这种从节点不停的向主节点进行全量复制的现象就是复制风暴。
3.4客户端缓冲区
客户端缓冲区是一个统称,连接到主节点普通客户端也会有自己的一个缓冲区一般称之为client buffer。对于主节点来说,从节点也是一个客户端也有自己的缓冲区,而每一个从节点的缓冲区叫做replication buffer。客户端缓冲区是Redis节点与所有客户端进行数据交互的一个内存区域,如果某个客户端缓冲区过大的时候,Redis会主动与该客户端断开连接回收内存。
3.5无盘复制
主节点进行全量复制的流程是:1.生产RDB快照并写到文件;2.将RDB快照读取到从客户端缓冲区;3.发送RDB文件。可以看到在主节点生成RDB快照的时候如果可以直接写到从客户端的缓冲区,就可以减少文件的IO,并且可以降低内核的调用与数据拷贝,从而提升性能。这个优化其实就是无盘复制,即生成的RDB文件不写入到磁盘,全程在内存里,所以叫无盘复制。因为RDB文件一般都较大,并且一直在内存中,所以比较适合网络畅通,从节点性能较好的场景,否则会占用主节点的内存,引发其他问题。
3.6主从节点的整体复制过程
1.主从服务建立socket连接
2.从服务器发送ping命令
3.主服务器响应pong命令,验证从服务器密码
4.从服务器保存主服务器信息(runid、masterip、masterport、…)
从服务器发送psync命令(psync ${master-runid} ${offset})
主服务器执行bgsave,并记录写命令到积压缓冲区,向从服务器发送RDB快照
从服务器加载RDB快照,完成数据同步,修改offset
从服务器再次发起psync ${master-runid} ${offset}命令
主服务器查看psync中的master-runid以及offset,发送写命令
从服务器执行写命令
4.主从节点必须要注意的问题
4.1主从节点的配置
部分参数配置可以不同(如:AOF),但是与内存相关的参数(maxmemory,hash-max-ziplist-entries)必须要一致,否则当从节点的数据量超过已分配的内存时,会触发maxmemory-policy策略进行内存溢出的控制。此时,从节点的数据必然会回收一部分(否则必然发生OOM),而主从复制流程依然正常进行,复制偏移量依然不变,这就会导致主从数据不一致。
4.2传输延迟问题
主从节点一般部署在不同机器上,复制时必然存在网络延迟。Redis提供了repl-disable-tcp-nodelay参数用于控制是否关闭TCP_NODELAY[默认关闭]。当该参数开启时,主节点会合并较小的TCP数据包从而节省带宽。 默认发送时间间隔取决于Linux的内核,一般默认为40毫秒。 这种配置节省了带宽但增大主从之间的延迟。当关闭时,主服务器会将所有命令数据及时地发送给从服务器,降低延迟,但是会增加网络带宽的消耗。注意tcp_backlog参数的理解。
5.Redis主从能否实现读写分离?
对于读占比较高的场景,确实可以通过把一部分读流量分摊到从节点来减轻主主节点的压力,同时所有写操作必须在主节点中执行。假设Redis现在的从节点可以执行读命令,那么使用了读写分离会有以下几个问题。
1.数据延迟问题:主从之间的数据必定是存在延迟的,如果现在主节点写入一个数据,客户端立马去从节点读取该数据,此时因为主节点的数据尚未同步到从节点,所以客户端认为该数据不存在,对于这种情况,业务端需要自己做出决策,究竟是读从节点读不到时,就去读主节点还是其他方案。此时如果选择去读取主节点,那么主节点仍然是承担了一部分读请求。
2.数据过期问题:主节点负责所有数据的写操作,当一个数据过期的时候,从节点并不会对该数据执行任何操作,从节点的数据全部来自于主节点。所以从节点是无法判断一个数据有没有过期的,所以这就需要业务侧对这种情况进行考虑。
3.客户端路由问题:当从节点宕机的时候,就需要业务端有自己的判断机制,是转向主库还是有其他的多个从节点作为备选方案。
事实上,Redis的从节点默认情况下是不会接受任何读写数据的请求的,从节点的目标只有一个就是作为主节点数据的副本,以提供主节点宕机后的快速恢复。换句话说Redis现在的主从架构默认情况下是不支持读写分离的。
再回到读写分离的本质上,为什么需要进行读写分离?无非就是分担主节点的压力,所以如果能够将主节点的压力降低到足够承受的地步,那么久自然不需要所谓的读写分离了。而主节点的压力绝大部分都是来自于主线程的阻塞,所以归根究底就是要把Redis的阻塞扼杀掉。Redis的性能瓶颈常见项
参考资料
1.极客时间专栏课-redis核心技术与实战
2.<<Redis开发与运维>>
3.<<Redis深度历险:核心原理与应用实践>>
4.<<Redis设计与实现>>
标签:架构,Redis,节点,复制,缓冲区,主从,客户端 来源: https://www.cnblogs.com/zhenjungan/p/16504092.html