Redis的主从复制和哨兵

目录

主从复制

配置

查看主从结构信息

断开复制

拓扑

主从复制的基本流程

数据同步

实时复制

主从复制的缺点

哨兵(Sentinal)

Redis-Sential架构

使用docker搭建哨兵

哨兵作用演示

选举原理


如果某个服务器程序,只有一个节点(只搞一个物理服务器,来部署这个服务器程序),那如果这个机器挂了,就意味着服务中断了,同时一个节点的服务器性能/支持的并发量也是比较有限的。

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

Redis主要有以下几种部署模式:主从模式、主从+哨兵模式、集群模式。


主从复制

Redis 主从复制是一种数据同步机制,允许将一个 Redis 服务器(主节点)的数据复制到一个或多个 Redis 服务器(从节点)。主节点主要负责处理 操作,而从节点通过复制主节点的数据来提供服务。这种机制主要用于数据冗余、负载均衡和故障恢复。

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

注意 :主从模式,主要是针对于 操作进行并发量和可用性的提高。而操作的话,无论是可用性还是并发,都是非常依赖主节点的,主节点又不能搞多个(如果有多个主节点,会存在数据无法同步问题)

配置

配置redis主从结构,首先需要启动多个redis服务器。正常来说,每个redis服务器程序,应该在一个单独的主机上。(下面主要演示的是在一个主机上,运行多个redis服务器程序)

但是要注意,在一台主机上,运行多个redis服务器进程,需要保证多个redis-server的端口是不同的。(redis-server的默认端口是6379)。

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

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

下面来介绍。一主二从的结构,通过配置文件来设定端口号。( 主节点配置不用变,主需要修改从节点配置即可**)**

  1. 创建一个redis-conf目录,将主节点的配置文件复制两份到该目录下,并命名为slave1,conf、slave2.conf,并修改配置文件中的端口号。

  2. 同时将配置文件中的daemonize选项改成yes,表示让redis-server按后台方式运行

  1. 使用redis-server ./slave1.conf启动一个新的redis服务器进程(slave2.conf也是如此)。
  1. 但是此时三个redis节点直接还没有主从关系,互相独立,要想形成主从结构还需要进一步进行配置。要想配置成主从结构,就需要使用slaveof。(这里以6379端口为主节点)

a. 在配置文件中加入slaveof {masterHost} {masterPort}随redis启动生效。

b. 在redis-server启动命令时加入 --slaveof {masterHost} {masterPort}生效。

c. 直接使用redis命令:slaveof {masterHost} {masterPort}生效。

  1. 主从结构设置完成后,使用netstat -anp|grep redis查看连接情况。

如上图所示,前面三个连接为三个redis-server服务器程序的连接。后面四个连接,其实也就如上图所画,两两为一对,描述的是其中一个redis从节点,和主节点之间建立的tcp连接。

查看主从结构信息

使用redis命令info replication。

主节点信息:

  • offset:表示的是从节点和主节点之间,同步数据的进度。从节点和主节点之间的数据同步不是瞬间完成的。
  • lag:表示延迟的意思。主从节点之间通过网络通信,当前在同一主机上所以不太会存在延迟。
  • master_replid:相当于主节点的身份标识。
  • master_repl_offset:表示主机点的数据进度。
  • 最后四个选项表示挤积压缓冲区:支持部分同步机制的实现。本质上就是一个内存中的队列,会记录最近一段时间修改的数据。但是总量有限,所以随着时间的推移,会把之前旧的数据逐渐删除。

从节点信息:

connected_slave:连接的从节点的数量。说明从节点,还能继续连接从节点。

断开复制

slaveof命令不但可以建立复制,还可以在从节点执行slaveof no one来断开与主节点复制关系。

可以发现,从节点与主节点断开复制后,自己就变成主节点了(只是代表不在属于别人的从节点的意思,不是指变成了另外两个节点的主节点)。但是已经存在的数据,是不会抛弃的,不过后续原主节点针对数据做出的修改,从节点就无法再同步数据了。

注意:这里通过命令行的方式修改的主从结构是临时性的,如果重新启动了redis服务器,仍然会按照最初在配置文件中设置的内容来建立主从结构。

拓扑

redis的复制拓扑结构可以支持单层或多层复制关系,根据拓扑复杂性可以分为以下三种:一主一从、一主多从、树状主从结构。

一主一从结构

⼀主⼀从结构是最简单的复制拓扑结构,用于主节点出现宕机时从节点提供故障转移⽀持。

