Redis持久化和集群架构

目录

Redis持久化

RDB快照(snapshot)

RDB优点

RDB缺点

RDB的触发机制

AOF持久化

AOF文件重写

AOF触发机制

混合模式

Redis主从架构

Redis哨兵高可用架构

[Redis Cluster架构](#Redis Cluster架构)

槽位定位算法

跳转重定位

Redis集群节点间的通信机制


Redis持久化

RDB快照(snapshot)

RDB持久化是指在指定的时间间隔内将内存中的数据集快照写入磁盘。也是4.0之前默认的持久化方式,这种方式是就是将内存中数据以快照的方式写入到二进制文件中,默认的文件名为dump.rdb。

RDB优点
  1. RDB文件紧凑,全量备份,非常适合用于进行备份和灾难恢复。

  2. 生成RDB文件的时候,redis主进程会fork()一个子进程来处理所有保存工作,主进程不需要进行任何磁盘IO操作。

  3. RDB 在恢复大数据集时的速度比AOF的恢复速度要快。

RDB缺点
  1. RDB快照是一次全量备份,存储的是内存数据的二进制序列化形式,存储上非常紧凑。

  2. 当进行快照持久化时,会开启一个子进程专门负责快照持久化,子进程会拥有父进程的内存数据,父进程修改内存子进程不会反应出来,所以在快照持久化期间修改的数据不会被保存,可能丢失数据。

RDB的触发机制

RDB持久化的触发机制有三种:save、bgsave、自动化

save

该命令会阻塞当前Redis服务器,执行save命令期间,Redis不能处理其他命令,直到RDB过程完成为止。具体流程:执行完成时候如果存在老的RDB文件,就把新的替代掉旧的。当客户端数量较多时,这种方式不可取。

bgsave

执行该命令时,Redis会在后台异步进行快照操作,快照同时还可以响应客户端请求。具体流程:在Redis进程执行fork操作创建子进程,RDB持久化过程由子进程负责,完成后自动结束。阻塞只发生在fork阶段,一般时间很短。基本上Redis内部所有的RDB操作都是采用bgsave命令。

自动触发

在配置中集中配置 save m n 的方式,表示 m秒内数据集存在n次修改时,系统自动触bgsave操作。


AOF持久化

全量备份总是耗时的,有时候我们提供一种更加高效的方式AOF,工作机制很简单,redis会将每一个收到的写命令都通过write函数追加到文件中。通俗的理解就是日志记录。然后在服务重启以后,会执行这些命令来恢复数据。

AOF文件重写

AOF的方式也同时带来了另一个问题。持久化文件会变的越来越大。为了压缩AOF的持久化文件。redis提供了bgrewriteaof命令。将内存中的数据以命令的方式保存到临时文件中,同时会fork出一条新进程来将文件重写。AOF文件重写就是把 Redis 进程内的数据转化为写命令,然后同步到新的AOF文件中。在重写的过程中,Redis 服务器会创建一个新的AOF文件来替代现有的AOF 文件,新、旧两个AOF文件所保存的数据库状态相同,但是新的AOF文件不会包含冗余命令。

AOF触发机制

appendfsync always:每次收到写命令就立即强制写入磁盘

appendfsync everysec:每秒钟强制写入磁盘一次,在性能和持久化方面做平衡,推荐该方式。

appendfsync no:完全依赖OS的写入,一般为30秒左右一次,性能最好但是持久化最没有保证,不推荐。


混合模式

重启Redis时,我们很少使用RDB来恢复内存状态,因为会丢失大量数据。我们通常使用AOF日志重放,但是重放AOF日志性能相对 RDB来说要慢很多,这样在Redis实例很大的情况下,启动需要花费很长的时间。 Redis 4.0 为了解决这个问题,带来了一个新的持久化选项混合持久化。

通过如下配置可以开启混合持久化(必须先开启aof)

# aof-use-rdb-preamble yes   

如果开启了混合持久化,AOF在重写时,不再是单纯将内存数据转换为RESP命令写入AOF文件,而是将重写这一刻之前的内存做RDB快照处理,并且将RDB快照内容和增量的AOF修改内存数据的命令存在一起,都写入新的AOF文件,新的文件一开始不叫appendonly.aof,等到重写完新的AOF文件才会进行改名,覆盖原有的AOF文件,完成新旧两个AOF文件的替换。

混合持久化AOF文件结构如下


Redis主从架构

如果你为master配置了一个slave,不管这个slave是否是第一次连接上Master,它都会发送一个PSYNC命令给master请求复制数据。

master收到PSYNC命令后,会在后台进行数据持久化通过bgsave生成最新的rdb快照文件,持久化期间,master会继续接收客户端的请求,它会把这些可能修改数据集的请求缓存在内存中。当持久化进行完毕以后,master会把这份rdb文件数据集发送给slave,slave会把接收到的数据进行持久化生成rdb,然后再加载到内存中。然后,master再将之前缓存在内存中的命令发送给slave。

当master与slave之间的连接由于某些原因而断开时,slave能够自动重连Master,如果master收到了多个slave并发连接请求,它只会进行一次持久化,而不是一个连接一次,然后再把这一份持久化的数据发送给多个并发连接的slave。

主从复制(全量复制)流程图

数据部分复制

当master和slave断开重连后,一般都会对整份数据进行复制。但从redis2.8版本开始,redis改用可以支持部分数据复制的命令PSYNC去master同步数据,slave与master能够在网络连接断开重连后只进行部分数据复制(断点续传)。

master会在其内存中创建一个复制数据用的缓存队列,缓存最近一段时间的数据,master和它所有的slave都维护了复制的数据下标offset和master的进程id,因此,当网络连接断开后,slave会请求master继续进行未完成的复制,从所记录的数据下标开始。如果master进程id变化了,或者从节点数据下标offset太旧,已经不在master的缓存队列里了,那么将会进行一次全量数据的复制。

主从复制(部分复制,断点续传)流程图

Redis哨兵高可用架构

sentinel哨兵是特殊的redis服务,不提供读写服务,主要用来监控redis实例节点。

哨兵架构下client端第一次从哨兵找出redis的主节点,后续就直接访问redis的主节点,不会每次都通过sentinel代理访问redis的主节点,当redis的主节点发生变化,哨兵会第一时间感知到,并且将新的redis主节点通知给client端(这里面redis的client端一般都实现了订阅功能,订阅sentinel发布的节点变动消息)

Redis Cluster架构

Redis Cluster 将所有数据划分为16384个slots(槽位),每个节点负责其中一部分槽位。槽位的信息存储于每个节点中。 当 Redis Cluster 的客户端来连接集群时,它也会得到一份集群的槽位配置信息并将其缓存在客户端本地。这样当客户端要查找某个key时,可以直接定位到目标节点。同时因为槽位的信息可能会存在客户端与服务器不一致的情况,还需要纠正机制来实现槽位信息的校验调整。

槽位定位算法

Cluster 默认会对 key 值使用 crc16 算法进行 hash 得到一个整数值,然后用这个整数值对 16384 进行取模 来得到具体槽位。 HASH_SLOT = CRC16(key) mod 16384

跳转重定位

当客户端向一个错误的节点发出了指令,该节点会发现指令的 key 所在的槽位并不归自己管理,这时它会向客户端发送一个特殊的跳转指令携带目标操作的节点地址,告诉客户端去连这个节点去获取数据。客户端收到指令后除了跳转到正确的节点上去操作,还会同步更新纠正本地的槽位映射表缓存,后续所有key将使用新的槽位映射表。

Redis集群节点间的通信机制

redis cluster节点间采取gossip协议进行通信,维护集群的元数据(集群节点信息,主从角色,节点数量,各节点共享的数据等)有两种方式:集中式和gossip

集中式

优点在于元数据的更新和读取,时效性非常好,一旦元数据出现变更立即就会更新到集中式的存储中,其他节点读取的时候立即就可以立即感知到;不足在于所有的元数据的更新压力全部集中在一个地方,可能导致元数据的存储压力。 很多中间件都会借助zookeeper集中式存储元数据。

Gossip

gossip协议是一种去中心化、随机化的节点通信协议,用于在分布式系统中传播信息。gossip协议包含多种消息,包括ping,pong,meet,fail等等。

meet:某个节点发送meet给新加入的节点,让新节点加入集群中,然后新节点就会开始与其他节点进行通 信;

ping:每个节点都会频繁给其他节点发送ping,其中包含自己的状态还有自己维护的集群元数据,互相通过 ping交换元数据(类似自己感知到的集群节点增加和移除,hash slot信息等);

pong: 对ping和meet消息的返回,包含自己的状态和其他信息,也可以用于信息广播和更新;

fail: 某个节点判断另一个节点fail之后,就发送fail给其他节点,通知其他节点,指定的节点宕机了。

gossip协议的优点在于元数据的更新比较分散,不是集中在一个地方,更新请求会陆陆续续,打到所有节点上 去更新,有一定的延时,降低了压力;缺点在于元数据更新有延时可能导致集群的一些操作会有一些滞后。

gossip的通信端口

每个节点都有一个专门用于节点间gossip通信的端口,就是自己提供服务的端口号+10000,比如7001,那么 用于节点间通信的就是17001端口。 每个节点每隔一段时间都会往另外几个节点发送ping消息,同时其他几 点接收到ping消息之后返回pong消息。

相关推荐
drebander1 分钟前
使用 Java Stream 优雅实现List 转化为Map<key,Map<key,value>>
java·python·list
乌啼霜满天2495 分钟前
Spring 与 Spring MVC 与 Spring Boot三者之间的区别与联系
java·spring boot·spring·mvc
tangliang_cn10 分钟前
java入门 自定义springboot starter
java·开发语言·spring boot
程序猿阿伟11 分钟前
《智能指针频繁创建销毁:程序性能的“隐形杀手”》
java·开发语言·前端
javaDocker17 分钟前
业务架构、数据架构、应用架构和技术架构
架构
Grey_fantasy20 分钟前
高级编程之结构化代码
java·spring boot·spring cloud
新知图书22 分钟前
Rust编程与项目实战-模块std::thread(之一)
开发语言·后端·rust
弗锐土豆27 分钟前
工业生产安全-安全帽第二篇-用java语言看看opencv实现的目标检测使用过程
java·opencv·安全·检测·面部
Elaine20239128 分钟前
零碎04 MybatisPlus自定义模版生成代码
java·spring·mybatis
盛夏绽放43 分钟前
Node.js 和 Socket.IO 实现实时通信
前端·后端·websocket·node.js