[021-15-002].并发能力问题的解决方案-搭建主从架构

我的后端学习大纲
我的Redis学习大纲


1.面试:请介绍下Redis的主从架构:

1.1.什么是主从复制

  • 1.单节点Redis的并发能力是有限的,要进一步提高并发能力,就可以使用主从模式,实现读写分离
  • 2.主从复制就是:主机数据更新后根据配置和策略, 自动同步到备机master/slaver机制,Master以写为主,Slave以读为主

1.2.主从复制可以干什么

  • 1.下图是一主三从的环境,实现了读写分离
  • 2.一主多从可以实现容灾的快速恢复,当一台从机挂掉,可以使用其他从机顶替
  • 3.上述架构,就会有一个疑问:就是只有一台主机,那假设这个主机挂掉,那岂不是凉了,能不能主机也是多台???答案是不可以,因为领导只能有一个,要不就领导互相打仗,有矛盾,所以不可以~!那怎么解决呢,可以使用集群的方式来解

2.Redis主从架构搭建

2.1.安装3台Redis:

  • 1.我们搭建的主从结构如图:为了省资源,这里就在一台机器上使用不同端口来搭建主从复制架构:
  • 2.共包含三个节点,一个主节点,两个从节点:这里我们会在同一台虚拟机中开启3个redis实例,模拟主从架构,信息如下:
IP PORT 角色
192.168.150.101 7001 master
192.168.150.101 7002 slave
192.168.150.101 7003 slave
  • 3.准备实例和配置:
    • 要在同一台虚拟机开启3个实例,必须准备三份不同的配置文件和目录,配置文件所在目录也就是工作目录。
  • 4.创建目录:我们创建三个文件夹,名字分别叫7001、7002、7003:
shell 复制代码
# 进入/tmp目录
cd /tmp
# 创建目录
mkdir 7001 7002 7003

如图:

  • 5.恢复原始配置:修改redis-6.2.4/redis.conf文件,将其中的持久化模式改为默认的RDB模式,AOF保持关闭状态(后面学习了主从同步原理后,就明白这里为何这么设置)
shell 复制代码
# 开启RDB
# save ""
save 3600 1
save 300 100
save 60 10000
# 关闭AOF
appendonly no
  • 6.拷贝配置文件到每个实例目录:然后将redis-6.2.4/redis.conf文件拷贝到三个目录中(在/tmp目录执行下列命令)
shell 复制代码
# 方式一:逐个拷贝
cp redis-6.2.4/redis.conf 7001
cp redis-6.2.4/redis.conf 7002
cp redis-6.2.4/redis.conf 7003
# 方式二:管道组合命令,一键拷贝
echo 7001 7002 7003 | xargs -t -n 1 cp redis-6.2.4/redis.conf
  • 7.修改每个实例的端口、工作目录:修改每个文件夹内的配置文件,将端口分别修改为7001、7002、7003,将rdb文件保存位置都修改为自己所在目录(在/tmp目录执行下列命令):
shell 复制代码
sed -i -e 's/6379/7001/g' -e 's/dir .\//dir \/tmp\/7001\//g' 7001/redis.conf
sed -i -e 's/6379/7002/g' -e 's/dir .\//dir \/tmp\/7002\//g' 7002/redis.conf
sed -i -e 's/6379/7003/g' -e 's/dir .\//dir \/tmp\/7003\//g' 7003/redis.conf
  • 8.修改每个实例的声明IP:虚拟机本身有多个IP,为了避免将来混乱,我们需要在redis.conf文件中指定每一个实例的绑定ip信息,格式如下:
shell 复制代码
# redis实例的声明 IP
replica-announce-ip 192.168.150.101
  • 9.因为每个目录都要改,我使用sed命令,进行快速更改,一键完成修改(在/tmp目录执行下列命令):
shell 复制代码
# 逐一执行
sed -i '1a replica-announce-ip 192.168.150.101' 7001/redis.conf
sed -i '1a replica-announce-ip 192.168.150.101' 7002/redis.conf
sed -i '1a replica-announce-ip 192.168.150.101' 7003/redis.conf
# 或者一键修改
printf '%s\n' 7001 7002 7003 | xargs -I{} -t sed -i '1a replica-announce-ip 192.168.150.101' {}/redis.conf
  • 10.启动:为了方便查看日志,我们打开3个ssh窗口,分别启动3个redis实例,启动命令:
