Redis分布式部署方式-主从复制

分布式部署Redis方式

分布式系统,涉及到一个非常关键的问题:单点问题

单点问题:如果某个服务器,只有一个节点(只搞一个物理服务器,来部署这个服务器程序),会遇到一些困难:

  1. 可用性问题,如果这个机器挂了,意味着服务就中断了
  2. 性能/支撑的并发量也是比较有限的

引入分布式系统,主要也就是为了解决上述的单点问题,在分布式系统中,往往希望有多个服务器来部署redis服务,从而构成一个redis集群,此时就可以让这个集群给整个分布式系统中其他的服务,提供更稳定。高效的数据存储功能

在分布式系统中,希望使用多个服务器来部署reids,往往存在以下几种redis的部署方式

  1. 主从模式
  2. 主从+哨兵模式
  3. 集群模式

主从复制能解决的问题

主从模式:在若干个redis节点中,有的是"主"节点,有的是"从"节点;假设有三个物理服务器(称为是三个节点),分别部署了一个redis-server进程;此时就可以把其中的一个节点,作为"主节点",另外两个节点作为"从节点";从节点,得听主节点的(从节点上的数据要跟随主节点变化:从节点的数据要和主节点保持一致)

本来,在主节点上保存一堆数据;引入从节点之后,就是要把主节点上面的数据,复制出来,放到从节点中,后续,主节点这边对于数据有任何修改,都会把这样的修改给同步到从节点上(从节点,就是主节点的副本)

Question:如果我改了从节点的数据,是否是把从节点的数据往主节点上同步呢?


Answer:Redis主从模式中,从节点的数据,不允许修改,只能读取数据!!!

由于从节点的数据都是时刻和主节点保持一致的,因此其他的客户端从从节点这里读取数据,和从主节点这里读取数据都是一样的;后续如果有客户端来读取数据,就可以从上述节点中,随机挑一个节点,给这个客户端提供读取数据的服务

之前只是一个单个redis服务器节点,此时机器挂了,整个redis就挂了;上述这个主从结构,这些redis服务器不太可能"同时挂了"

Question:

  1. 但是整个机房是否可能被一锅端了?
  2. 如果是挂了某个从节点?
  3. 如果是挂了主节点呢?
  4. 是否可以引入多个主节点呢?

Answer:

  1. 这个时候如果考虑到更多的可用性,就可以把这些机器放到多个不同的机房中(异地多活)
  2. 没啥影响,此时继续从主节点或者其他从节点读取数据,得到的效果完全一致
  3. 还是有一点影响,从节点只能读数据,如果需要写数据,就没得写了(可用性是提高了,但是还没到非常理想的程度)
  4. 一山不容二虎,听谁的是个麻烦事!!

更准确的说,主从模式,主要是针对"读操作",进行并发量&可用性的提高;而写操作的话,不论是可用性还是并发,都是非常依赖主节点,主节点又不能搞多个;实际业务场景中,读操作往往就是比写操作更频繁

主从结构,是分布式系统中比较经典的一种结构,不仅仅是redis,像MySQL等其他常用组件也常见的

如何启动多个redis-server

配置redis主从结构,首先需要启动多个redis服务器;正常来说,每个redis服务器程序,应该在一个单独的主机上(才是分布式)

可以在一个云服务器主机上,运行多个redis-server进程的,需要保证多个redis-server的端口是要不同的;本来redis-server默认的端口是6379,此时就不能让新启动的redis-server再继续使用6379了

Question:如何求指定redis-server的端口呢?


Answer:

  1. 可以在启动程序的时候,通过命令行来指定端口号 --port选项
  2. 也可以直接在配置文件中,来设定端口

此处准备搞一个主节点,两个从节点;主节点的配置不用变,只需要修改从节点的配置即可

bash 复制代码
redis-server  ./slave.conf 
bash 复制代码
redis-server  ./slave2.conf 

当前这几个节点并没有构成主从结构,而是各自为政,要想成为主从结构,还需要进一步的配置

bash 复制代码
redis-cli -p 6380

配置主从复制