当应用写命令并发量较高且需要持久化时,可以只在从节点上开启AOF,这样既可以保证数据 安全性同时也避免了持久化对主节点的性能干扰。但是这种设定方式,有一个验严重的缺陷,主节点一旦挂了,不能让它自动重启,如果自动重启,此时没有AOF文件,就会丢失数据,进一步主从同步,就会把从节点的数据也给删除。所以需要让主节点从从节点这里获取到AOF文件后,再启动。

一主多从结构

⼀主多从结构(星形结构)使得应用端可以利用多个从节点实现读写分离。对于读比重较大的场景,可以把读命令负载均衡到不同的从节点上来分担压力。

但是这种结构随着从节点数量的增加,同步一条数据,就需要传输多次,对主节点的网络带宽压力还是比较大的。

树形主从结构

树形主从结构(分层结构)使得从节点不但可以复制主节点数据,同时可以作为其他从节点的主节点继续向下层复制(但是实际上仍是从节点,自身仍然是不能修改数据的)。这样的设定方式,就减少了主节点的网络带宽压力。

但是这种结构一旦数据进行修改了,同步延时的时间是比较长的。

主从复制的基本流程

1)保存主节点信息:保存主节点的ip和端口。

2)主从建立连接:建立TCP连接(三次握手),验证双方是否能正确读写数据。

3)发送ping命令:验证主节点是否能够正常工作。

4)权限验证:如果redis开启了密码,就会进行权限验证。

5)同步数据集:对于首次建立复制的场景,主节点会把当前持有的所有数据全部发送给从节点,这步操作耗时是最长的,分为两种情况:全量同步和部分同步。

6)命令持续复制:当从节点复制了主节点的所有数据之后,针对之后的修改命令,主节点会持续的把命令发送给从节点,从节点执行修改命令,保证主从数据的一致性。(实时复制)

数据同步

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

同步过程分为:全量复制和部分复制。

  • 全量复制:⼀般用于初次复制场景,Redis早期支持持的复制功能只有全量复制,它会把主节点全部数据⼀次性发送给从节点,当数据量较大时,会对主从节点和网络造成很大的开销。
  • 部分复制:用于处理在主从复制中因网络闪断等原因造成的数据丢失场景,当从节点再次连上主节点后,如果条件允许,主节点会补发数据给从节点。因为补发的数据远小于全量数据,可以有效避免全量复制的过高开销。

PSYNC的语法格式

复制代码
psync replicationid offset
  • 如果replicationid 设为?并且offset设为-1,此时就是在尝试进行全量复制.。
  • 如果replicationid offset 设为了具体的数值,则是尝试进行部分复制。由主节点自行判定,看当前是否方便给部分数据,如果不方便就只能全量复制了。

replicationid/replid(复制id)

主节点重新启动或者从节点晋级成主节点,都会生成这个id。同一个主节点,每次重启,生成的replicationid也会变化。

从节点和主节点建立连接之后,就会获取到主节点的replicationid。可以通过info replication命令查看这个id。

offset(偏移量)

主从节点都会维护自身复制偏移量。主节点在处理完写入命令后,会把命令字节长度做累加记录,统计信息在info replication中的master_repl_offset指标中。

从节点在接受到主节点发送的命令后,也会累加记录自身的偏移量,统计信息在info replication中的slave_repl_offset指标中。

同时从节点还会每秒上报自身的复制偏移量给主节点,主节点也会保存从节点的复制偏移量。

replid+offset共同标识了一个数据集。如果两节点的replid和offset都相同,那么这两个节点上持有的数据,就一定相同。

全量复制的流程

1)从节点发送psync命令给主节点进行数据同步,由于是第⼀次进行复制,从节点没有主节点的运行ID和复制偏移量,所以发送psync ? -1。

2)主节点根据命令,解析出要进行全量复制,回复+FULLRESYNC响应。

3)从节点接收主节点的运行信息进行保存,如replid。

4)主节点执行bgsave进行RDB文件的持久化。

5)主节点发送RDB文件给从节点,从节点保存RDB数据到本地硬盘。

6)主节点将从生成RDB到接收完成期间执行的写命令,写入缓冲区中,等从节点保存完RDB文件后,主节点再将缓冲区内的数据补发给从节点,补发的数据仍然按照RDB的⼆进制格式追加写入到收到的EDB文件中,保持主从⼀致性。

7)从节点清空自身原有旧数据。

8)从节点加载RDB文件得到与主节点⼀致的数据。

9)如果从节点加载RDB完成之后,并且开启了AOF持久化功能,它会进行bgrewrite操作,得到最近的AOF⽂件。

Redis从2.8.18版本开始支持无硬盘模式全量复制:主节点在执行RDB生成流程时,不会生成RDB文件保存在硬盘中,而事故直接把生成的RDB数据通过网络发送给从节点,这样就节省了一系列写硬盘和读硬盘的操作开销。

