Redis系统学习之主从复制

Redis主从复制

  • 什么是主从复制(来自小姐姐的面试题72)?
  • 使用一个redis实例作为主机,其余的作为备份机。主机和备份的数据完全一致,主机支持写入和读取操作,而从机只支持数据同步和读取操作。客户端将数据写入当主机,由主机自动将数据同步到从机。因而可以将写入数据的命令发送给主机执行,读取数据的命令发送给不同的从机执行,达到读写分离的目的。(64为mysql的主从同步原理)
    • slave从节点不会竞选成为master,因为每个客户端连接redis实例时都指定了ip和端口号,如果所连接的redis实例故障下线了,而主从模式没有提供手段通知客户端另外可连接的客户端地址,则需要手动更改客户端配置重新连接。
    • 优点:7点
      • 一个master可以同步多个slaves
      • slave同样可以接收其他slaves的连接和同步请求,有效分载master的同步压力
      • master server是以非阻塞的方式为slaves提供服务,在master-slave同步期间,客户端仍然可以提交查询或修改的请求
      • slave server也是以非阻塞的方式完成数据同步,在同步期间,客户端提交查询请求,则返回同步前的数据
      • 为了分载master的读操作压力,slave服务器可以为客户端提供只读操作的服务,写服务由master来完成,系统的伸缩性得到了很大的提高
      • master可以将数据保存操作交给slaves完成,避免在master中要有独立的进程来完成此操作(不是写操作由master完成吗?)
      • 应该是由Master写到内存,然后slaves同步到自己的里面的
      • 支持主从复制,主机会自动将数据同步到从机,读写分离
    • 缺点:4点
      • redis不具备自动容错和恢复功能,主从机宕机都会导致前端部分读写请求失败,需要等待重启或手动切换前端ip才能恢复
      • 主机宕机前有部分数据未能及时同步到从机,切换ip后数据不一致,降低系统可用性
      • redis的主从复制采用全量复制,复制过程中主机会fork出一个子进程对内存做一份快照,并将子进程对内存快照保存为文件发送给从机。需要确保主机有足够多的内存空间,若快照文件较大,对集群对服务能力会产生较大的影响。而且复制过程是在从机新加入或从机和主机网络断连时都会进行,也就是网络波动会造成主机和从机间的一次全量复制,对系统运营造成麻烦。
      • redis较难支持在线扩容,运维人员在系统上线时必须确保有足够的空间,这对资源造成很大浪费
    • 主从复制的作用主要包括:
      • 数据冗余:主从复制实现了数据的热备份,是持久化之外的一种数据冗余方式
      • 故障恢复:当主节点出现问题时,可以由从节点提供服务,实现快速的故障恢复,实际上是一种服务的冗余
      • 负载均衡:在主从复制的基础上,,配合读写分离,可以由主节点提供写服务,由从节点提供读服务(就是写redis数据时应用连接主节点,读redis数据时,应用连接从节点),分担服务器负载,尤其是在写少读多的场景下,通过多个从节点分担读负载,可以大大提高redis服务器的并发量
      • 高可用基石:除了上述作用以外,主从复制还是哨兵和集群能够实施的基础,因此说主从复制是Redis高可用的基础
    • 一般来说Redis在项目中,不可能是一台的,当然也有,我之前做的就是
      • 从结构上,单个Redis服务器存在单点故障问题,并且一台服务器需要处理所有的请求负载,压力较大
      • 从容量上,单个Redis服务器内存容量有限,就算一台Redis服务器内存容量为256G,也不可能将所有内存用作Redis的存储内存,一般来说线上服务器,单台Redis最大使用内存不应该超过20G
    • 电商网站上的商品,一般都是一次上传,无数次浏览,其实就是读多写少
      • 对于这种场景我们可以使用下面这种架构
      • image.png

环境搭建

启动源redis

image.png

连接查看信息

[root@localhost bin]# redis-cli 连接客户端
127.0.0.1:6379> info replication
NOAUTH Authentication required.
127.0.0.1:6379> auth 123456 #认证
OK
127.0.0.1:6379> info replication 查看redis的信息
# Replication
role:master #当前位主节点
connected_slaves:0 #没有从节点
master_replid:32128903c20911483fef0c990175fc21c4139fac
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:0
second_repl_offset:-1
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
127.0.0.1:6379> config set requirepass "" # 设置密码为空,老麻烦了,老需要认证
OK
127.0.0.1:6379>

打开四个窗口,从左到右称为A B C D,上面的操作是A完成的

image.png

全部切换到 /usr/local/bin 目录下

A,关闭redis,因为刚才连接查看信息,后还在连接中,执行shutdown就可以了

image.png

A,查看服务已经关闭

image.png

A进入到redisConfig目录下,拷贝三份配置文件,拷贝redis.conf为 redis-6379.conf redis-6380.conf redis-6381.conf,因为默认的端口是6379,我是端口号直接往上加的,不用原来的配置文件,防止修改错误

image.png

A,修改redis-6379.conf redis-6380.conf redis-6381.conf三个配置文件