有三种方法:

  • 在配置⽂件中加⼊ slaveof {masterHost} {masterPort} 随 Redis 启动⽣效
  • 在 redis-server 启动命令时加⼊ --slaveof {masterHost} {masterPort} ⽣效
  • 直接使⽤ redis 命令:slaveof {masterHost} {masterPort} ⽣效。

使用配置文件来配置主从结构(持久)!!

redis服务器配置文件需要重启才能生效

这种停止redis-server的方式,是和直接运行redis-server命令的方式搭配的

如果使用service redis-server start这种方式启动的,就必须使用service redis-server stop 来进行停止的;此时如果使用kill -9 的方式停止,kill掉之后,这个redis-server进程就能自动启动(服务器就是要稳定性和高可用,但是服务器上的某些程序,可能也难以避免出现挂了的情况,如果服务器进程挂了,要是能自动重启进程(把进程再启动起来),对于整体的服务不会产生严重影响,往往会有另外一个进程来专门监控指定的服务器进程的运行状态)

程序启动起来,并且还多了一些TCP连接(其中一个redis节点,和主节点之间的tcp连接,从节点启动之后就会和主节点建立tcp连接;主节点就相当于服务器,从节点就相当于客户端)

查看主从结构信息

主节点这边数据产生的任何修改,从节点就能立即感知到,就是刚才看到的这些tcp连接起到的效果;从节点不能写入数据

bash 复制代码
info replication
//查看主从信息

okffset:主节点会受到源源不断的"修改数据"的请求,从节点就需要从主节点这里同步这些修改请求,从节点和主节点之间的数据同步,不是瞬间完成的,offset就相当于主节点和从节点之间,同步数据的进度!

lag:延迟

master_replid:当从节点出现网络波动的情况时才会起作用

reol_backlog:积压缓冲区,支持部分同步机制的实现

slave_read_only:可以在配置文件中配置修改

断开主从结构和修改主从结构

断开复制 slaveof 命令不但可以建⽴复制,还可以在从节点执⾏ slaveof no one 来断开与主节点复制关系,直接使用这个命令(redis客户端)断开现有的主从复制连接

例如在 6380 节点上执⾏ slaveof no one 来断开复制。 断开复制主要流程

  1. 断开与主节点复制关系
  2. 从节点晋升为主节点

从节点断开复制后并不会抛弃原有数据,只是⽆法再获取主节点上的数据变化

通过 slaveof 命令还可以实现切主操作,将当前从节点的数据源切换到另⼀个主节点。执⾏ slaveof {newMasterIp} {newMasterPort} 命令即可。 切主操作主要流程

  1. 断开与旧主节点复制关系
  2. 与新主节点建⽴复制关系
  3. 删除从节点当前所有数据
  4. 从新主节点进⾏复制操作。

此时,6380看起来像是个主节点,实际上不是,仍然是从节点,只是作为6381同步数据的来源,自身仍然是不能修改数据的

通过slaveof是修改了主从结构,此处的修改时临时性的,如果重新启动redis服务器,仍然会按照配置文件中的内容重启服务器

主从复制时的安全,只读,传输延时

安全性

对于数据⽐较重要的节点,主节点会通过设置 requirepass 参数进⾏密码验证,这时所有的客⼾ 端访问必须使⽤ auth 命令实⾏校验。从节点与主节点的复制连接是通过⼀个特殊标识的客⼾端来完 成,因此需要配置从节点的masterauth 参数与主节点密码保持⼀致,这样从节点才可以正确地连接到 主节点并发起复制流程。

只读

默认情况下,从节点使⽤ slave-read-only=yes 配置为只读模式。由于复制只能从主节点到从节 点,对于从节点的任何修改主节点都⽆法感知,修改从节点会造成主从数据不⼀致。所以建议线上不要修改从节点的只读模式。

传输延迟