shell 复制代码
# 第1个
redis-server 7001/redis.conf
# 第2个
redis-server 7002/redis.conf
# 第3个
redis-server 7003/redis.conf
  • 11.启动后,使用工具的Multily窗口形式来查看:

  • 12.如果要一键停止,可以运行下面命令:
shell 复制代码
printf '%s\n' 7001 7002 7003 | xargs -I{} -t redis-cli -p {} shutdown

2.2.开启主从关系:

  • 1.现在三个实例还没有任何关系,要配置主从可以使用replicaof 或者slaveof(5.0以前)命令,有临时和永久两种模式:
    • 方式1:修改配置文件(永久生效):在redis.conf配置文件中添加一行配置:slaveof <masterip> <masterport>
    • 方式2:使用redis-cli客户端连接到redis服务,执行slaveof命令(重启后失效):
  • 2.注意 :在5.0以后新增命令replicaof,与salveof效果一致。
    • 这里我们为了演示方便,使用方式二进行临时配置。
    • 通过redis-cli命令连接7002,执行下面命令:
shell 复制代码
# 连接 7002
redis-cli -p 7002
# 执行slaveof
slaveof 192.168.150.101 7001
  • 3.通过redis-cli命令连接7003,执行下面命令:
shell 复制代码
# 连接 7003
redis-cli -p 7003
# 执行slaveof
slaveof 192.168.150.101 7001
  • 4.然后连接 7001节点,查看集群状态:
sh 复制代码
# 连接 7001
redis-cli -p 7001
# 查看状态
info replication
  • 5.结果:

2.3.测试:

  • 1.执行下列操作以测试:
    • 利用redis-cli连接7001,执行set num 123
    • 利用redis-cli连接7002,执行get num,再执行set num 666
    • 利用redis-cli连接7003,执行get num,再执行set num 888
  • 2.可以发现,只有在7001这个master节点上可以执行写操作,7002和7003这两个slave节点只能执行读操作;

3.面试:主从复制的原理:

3.1.全量同步:

a.全量同步流程:

  • slave节点请求增量同步
  • master节点判断replid,发现不一致,拒绝增量同步,进行全量同步
  • master将完整内存数据生成RDB,发送RDB到slave
  • slave清空本地数据,加载master的RDB
  • master将RDB期间的命令记录在repl_baklog,并持续将log中的命令发送给slave
  • slave执行接收到的命令,保持与master之间的同步

b.全量同步解析图:

c.master如何得知salve是第一次来连接呢?

有几个概念,可以作为判断依据:

  • 1.全量复制:而slave服务在接收到数据库文件数据后,将其存盘并加载到内存中。
  • 2.增量复制:Master继续将新的所有收集到的修改命令依次传给slave,完成同步
  • 3.只要是重新连接master,一次完全同步(全量复制)将被自动执行
  • 4.Replication Id:简称replid,是数据集的标记,id一致则说明是同一数据集。每一个master都有唯一的replid,slave则会继承master节点的replid
  • 5.offset :偏移量,随着记录在repl_baklog中的数据增多而逐渐增大。slave完成同步时也会记录当前同步的offset。如果slave的offset小于master的offset,说明slave数据落后于master,需要更新。

是否全量同步判断过程:

  • 1.因此slave做数据同步,必须向master声明自己的replication id 和offset,master才可以判断到底需要同步哪些数据。
  • 2.因为slave原本也是一个master,有自己的replid和offset,当第一次变成slave,与master建立连接时,发送的replid和offset是自己的replid和offset
  • 3.master判断发现slave发送来的replid与自己的不一致,说明这是一个全新的slave,就知道要做全量同步了。
  • 4.master会将自己的replid和offset都发送给这个slave,slave保存这些信息。以后slave的replid就与master一致了。因此,master判断一个节点是否是第一次同步的依据,就是看replid是否一致

3.2.增量同步

a.增量同步的说明:

  • 1.全量同步需要先做RDB,然后将RDB文件通过网络传输个slave,成本太高了。因此除了第一次做全量同步,其它大多数时候slave与master都是做增量同步
  • 2.1.增量同步就是只更新slave与master存在差异的部分数据

b.增量同步流程:

  • 1.主从第一次同步是全量同步,但是如果slave重启后同步,就是执行增量同步了