部分复制的流程

1)当主从节点之间出现网络中断时,如果超过repl-timeout时间,主节点会认为从节点故障并中断复制连接。

2)主从连接中断期间主节点依然响应命令,但这些复制命令都因网络中断无法及时发送给从节点,所以暂时将这些命令滞留在积压缓冲区中。

3)当主从节点网络恢复后,从节点再次连上主节点。

4)从节点将之前保存的replicationId和复制偏移量作为psync的参数发送给主节点,请求进行部分复制。

5)主节点接到psync请求后,进行必要的验证。如果从节点的进度已经超出积压缓冲区的范围了,就只能进行全量复制了。如果没有超出范围,就根据offset去复制积压缓冲区查找合适的数据,并响应+CONTINUE给从节点。

6)主节点将需要从节点同步的数据发送给从节点,最终完成⼀致性。

实时复制

主从节点在建立复制连接后,主节点会把自己收到的修改操作,通过tcp长连接的方式,源源不断的传输给从节点,从节点就会根据这些请求来同时修改自身的数据。从而保持和主节点数据的⼀致性.

在进行实时复制时,需要保证连接处于可用状态,这就需要通过心跳包机制来维护。

主节点:默认每隔10s给从节点发送一个ping命令,从节点收到就返回pong。判断从节点的存活性和连接状态。

从节点:默认每隔1s给主节点发送一个特定的请求,上报当前从节点复制数据的进度。

如果主节点发现从节点通信延迟超过repl-timeout配置的值(默认60秒),则判定从节点下线,断 开复制客户端连接。从节点恢复连接后,心跳机制继续进行。

主从复制的缺点

  • 从机多了,复制数据的延时非常明显。
  • 主机挂了,从机不能升级成主机,替换原来的主机,只能通过人工干预的方式恢复。(为了解决这个问题,就引入了哨兵模式)

哨兵(Sentinal)

哨兵机制是通过独立的进程来体现的,和之前的redis-server是不同的进程。

redis-sential不负责存储数据,只是对其他的redis-server进程起到监控的效果。通常哨兵节点,也会搞一个集合(多个哨兵节点构成)。

Redis-Sential架构

这三个哨兵进程会监控所有的master和slave。(监控:与这些进程建立tcp长连接,通过连接,定期发送心跳包,判断某个主机是否挂了)

针对主节点故障情况的处理流程

  1. 主节点故障,从节点同步连接中断,主从复制停止。
  2. 哨兵节点通过定期监控发现主节点出现故障。哨兵节点与其他哨兵节点进行协商,达成多数认同主节点故障的共识,防止出现误判。
  3. 如果主节点确实挂了,哨兵节点之间使用Raft算法选举出⼀个leader角色,由该节点负责后续的故障转移工作。
  4. 哨兵leader开始执行故障转移:从节点中选择⼀个作为新主节点,就会自动控制该节点执行slaveof no one让其变成主节点,并且控制其他节点,修改slaveof 的主节点ip port,连接上新的主节点。
  5. 最后告知客户端,让客户端能够连接新的主节点。

如果后续之前挂了的主节点,修复故障了,就可以作为一个新的从节点,连接到现在新的主节点上。

Redis-Sential的核心功能:

  • 监控:Sentinel节点会定期检测redis主从节点的工作状态。
  • 故障转移:实现从节点晋升为主节点并维护后续正确的主从关系。
  • 通知:Sentinel节点会将故障转移的结果通知给客户端。

注意:哨兵节点最高要搞奇数个,最少也应该是3个,和后续将到的选举leader有关。

使用docker搭建哨兵

  1. 使用docker获取到redis的镜像。

    docker pull redis:5.0.9

  2. 通过docker-compose进行容器编排(通过一个配置文件,把具体要创建哪些容器,以及每个容器运行的各种参数,描述清楚)。

a)编排redis主从节点配置文件。创建/redis/redis-data/docker-compose.yml。

version: '3.7'

services:

master: #服务的名字,自己设定

image: 'redis:5.0.9' #基于哪个镜像创建

container_name: redis-master

restart: always #异常情况是否自动重启

command: redis-server --appendonly yes #启动服务器时,用到哪些选项

ports: #端口映射,宿主机端口:容器内部端口

  • 6379:6379

slave1:

image: 'redis:5.0.9'

container_name: redis-slave1

restart: always

command: redis-server --appendonly yes --slaveof redis-master 6379 #docker会自动将容器名解析成ip

ports:

  • 6380:6379 #注意这里是三个容器,所以都使用6379端口不会有冲突

slave2:

image: 'redis:5.0.9'

container_name: redis-slave2

restart: always

command: redis-server --appendonly yes --slaveof redis-master 6379