主从节点⼀般部署在不同机器上,复制时的⽹络延迟就成为需要考虑的问题,Redis 为我们提供 了 repl-disable-tcp-nodelay(这个选项可以用于在主从同步通信过程中,关闭tcp的nagle算法,从节点更快速的和主节点进行同步) 参数⽤于控制是否关闭 TCP_NODELAY,默认为 no,即开启 tcpnodelay 功能(TCP内部支持了nagle算法),说明如下

  • 当关闭时,主节点产⽣的命令数据⽆论⼤⼩都会及时地发送给从节点,这样主从之间延迟会变⼩, 但增加了⽹络带宽的消耗。适⽤于主从之间的⽹络环境良好的场景,如同机房部署(减少了tcp的传输延迟,增加了网络带宽)
  • 当开启时(默认开启),主节点会合并较⼩的 TCP 数据包从⽽节省带宽。默认发送时间间隔取决于 Linux 的内 核,⼀般默认为 40 毫秒。这种配置节省了带宽但增⼤主从之间的延迟。适⽤于主从⽹络环境复杂 的场景,如跨机房部署(增加tcp的传输延迟,节省了网络带宽)

nagle算法目的和tcp的捎带应答是一样的,针对小的tcp数据报,进行合并,减少了包的个数

主从复制的拓扑结构

拓扑结构:若干个节点之间,按照什么样的方式进行组织连接

⼀主⼀从拓扑

如果写数据请求太多,此时也是会给主节点造成一些压力,可以通过关闭主节点的AOF,只在从节点上开启AOF

但是这种设定方式,有一个缺陷:主节点一旦挂了,不能让他自动重启(如果自动重启,此时没有AOF文件,就会丢失数据,进一步的主从同步,会把从节点的数据也给删了)

改进方法:当主节点挂了之后,就需要让主节点从从节点这里获取到AOF文件,在启动

实际开发中,读请求远远超过写请求

⼀主多从结构

主节点上的数据发生改变,就会把改变的数据同时同步给所有的从节点;随着从节点个数的增加,同步一条数据,就需要传输多次(扁平化结构)

树形主从结构

主节点就不需要那么高的网卡带宽了,一旦数据进行修改了,同步的延时是比刚才更长的

主从复制的基本流程

  • 先保存主节点的IP和端口(变量)
  • 建立TCP连接(三次握手),验证的是 通信双方能否正确读写数据(系统层面)路是通的
  • 发送ping,收到pong,验证主节点能否正常工作(站在应用程序的角度)车能跑
  • redis主节点开启了密码
  • 复制数据最关键操作
  • 5.全量同步+6.增量同步

redis提供了psync命令,完成数据同步的过程,psync不需要咱们手动执行,redis服务器会在建立好主从同步关系之后,自动执行psync,从节点负责执行psync,从节点从主节点这边拉取数据

bash 复制代码
PSYNC replicationid offset

replicationid的作用

replication-复制,是主节点生成的,主节点启动的时候就会生成(从节点晋升成主节点的时候,也会生成),即使是同一个主节点,每次重启,生成的replicationid都是不同的,从节点和主节点建立了复制关系,就会从主节点这边获取到replication id;当前讨论的是一个主节点 多个从节点

bash 复制代码
info replication

获取到当前replication id 的值

一般情况下,replid2是用不上的,有一个主节点A(生成replid),还有一个从节点B(获取到A的relid),如果A和B通信过程中出现了一些网络抖动,B可能就会认为A挂了;B就会自己成为主节点(给自己生成replid),此时B也会记得之前旧的replid,就是通过replid2,后续网络稳定,B还可以根据replid2重新回到A的怀抱(需要手动干预,哨兵机制可以自动完成这个过程)

offset的作用

offset-偏移量,主节点和从节点都会维护偏移量(整数)

主节点的偏移量:主节点上会受到很多的修改操作的命令,每个命令都要占据几个字节,主节点会把这些修改命令,每个命令的字节数进行累加;

从节点的偏移量:描述了从节点这里的数据同步到了哪里;如果从节点和主节点的偏移量一致,说明已经赶上了!从节点(slave)每秒钟上报⾃⾝的复制偏移量给主节点,因此主节点也会保存从节点的复制偏移量

replid + offset 共同标识了⼀个 "数据集". 如果两个节点, 他们的 replid 和 offset 都相同, 则这两个节点上持有的数据, 就⼀定相同.