c.master怎么知道slave与自己的数据差异:

  • 1.master要想知道slave与自己的数据差异在哪,这就要说到全量同步时的repl_baklog文件
  • 2.repl_baklog文件:这个文件是一个固定大小的数组,只不过数组是环形,也就是说角标到达数组末尾后,会再次从0开始读写,这样数组头部的数据就会被覆盖。
  • 3.repl_baklog中会记录Redis处理过的命令日志及offset,包括master当前的offset,和slave已经拷贝到的offset。
  • 4.slave与master的offset之间的差异,就是salve需要增量拷贝的数据了。随着不断有数据写入,master的offset逐渐变大,slave也不断的拷贝,追赶master的offset,一直到数组被填满:

  • 5.此时,如果有新的数据写入,就会覆盖数组中的旧数据。不过,旧的数据只要是绿色的,说明是已经被同步到slave的数据,即便被覆了也没什么影响。因为未同步的仅仅是红色部分。
  • 6.但是,如果slave出现网络阻塞,导致master的offset远远超过了slave的offset
  • 7.如果master继续写入新数据,其offset就会覆盖旧的数据,直到将slave现在的offset也覆盖:
  • 8.棕色框中的红色部分,就是尚未同步,但是却已经被覆盖的数据。此时如果slave恢复,需要同步,却发现自己的offset都没有了,无法完成增量同步了。只能做全量同步。

4.面试:主从架构中数据同步都可以进行哪些优化??

  • 1.主从同步可以保证主从数据的一致性,非常重要。可以从以下几个方面来优化Redis主从集群:
    • 在master中配置repl-diskless-sync yes启用无磁盘复制避免全量同步时的磁盘IO(磁盘慢,网络快的情况喜爱使用这个方式优化)
    • Redis单节点上的内存占用不要太大,减少RDB导致的过多磁盘IO
    • 适当提高repl_baklog的大小,发现slave宕机时尽快实现故障恢复,尽可能避免全量同步
    • 限制一个master上的slave节点数量,如果实在是太多slave,则可以采用主-从-从链式结构,减少master压力,即薪火相传模式架构,如下图所示

5.主从同步小结:

  • 1.简述全量同步和增量同步区别:
    • 全量同步:master将完整内存数据生成RDB,发送RDB到slave。后续命令则记录在repl_baklog,逐个发送给slave。
    • 增量同步:slave提交自己的offset到master,master获取repl_baklog中从offset之后的命令给slave
  • 2.什么时候执行全量同步?
    • slave节点第一次连接master节点时
    • slave节点断开时间太久,repl_baklog中的offset已经被覆盖时
  • 3.什么时候执行增量同步?
    • slave节点断开又恢复,并且在repl_baklog中能找到offset时

6.薪火相传模式:

  • 1.大哥带小弟,小弟下面还可以发展自己的小弟;
  • 2.上一个Slave可以是下一个slave的Master
  • 3.Slave同样可以接收其他 slaves的连接和同步请求,
  • 4.那么该slave作为了链条中下一个的master, 可以有效减轻master的写压力,去中心化降低风险
  • 5.用 slaveof <ip><port>
  • 6.中途变更转向:会清除之前的数据,重新建立拷贝最新的
  • 7.风险是一旦某个slave宕机,后面的slave都没法备份主机挂了,从机还是从机,无法写数据了
  • 8.主服务器挂掉后,从服务器还是从服务器,不会上位。永远是小弟

相关推荐
m0_748246613 分钟前
超详细:数据库的基本架构
数据库·架构
songbaoxian7 分钟前
ElasticSearch
java·linux·elasticsearch
非 白22 分钟前
【Java】代理模式
java·开发语言·代理模式
Good Note32 分钟前
Golang的静态强类型、编译型、并发型
java·数据库·redis·后端·mysql·面试·golang
我就是我3521 小时前
记录一次SpringMVC的406错误
java·后端·springmvc
向哆哆1 小时前
Java应用程序的跨平台性能优化研究
java·开发语言·性能优化
ekkcole2 小时前
windows使用命令解压jar包,替换里面的文件。并重新打包成jar包,解决Failed to get nested archive for entry
java·windows·jar
卑微的小鬼2 小时前
Go 语言结合 Redis 实现固定窗口、滑动窗口、令牌桶和漏桶限流算法的示例代码
开发语言·redis·golang
handsomestWei2 小时前
java实现多图合成mp4和视频附件下载
java·开发语言·音视频·wutool·图片合成视频·视频附件下载
全栈若城2 小时前
03 Python字符串与基础操作详解
java·开发语言·python