Redis 双主实现

2024-06-02 13:58
文章标签 实现 redis 双主

本文主要是介绍Redis 双主实现,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

redis双主设计

背景

目前redis仅支持主从复制模式,可以支持在线备份、读写分离等功能,实际应用中通常通过sentinel服务做主从切换的管理,这增加了管理的复杂度和维护成本,基于此360基础架构组联合DBA从redis内部实现了双主功能。

主从复制介绍

redis支持树形的主从异步复制,并具有非阻塞、部分同步等特性,下面简单介绍下其实现原理以及目前redis主从复制模式在故障发生时的数据丢失情况。

实现原理

数据同步

slave开始连接到master时需要同步master已有的数据,具体过程如下图所示,主要有以下几个步骤:

  1. slave向master发送PSYNC命令,将缓存的master的runid和reploff发送给master。

  2. master根据slave发送的reploff判断需要开始同步的数据是否在当前缓冲区(积压空间)中,如果在的话完成和slave的连接建立并向slave发送CONTINUE回复标志,开始发送积压空间中的数据;否则,向slave发送FULLSYNC标志并开启子进程dump当前时刻的快照数据到本地rdb文件。

  3. slave接收psync命令的返回值,并判断是CONTINUE还是FULLSYNC,如果是CONTINUE则完成连接过程准备接收master数据;否则,触发接收master dump的rdb文件事件,等待master发送rdb文件。

  4. master将快照数据dump到本地文件后,向slave发送rdb文件

  5. slave接收完master发送的rdb文件后,清空本地库并重新加载接收的rdb文件,由于这时的数据变化较大,如果开启了aof选项则还需进行aof rewrite操作

  6. 开始传播master积压空间中的新数据。

数据传播

master实例会维护其slave实例列表,当有更改操作发生时,其会通过连接建立时创建的socket向所有slave实例发送操作命令进行数据传播,同时为了防止故障恢复slave重新连接master时每次都进行全量同步,master实例会内部维护一个缓冲区(积压空间)来缓存部分slave命令,master数据传播的具体过程为:

  1. 写入本地库

  2. 写入积压空间

  3. 触发写入slave实例事件,进行异步传播;如果此刻正在进行数据同步操作则将命令写入缓冲区,待同步操作完成后再触发向slave实例写入事件。

数据丢失

redis主从模式并不能保证数据的100%完整,在网络故障、主库宕机等情况下提升slave为master时可能会丢失部分数据,如下图所示,假如在某个时刻master的数据还未完全传播给slave时,master宕机等情况发生并将slave提升为master,这时原来master未传播的一部分数据将丢失。

双主复制设计

前提假设

由于时间、精力等因素,目前我们在进行双主设计时结合如下实际项目需求进行了一些设计折衷,后续我们会继续完善相关设计。

  • 上层保证某个时间点只有一个master在写

  • 故障时允许丢失少量数据

总体设计

为避免额外维护成本,双主模块完全在redis内部实现,双主两个实例各自创建一个socket进行彼此通信;加入双主复制后不会影响原有的主从复制模式,但如下图所示,主从复制实例可以通过我们新增的doublemasterof命令转化为双主复制,双主复制实例也可以通过原有的slaveof命令转换为主从复制实例。

同步策略

redis双主实例网络故障恢复或重启等情况下会进行重新连接以同步彼此数据,主从模式下同步策略很简单,只需要从库同步主库数据即可,而双主模式下我们必须根据一定的策略来选出一个实例作为数据同步的对象,我们考虑到两种具体同步策略:基于数据量和基于时间戳的同步策略。

数据量同步策略

基于数据量的同步策略可以理解为数据量少的实例去同步数据量多的实例,这种同步策略在故障发生时数据已经全部传播到另外一个实例的情况下,故障恢复后可以保证数据完整性,但如下图所示,假如原来操作在双主A上执行,某一时刻双主A上的操作还未同步到双主B上发生了网络故障,上层会切到B上继续写入,当写入了图中红色所示大小的数据后网络故障恢复,这时进行数据同步时就有可能丢失A或B上的部分数据。

时间戳同步策略

对于基于时间戳的同步策略,我们会在redis内部维护双主实例的最近更新时间戳,故障恢复进行数据同步时时间戳较旧的实例会同步时间戳较新的实例;和基于数据量同步策略一样当故障发生时如果数据已经全部传播到另外实例则故障恢复后可以保证数据完整性,否则,如下图所示故障恢复后将丢失双主A实例的部分数据。

我们的选择

根据业务需求,我们需要保证最新写入的数据不会丢失,所以具体实现上我们选择了基于时间戳的同步策略。

同步实现

我们在redis原有的全同步,部分同步的基础上增加了ignore resync策略以实现双主同步,具体实现如下图所示,有以下几个步骤:

  1. 双主实例A链接到另外一个实例B时会通过发送2mastersync命令,该命令会将A实例最后的更新时间戳发送给B

  2. B实例判断A的最后更新时间戳是否比自己新,如果比自己新则直接将A标示为ONLINE并向A发送IGNORE runid reploff信息,A接收到IGNORE信息后记录下runid reploff,即可完成与B的同步;否则,则按照主从同步方式进行全同步或部分同步。

数据传播

对一个双主实例的更改操作,redis内部会通过双主实例建立连接时创建的socket异步传播给另一个双主实例,这里要解决的问题是要避免数据再次传播回来,具体实现上我们通过双主实例的runid进行判断,每个双主实例内部会维护其另外一个实例的runid信息,当有更改命令要执行时,我们会通过runid来判断该命令是否是其双主实例传播过来的,如果是将不再回传。