psync 运⾏流程

  1. 从节点发送 psync 命令给主节点,replid 和 offset 的默认值分别是 ? 和 -1
  2. 主节点根据 psync 参数和⾃⾝数据情况决定响应结果:
  • 如果回复 +FULLRESYNC replid offset,则从节点需要进⾏全量复制流程
  • 如果回复 +CONTINEU,从节点进⾏部分复制流程
  • 如果回复 -ERR,说明 Redis 主节点版本过低,不⽀持 psync 命令。从节点可以使⽤ sync 命令进⾏ 全量复制

  • psync ⼀般不需要⼿动执⾏. Redis 会在主从复制模式下⾃动调⽤执⾏
  • sync 会阻塞 redis server 处理其他请求. psync 则不会.

全量复制和部分复制

Question:

什么时候进行全量复制?

什么时候进行部分复制?


Answer:

  • 首次和主节点进行数据同步
  • 主节点不方便进行部分复制的时候

  • 从节点之前已经从主节点上复制过数据了,因为网络抖动或者从节点重启了
  • 从节点需要重新从主节点这边进行同步数据,此时看看能不能只同步一小部分(大部分数据都是一致的)

全量复制的流程

  1. 从节点发送 psync 命令给主节点进⾏数据同步,由于是第⼀次进⾏复制,从节点没有主节点的运 ⾏ ID 和复制偏移量,所以发送 psync ? -1
  2. 主节点根据命令,解析出要进⾏全量复制,回复 +FULLRESYNC 响应
  3. 从节点接收主节点的运⾏信息进⾏保存
  4. 主节点执⾏ bgsave 进⾏ RDB ⽂件的持久化,rdb文件是二进制格式的,比较省空间
  5. 主节点发送 RDB ⽂件给从节点,从节点保存 RDB 数据到本地硬盘,不能使用原有的rdb文件,而是必须要重新生成,已有的rdb文件可能会和当前的数据存在较大的差异,在主节点生成rdb文件和传输rdb文件的过程中,还会继续收到很多新的修改操作,新修改的数据,也必须要同步给从节点
  6. 主节点将从⽣成 RDB 到接收完成期间执⾏的写命令,写⼊缓冲区中,等从节点保存完 RDB ⽂件 后,主节点再将缓冲区内的数据补发给从节点,补发的数据仍然按照 rdb 的⼆进制格式追加写⼊到收 到的 rdb ⽂件中. 保持主从⼀致性
  7. 从节点清空⾃⾝原有旧数据
  8. 从节点加载 RDB ⽂件得到与主节点⼀致的数据
  9. 如果从节点加载 RDB 完成之后,并且开启了 AOF 持久化功能,它会进⾏ bgrewrite 操作,得到最近的 AOF ⽂件,产生很多AOF日志,由于当前收到的是大批量的数据,会有冗余数据,所以进行bgrewrite操作

全量复制的无硬盘模式

主节点,进行全量复制的时候,也支持"无硬盘模式",主节点生成的rdb文件的二进制数据,不是保存到文件中,而是直接网络传输了(省下了一系列读硬盘和写硬盘的操作),从节点之前也是把收到的rdb数据,写入到硬盘中,然后再加载,现在也可以省略这个过程,直接把收到的数据进行加载了

即使引入了无硬盘模式,仍然这个操作是比较重量,比较耗时的,网络传输(大规模数据->全量复制)是没法省的,相比于网络传输来说,读写硬盘是小头

有磁盘复制 vs ⽆磁盘复制(diskless) 默认情况下, 进⾏全量复制需要主节点⽣成 RDB ⽂件到主节点的磁盘中, 再把磁盘上的 RDB ⽂件通过发送给从节点. Redis 从 2.8.18 版本开始⽀持⽆磁盘复制. 主节点在执⾏ RDB ⽣成流程时, 不会⽣成 RDB ⽂ 件到磁盘中了, ⽽是直接把⽣成的 RDB 数据通过⽹络发送给从节点. 这样就节省了⼀系列的写 硬盘和读硬盘的操作开销

关于runid和replid

一个redis服务器上,replication id 和run id是都存在的,两个不同的id,看起来非常像