vi redis-6379.conf
logfile "" 修改为 logfile "6379.log"
dbfilename dump.rdb 修改为 dbfilename dump-6379.rdb
vi redis-6380.conf
port 6379 修改为 port 6380
pidfile /var/run/redis_6379.pid 修改为 pidfile /var/run/redis_6380.pid
logfile "" 修改为 logfile "6380.log"
dbfilename dump.rdb 修改为  dbfilename dump-6380.rdb
vi redis-6381.conf
port 6379 修改为 port 638
pidfile /var/run/redis_6379.pid 修改为 pidfile /var/run/redis_6381.pid
logfile "" 修改为 logfile "6381.log"
dbfilename dump.rdb 修改为  dbfilename dump-6381.rdb

A运行redis-6379.conf

image.png

B运行redis-6380.conf

image.png

C 运行redis-6381.conf

image.png

D 执行查看服务

image.png

一主二从配置(命令配置,命令配置是暂时的,就像设置密码一样缓存丢失,密码失效):

默认情况下,每台服务器都是主节点

只需要配置从机就可以了

规划:6379为主,80 81为从

A B C 都连接自己的redis进入cli界面

A:

image.png

B:

image.png

C:

image.png

只需要配置从节点就可以了,主节点不用动

B:执行设置主节点

命令:slaveof ip port

image.png

A:查看自己节点信息

image.png

C:执行设置主节点

image.png

A:查看自己的节点状态

image.png

一主二从搭建完成

配置文件配置(上面配置文件中没有写,在这里写)

# replicaof <masterip> <masterport> 删除前面的井号, 然后 后面的两个标签 分别是写 ip 和 端口的
# masterauth <master-password> 如果主节点有密码,删除前面的井号,后面的标签 写主节点的密码就可以了

刚才的命令也是在配置replicaof获取一下就看见了

B 获取从机配置文件中的replicaof

image.png

可以看到 就是IP 和端口

测试:

主机断开后,丛机依旧能获取到数据,但是这个时候没有了写操作,并且丛机不能自动提升为主机

主机重启成功后,从节点会自动连接到主节点,这个时候丛机依旧可以从主节点同步

如果丛机是采用命令行配置的主从,那么丛机宕机后重启就会自动变回原来的主节点,需要重新设置为从节点,并且在第一次连接主节点的时候,做全量数据复制,之后做增量复制

这种是默认的一主二从

架构的演变(层层链路模式)

6379为主节点,他的子节点是6380,6380的子节点是6381,所以他是从节点也是主节点,当然在6379还活着的时候他是从节点,如果6379宕机了,那么6380可以通过 slaveof no one使自己变成主节点,当然是手动的,但是层层链路有个问题,那就是中间节点宕机了,那么需要手动将他的下级节点指向他的上级节点,也就是说将6381指向6379,来完善链路

这里就可以有我想到了一个解决方案:

因为这个层层链路本省就是一个链表我们可以在,内存中维护这个链表,一旦中间的节点宕机,我们将这个链拿出来,等待重启之后添加到最后面,并指定他的主节点为最后一个层节点

类似于 1->2->3->4->5

在这个时候3宕机了,那么4直接指定自己的父节点为2

等3重启之后,直接指定自己的父节点为5就变成了

1->2->4->5->3

当然在工作中这些都是不用的[那我在学什么[手动滑稽]]

redis主从复制的核心原理(来自小姐姐的面试题73)

通过执行slaveof命令设置slaveof选项,当写操作导致数据变化时会自动将数据同步给从数据库,一个主库可以有多个从库,而一个从库只能有一个主库。

  • 全量复制
    • 主节点通过bgsave命令fork一个子进程进行RDB持久化,生成一个dump.rdb的全量快照文件,该过程是非常消耗CPU、内存(页表复制)、硬盘IO的
    • 主节点通过网络将RDB文件发送给从节点,对主节点的带宽会带来很大的消耗
    • 从节点清空老数据,载入新RDB文件的过程是阻塞的,无法响应客户端的命令,如果从节点执行bgrewriteaof(bg rewrite AOF)也会带来额外的消耗
  • 部分复制
    • 复制偏移量:执行复制的双方,主从节点分别会维护一个复制偏移量offset,当主从节点回复的偏移量记录不同时,以主节点为准
    • 复制积压缓冲区:主节点内部维护了一个固定长度(可以指定,也可临时更改长度)的、先进先出(FIFO)队列作为复制积压缓冲区,将offset后的数据放入队列,每次增量复制时,同步缓存区中的数据即可,避免操作硬盘。当主从节点的offset差距过大超过缓冲区长度时,将无法执行部分复制,只能全量复制
    • 服务器运行ID(runid):每个redis节点在启动时自动生成运行id,主节点会将自己的运行id发给从节点,从节点会保存起来,当主从节点断开后重连,从节点根据运行id判断同步方式:
      • 若从节点保存的runid与主节点现在的runid相同,说明之前有过同步,主节点会继续尝试使用部分复制(具体看offset和复制积压缓冲区的情况)
      • 若runid不同,说明主节点宕机并发生重新选举,断线前同步的redis节点不是当前主节点,只能进行全量复制

image.png

 

作者:彼岸舞

时间:202155

内容关于:Redis

本文属于作者原创,未经允许,禁止转发

原文地址:https://www.cnblogs.com/flower-dance/p/14731212.html