复制偏移量维护

redis主从实现机制上,当通信模块接收到主库的更改命令时会直接在从库上增加其复制偏移量来记录数据同步的位置,而对于双主实例我们知道为避免数据循环传播,双主实例A传播给双主实例B的命令不会回传过来,那么该如何维护其复制偏移量呢?设计上我们考虑了两种策略:

策略一

如下图所示,双主A向双主B传播一条数据后,B会回复A一个ACK length确认,A接收到确认信息后将自己的复制偏移量增加length。

策略二

如下图所示,双主A再向B传播数据之前自己主动增加复制偏移量,双主B不会向双主A回复确认信息

策略一对比策略二进一步保证了数据的完整性,但同时带来了一定的网络开销,两种策略都不能完全保证复制偏移量再网路故障下的正确性(策略一在ACK丢失的情况下无法保证复制偏移量正确),结合目前的需求为了不影响性能我们选择了策略二。

小结

结合目前项目的需求我们在redis内部实现了双主功能,但是也有一些需要改进的地方,欢迎大家提出意见,后面我们会不断完善,敬请关注!

这篇关于Redis 双主实现的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1024162

相关文章

使用Java解析JSON数据并提取特定字段的实现步骤(以提取mailNo为例)

《使用Java解析JSON数据并提取特定字段的实现步骤(以提取mailNo为例)》在现代软件开发中,处理JSON数据是一项非常常见的任务,无论是从API接口获取数据,还是将数据存储为JSON格式,解析... 目录1. 背景介绍1.1 jsON简介1.2 实际案例2. 准备工作2.1 环境搭建2.1.1 添加

Java实现任务管理器性能网络监控数据的方法详解

《Java实现任务管理器性能网络监控数据的方法详解》在现代操作系统中,任务管理器是一个非常重要的工具,用于监控和管理计算机的运行状态,包括CPU使用率、内存占用等,对于开发者和系统管理员来说,了解这些... 目录引言一、背景知识二、准备工作1. Maven依赖2. Gradle依赖三、代码实现四、代码详解五

Redis连接失败:客户端IP不在白名单中的问题分析与解决方案

《Redis连接失败:客户端IP不在白名单中的问题分析与解决方案》在现代分布式系统中,Redis作为一种高性能的内存数据库,被广泛应用于缓存、消息队列、会话存储等场景,然而,在实际使用过程中,我们可能... 目录一、问题背景二、错误分析1. 错误信息解读2. 根本原因三、解决方案1. 将客户端IP添加到Re

java如何分布式锁实现和选型

《java如何分布式锁实现和选型》文章介绍了分布式锁的重要性以及在分布式系统中常见的问题和需求,它详细阐述了如何使用分布式锁来确保数据的一致性和系统的高可用性,文章还提供了基于数据库、Redis和Zo... 目录引言:分布式锁的重要性与分布式系统中的常见问题和需求分布式锁的重要性分布式系统中常见的问题和需求

SpringBoot基于MyBatis-Plus实现Lambda Query查询的示例代码

《SpringBoot基于MyBatis-Plus实现LambdaQuery查询的示例代码》MyBatis-Plus是MyBatis的增强工具,简化了数据库操作,并提高了开发效率,它提供了多种查询方... 目录引言基础环境配置依赖配置(Maven)application.yml 配置表结构设计demo_st

详谈redis跟数据库的数据同步问题

《详谈redis跟数据库的数据同步问题》文章讨论了在Redis和数据库数据一致性问题上的解决方案,主要比较了先更新Redis缓存再更新数据库和先更新数据库再更新Redis缓存两种方案,文章指出,删除R... 目录一、Redis 数据库数据一致性的解决方案1.1、更新Redis缓存、删除Redis缓存的区别二

Redis与缓存解读

《Redis与缓存解读》文章介绍了Redis作为缓存层的优势和缺点,并分析了六种缓存更新策略,包括超时剔除、先删缓存再更新数据库、旁路缓存、先更新数据库再删缓存、先更新数据库再更新缓存、读写穿透和异步... 目录缓存缓存优缺点缓存更新策略超时剔除先删缓存再更新数据库旁路缓存(先更新数据库,再删缓存)先更新数

Redis事务与数据持久化方式

《Redis事务与数据持久化方式》该文档主要介绍了Redis事务和持久化机制,事务通过将多个命令打包执行,而持久化则通过快照(RDB)和追加式文件(AOF)两种方式将内存数据保存到磁盘,以防止数据丢失... 目录一、Redis 事务1.1 事务本质1.2 数据库事务与redis事务1.2.1 数据库事务1.

python使用watchdog实现文件资源监控

《python使用watchdog实现文件资源监控》watchdog支持跨平台文件资源监控,可以检测指定文件夹下文件及文件夹变动,下面我们来看看Python如何使用watchdog实现文件资源监控吧... python文件监控库watchdogs简介随着Python在各种应用领域中的广泛使用,其生态环境也

el-select下拉选择缓存的实现

《el-select下拉选择缓存的实现》本文主要介绍了在使用el-select实现下拉选择缓存时遇到的问题及解决方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的... 目录项目场景:问题描述解决方案:项目场景:从左侧列表中选取字段填入右侧下拉多选框,用户可以对右侧