长度相同,格式也非常相似

run id是每个节点都不相同的,replid则是具有主从关系的节点

官方文档,明确表示,psync使用的是replicationid

runid是标识一次redis的"运行",和主从复制没有什么关系,和哨兵有关系

replid和主从复制有关系,在主从复制中起作用的

replid+offset共同标识了一个数据集合!!!

部分复制的流程

出现网络抖动,主节点最近修改的数据可能无法及时同步过来,更严重的,从节点已经感知不到主节点了(从节点可能会晋升主节点),网络抖动,一般都是"暂时的",此时就可以让主节点和从节点重新建立联系;当主节点和从节点重新建立连接之后,就需要进行数据的同步

psync带有具体的replid和offset值,主节点就要根据psync的参数进行判定,当前这次是按照全量复制合适还是按照部分复制合适

  1. 当主从节点之间出现⽹络中断时,如果超过 repl-timeout 时间,主节点会认为从节点故障并终端 复制连接
  2. 主从连接中断期间主节点依然响应命令,但这些复制命令都因⽹络中断⽆法及时发送给从节点,所 以暂时将这些命令滞留在复制积压缓冲区中
  3. 当主从节点⽹络恢复后,从节点再次连上主节点
  4. 从节点将之前保存的 replicationId (描述数据的来源,如果replicationid不一样,说明这个从节点就是专捅义父,需要全量复制)和 复制偏移量(数据的复制的进度,从节点之前同步数据的进度,主节点就看这个进度是否在当前的积压缓冲区之内,如果确实是在积压缓冲区之内,此时就可以直接进行部分复制,就只把最近的数据同步过去即可)作为 psync 的参数发送给主节点,请求进⾏部分 复制
  5. 主节点接到 psync 请求后,进⾏必要的验证。随后根据 offset 去复制积压缓冲区查找合适的数据, 并响应 +CONTINUE 给从节点
  6. 主节点将需要从节点同步的数据发送给从节点,最终完成⼀致性。

复制积压缓冲区 复制积压缓冲区是保存在主节点上的⼀个固定⻓度的队列,默认⼤⼩为 1MB,当主节点有连接的从节 点(slave)时被创建,这时主节点(master)响应写命令时,不但会把命令发送给从节点,还会写⼊ 复制积压缓冲区,如图所⽰。

由于缓冲区本质上是先进先出的定⻓队列,所以能实现保存最近已复制数据的功能,⽤于部分复制和 复制命令丢失的数据补救。复制缓冲区相关统计信息可以通过主节点的 info replication 中:

bash 复制代码
127.0.0.1:6379> info replication
# Replication
role:master
...
repl_backlog_active:1 // 开启复制缓冲区
repl_backlog_size:1048576 // 缓冲区最⼤⻓度
repl_backlog_first_byte_offset:7479 // 起始偏移量,计算当前缓冲区可⽤范围
repl_backlog_histlen:1048576 // 已保存数据的有效⻓度

根据统计指标,可算出复制积压缓冲区内的可⽤偏移量范围:[repl_backlog_first_byte_offset, repl_backlog_first_byte_offset + repl_backlog_histlen]

这个相当于⼀个基于数组实现的环形队列. 上述区间中的值就是 "数组下标" .

如果当前从节点需要的数据, 已经超出了主节点的积压缓冲区的范围, 则⽆法进⾏部分复制, 只 能全量复制了.

实时复制的流程

  • 全量复制:从节点刚连上主节点之后,进行的数据初始化工作
  • 部分复制:全量复制的特殊情况,优化手段,目的和全量复制一样
  • 实时复制:从节点,已经和主节点,同步好数据了(从节点这一时刻已经和主节点数据一致了),但是之后,主节点这边会源源不断的收到新的修改数据的请求,主节点上的数据也会随之改变,也需要能够同步给从节点
  • 从节点和主节点之间会建立TCP的长连接,然后主节点会把自己受到的修改数据的请求,通过上述连接发给从节点,从节点再根据这些修改请求,修改内存中的数据,这个过程也是需要时间的,正常来说是比较短的,但是如果是树形结构(级别很多),延时也就变大了
  • 在进行实时复制的时候,需要保证连接处于可用状态--心跳包机制,主节点默认每10s给从节点发送一个ping命令,从节点收到就返回pong;从节点默认每隔1s就给主节点发起一个特点的请求,就会上报当前从节点复制的进度(offset)
  • 如果没有收到pong,有一个阈值(60s),就会认为从节点有问题,判定从节点下线
  • 这些时间都是可以修改的!