ports:

  • 6381:6379

在创建docker-compose.yml的目录下启动所有容器。

复制代码
docker-compose up -d

查看运行日志

复制代码
docker-compose logs

b)编排redis哨兵节点配置文件。创建/redis/redis-sential/docker-compose.yml。

version: '3.7'

services:

sentinel1:

image: 'redis:5.0.9'

container_name: redis-sentinel-1

restart: always

command: redis-sentinel /etc/redis/sentinel.conf

volumes:

  • ./sentinel1.conf:/etc/redis/sentinel.conf #配置文件映射,前面是当前目录下创建的配置文件

ports:

  • 26379:26379

sentinel2:

image: 'redis:5.0.9'

container_name: redis-sentinel-2

restart: always

command: redis-sentinel /etc/redis/sentinel.conf

volumes:

  • ./sentinel2.conf:/etc/redis/sentinel.conf

ports:

  • 26380:26379

sentinel3:

image: 'redis:5.0.9'

container_name: redis-sentinel-3

restart: always

command: redis-sentinel /etc/redis/sentinel.conf

volumes:

  • ./sentinel3.conf:/etc/redis/sentinel.conf

ports:

  • 26381:26379

networks:

default:

external:

name: redis-data_default #让三个哨兵节点,加入到redis服务器的局域网中

slave1.conf、slave2.conf、slave3.conf的内容。

bind 0.0.0.0

port 26379

sentinel monitor redis-master redis-master 6379 2 #监控哪个服务器

sentinel down-after-milliseconds redis-master 1000

#参数解析

第一个redis-master:服务器名

第二个redis-master:ip,docker会自动进行域名解析。

6379:填宿主机端口号

2:法定票数。只有当达到该数量的哨兵节点都觉得该节点挂了,才算该节点真的挂了。

down-after-milliseconds:心跳包超时时间。

启动所有容器。

复制代码
docker-compose up -d

哨兵作用演示

手动将redis-master干掉。

复制代码
docker stop redis-master

观察哨兵日志。

可以看到哨兵发现主节点sdown,进一步由于主节点宕机得票达到3/2,达到法定得票,于是redis-master被判定为odown。

  • 主观下线(sdown):哨兵感知到主节点没心跳,判定为主观下线。
  • 客观下线(odown):多个哨兵达成一致意见,才能认为master确实下线。

接下来哨兵选举出来新的master,在上图中,新选出的主节点是172.18.0.3 6379。

redis-master重启之后。

复制代码
docker start redis-master

观察哨兵日志。可以看到刚才新启动的redis-master被当成了slave。

选举原理

哨兵leader的选举

选举哨兵的leader。这个选举的过程涉及到Raft算法。

观察日志,可以看到谁给谁投了票。

选举流程:

  1. 每个哨兵节点都给其他所有的哨兵节点,发起一个"拉票请求"。
  2. 收到拉票请求的节点,会回复一个"投票响应",响应结果有两种,投或不投。
  3. 一轮投票完成之后,发现得票超过盘数的节点,自动成为leader。(这也是为啥建议哨兵节点的数量设置成奇数个的原因。如果是偶数个,则增大了平票的概率,带来了不必要的开销)
  4. leader节点负责挑选一个slave称为新的master,当其他sential发现新的master出现,就说明选举结束了

leader挑选合适的slave成为新的master

挑选规则:

  1. 比较优先级,优先级高(数值小)的选中。优先级是配置文件中的配置项(slave-priority或者replica-priority)。
  2. 优先级相同的,比较replication offset谁复制的数据最多,谁选中。
  3. 上述都相同的,比较runid,谁小谁选中。

RunID在节点启动时自动随机生成的一串数字,并保持不变直到节点重启。用于区分集群中的不同节点。通过redis命令info server查看。

相关推荐
ego.iblacat2 小时前
Redis 核心概念与部署
数据库·redis·缓存
卢傢蕊3 小时前
NoSQL 之 Redis 配置与优化
redis·nosql
炸炸鱼.3 小时前
NoSQL 之 Redis 配置与优化
redis·nosql
J超会运3 小时前
Redis高效配置与优化指南
redis
苏渡苇3 小时前
5 分钟跑起 Redis(Docker 版)
数据库·redis·缓存·docker·redis入门
Jul1en_4 小时前
【Redis】Zset类型、命令及应用场景
数据库·redis·缓存
亚空间仓鼠5 小时前
NoSQL数据库Redis(一):数据库基础
数据库·redis·nosql
一只游鱼6 小时前
langchain4j+redis+持久化存储记忆
java·redis·langchain4j
亚空间仓鼠7 小时前
NoSQL数据库Redis(三):主从复制
redis·bootstrap·nosql