小结

主从复制解决的问题:单点问题

  1. 单个 redis 节点, 可⽤性不⾼.
  2. 单个 redis 节点, 性能有限

主从复制的特点:

  1. Redis 通过复制功能实现主节点的多个副本
  2. 主节点⽤来写, 从节点⽤来读. 这样做可以降低主节点的访问压⼒
  3. 复制⽀持多种拓扑结构,可以在适当的场景选择合适的拓扑结构
  4. 复制分为全量复制, 部分复制和实时复制
  5. 主从节点之间通过⼼跳机制保证主从节点通信正常和数据⼀致性。

主从复制配置的过程:

  1. 主节点配置不需要改动
  2. 从节点在配置⽂件中加⼊ slaveof 主节点ip 主节点端⼝ 的形式即可

主从复制的缺点

  1. 从机多了, 复制数据的延时⾮常明显
  2. 主机挂了, 从机不会升级成主机. 只能通过⼈⼯⼲预的⽅式恢复.

问题补充-关于从节点何时晋升成主节点的问题

从节点和主节点之间断开连接,有两种情况

  • 从节点主动和主节点断开连接
bash 复制代码
slaveof no one

这个时候,从节点就能够晋升成主节点;意味着我们要主动修改redis的组成结构(拓扑结构)

  • 主节点挂了

这个时候,从节点不会晋升成主节点,必须通过人工干预的方式,恢复主节点,这个是脱离我们掌控的(哨兵机制)

问题补充-关于redis主节点无法重启的问题

这里有AOF文件,这个文件是redis服务器启动的时候,需要去加载的,当前这三个redis-server用的是同一个AOF文件,本身不太科学

之前最开始创建从节点的配置文件没有改日志,就导致生成AOF文件的路径/文件名是同一个

通过service redis-server start启动的服务器是通过一个redis这样的用户,来启动的(所属的用户是redis用户)主要是怕,通过root启动的redis,权限太高,一旦redis被黑客攻破了,后果就会比较严重

redis-server需要按照可读可写的方式打开这个AOF文件,而这个文件对于root之外的用户只有读权限;因此,service redis-server start启动的redis服务器无法打开这个文件,就启动失败了

解决方案:把三个redis服务器生成的文件,也给区分开,更靠谱的是,直接把三个redis服务器的工作目录区分开(修改配置文件中的dir选项)

  • 停止之前的redis服务器
  • 删除之前工作目录下已经生成的AOF文件,或者也可以通过chown命令修改AOF文件所属目录
  • 给从节点创建出新的目录用来作为从节点的工作目录,并且修改从节点的配置文件,设定成新的目录为工作目录
  • 启动redis服务器

这就是主从复制啦!!

相关推荐
月光水岸New2 小时前
Ubuntu 中建的mysql数据库使用Navicat for MySQL连接不上
数据库·mysql·ubuntu
狄加山6752 小时前
数据库基础1
数据库
我爱松子鱼2 小时前
mysql之规则优化器RBO
数据库·mysql
chengooooooo2 小时前
苍穹外卖day8 地址上传 用户下单 订单支付
java·服务器·数据库
Rverdoser3 小时前
【SQL】多表查询案例
数据库·sql
Galeoto3 小时前
how to export a table in sqlite, and import into another
数据库·sqlite
希忘auto4 小时前
详解Redis在Centos上的安装
redis·centos
人间打气筒(Ada)4 小时前
MySQL主从架构
服务器·数据库·mysql
leegong231114 小时前
学习PostgreSQL专家认证
数据库·学习·postgresql
喝醉酒的小白4 小时前
PostgreSQL:更新字段慢
数据库·postgresql