当前位置: 首页 > news >正文

关于Redis集群同步/持久化/淘汰机制的详解

Redis是非常常用的KV数据库, 使用内存以及HashMap进行存储的特点带来了高效的查询. 本文将围绕Redis的常见开发使用场景, 阐述在Redis集群中各个节点是如何进行数据同步, 每个节点如何进行持久化以及在长期使用中如何对数据进行更新和淘汰.

如果对Redis有更多的兴趣, 可以查看我的技术博客: https://dingyuqi.com

下面是Redis在开发过程中常用的几种使用场景.
在这里插入图片描述

集群

Redis对于集群的部署支持三种模式: 主从, 哨兵和分片. 在正式的生产环境中一般会采用一主一从+哨兵的模式来解决高可用和高并发读的问题, 但是这种模式无法解决高并发写的问题. 高并发写可以借助于分片集群.

主从模式

由于单个服务器的并发数量存在上限, 我们可以使用主从模式实现读写分离, 以此提高读写的效率. 通常主节点进行写操作, 从节点进行读操作.

在主从模式中主节点和从节点之间存在数据同步的问题, 目前Redis支持两种不同的同步方式: 全量同步和增量同步.

全量同步

在了解全量同步的流程之前, 我们先熟悉几个Redis内部的定义:

  1. ReplicationId: 数据集标记, id一致说明是同一个数据集.
  2. repl-baklog: 命令的日志文件. 主要用于记录同步过程中master生成快照到slave拷贝快照这段时间master接受的命令.
  3. offset: repl-baklog的偏移量. slave的offset如果小于master则说明版本落后于master, 需要更新.

下面是全量同步的流程时序图:

slave master 执行replicaf命令建立连接 1 请求同步(参数: ReplicationId+offset) 2 判断是否为第一次同步请求(判断replid是否一致) 3 返回master的版本信息 4 保存版本信息 5 执行`bgsave`生成RDB 6 发送RDB文件 7 清空本地, 加载RDB 8 记录此间受到的所有命令到repl-baklog中 9 发送repl-baklog 10 执行repl-baklog中所有的命令 11 slave master

::: tip
步骤9实际上记录了步骤6到步骤10之间master收到的所有命令.
:::

增量同步

在了解过全量同步后, 再来对比看一下增量同步的流程. 增量同步主要用于slave节点重启后或者后期出现数据变化的场景.

slave master 重启 1 同步ReplicationId, offset 2 判断ReplicationId是否一致 3 不是第一次, 回复continue 4 从repl-baklog中获取offset之后的数据 5 发送offset之后的命令 6 执行命令 7 slave master

哨兵模式

哨兵模式主要用来实现主从集群的自动恢复. 主要的功能有三个:

  1. 监控: 检查master和slave是否正常工作
  2. 自动恢复: 如果master出现故障, 提升slave为master
  3. 通知: 集群发生故障转移时, 将最新的信息推送给Redis客户端
监控

用心跳机制, 每隔15s发一次ping确保节点的状态保持活跃. 节点下线分为两种情况:

  1. 主观下线: 某个节点超时未响应.
  2. 客观下线: 超过阈值数量的哨兵认为某节点下线. 阈值变量为quorum.
选主

当Redis中的master节点宕机后, 会使用类似Raft的投票机制来进行选主. 选主的标准大致基于以下几个:

  1. slave-priority越小
  2. offset越小
  3. 运行id越小

分片集群

分片集群主要用于应对海量的数据, 有以下几个特点:

  1. 多个master. 每个master都会存储不同的数据
  2. 每个master有多个slave
  3. master之间会用ping检测健康
  4. client可访问任意的节点进行读写, 内部会将请求自动转发到正确的节点上

那么如果不同的master存储的是不同的数据, Redis又是如何决定每一个数据应当存储到哪个节点上呢? Redis使用的是插槽, 一共有16384个插槽. 大致过程为: 首先根据key的有效部分计算Hash值, 再与16384取余决定其插槽位置, 再去取数据.

至于为什么插槽的数量定为16384, 其作者有做过正式答复:

why redis-cluster use 16384 slots?

  • Normal heartbeat packets carry the full configuration of a node, that can be replaced in an idempotent way with the old in order to
    update an old config. This means they contain the slots configuration
    for a node, in raw form, that uses 2k of space with16k slots, but
    would use a prohibitive 8k of space using 65k slots.
  • At the same time it is unlikely that Redis Cluster would scale to more than 1000 mater nodes because of other design tradeoffs. So 16k
    was in the right range to ensure enough slots per master with a max of
    1000 maters, but a small enough number to propagate the slot
    configuration as a raw bitmap easily. Note that in small clusters the
    bitmap would be hard to compress because when N is small the bitmap
    would have slots/N bits set that is a large percentage of bits set.

持久化

Redis一共提供两种持久化的策略: RDB和AOF, 现在我们分别来看一下这两种策略的优缺点.

RDB

RDB是基于快照的全量备份, 周期性地把全量的数据写入快照文件.

优点

  1. 恢复快. 因为是全量数据直接恢复就好
  2. 主进程不进行I/O, 对节点影响小

缺点

  1. 丢失间隔. RDB是快照文件, 两个快照之间节点宕机会导致快照之间的修改会丢失
  2. 老版本无法兼容. RDB文件格式与Redis的版本息息相关, 不同版本可能无法使用相同的RDB进行恢复
  3. 设置的备份的间隔时间过长, RDB太大的时候可能导致服务暂停

AOF

AOF策略是对内存修改进行指令记录.

优点

  1. 不会出现数据丢失. 最多丢失1s的数据
  2. 没有磁盘寻址开销. 因为日志是追加写入(append-only)
  3. 日志可读. 该场景可以用于紧急恢复, 例如误删了重要数据后, 可以趁着文件还未更新前将AOF保存下来.

缺点

  1. AOF日志比RDB更大. 因为AOF是指令文件, RDB是二进制文件
  2. 性能低. 因为备份间隔更小
  3. 恢复慢. 需要执行一遍AOF中的指令才能恢复

过期淘汰机制

随着Redis集群的使用时间不断增加, 里面保存的KV越来越多, 此时就会面临内存不够用的问题. Redis为此提供了过期和淘汰策略来管理海量的数据.

过期策略

顾名思义就是每一个数据在Redis当中都有一个"寿命", 当过了设定的有效时间该数据就会变为无效的数据, 不再支持读写. Redis提供两种过期策略:

  1. 定期删除: 每隔100ms随机删除部分过期key. 这里只删除部分的原因是如果进行全量扫描会导致Redis性能过低. 如果想要调整扫描间隔可以修改参数h2.
  2. 惰性删除: 不进行定期扫描, 仅仅在查询的时候判断该key是否过期, 如果过期则删除

还有一些额外的场景下Redis会对过期的key进行统一的处理:

  1. RDB生成和载入
  2. AOF的写入和重写
  3. 主从同步
    以上几种场景中都会过滤过期的key, 即过期的key不会进入快照文件或者被同步到slave节点.

淘汰机制

序号名称定义
1volatile_LRU设置了过期时间的key中执行LRU算法
2allkeys-LRU在所有key中执行LRU算法
3volatile_LFU设置了过期时间的key中执行LFU算法
4allkeys-LFU在所有key中执行LFU算法(删除最不常用的key)
5volatile_random设置了过期时间的key中执行随机删除
6allkeys-random在所有key中执行随机删除
7volatile_TTL删除过期时间最早的key
8noeviction不进行key的删除(默认配置, 但是正常开发中不会使用该模式)

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • html知识点总结
  • Windows子系统Ubuntu安装MySQL及windows的navicate连接
  • NDP协议是怎样帮助IPv6实现网络安全运行的?
  • 技术分享-商城篇-营销模块-优惠券-常见问题(二十五)
  • 油耳朵耳屎怎么清理?可视耳勺使用方法
  • .NET编程——利用C#调用海康机器人工业相机SDK实现回调取图与软触发取图【含免费源码】
  • 搭建Windows下的Rust开发环境
  • mapActions辅助函数的使用
  • 操作系统 --- 进程的状态和状态转换
  • 10个Python办公自动化案例
  • Docker容器的基础命令操作大全(入门必看)
  • 试商法除法器
  • 大和解!淘宝微信11年“屏蔽战”终落幕
  • NC 二进制中1的个数
  • 如何在Android 12 aosp系统源码中添加三指下滑截图功能
  • 【407天】跃迁之路——程序员高效学习方法论探索系列(实验阶段164-2018.03.19)...
  • CentOS7 安装JDK
  • express如何解决request entity too large问题
  • java中的hashCode
  • JS专题之继承
  • learning koa2.x
  • Mithril.js 入门介绍
  • Spring Cloud Alibaba迁移指南(一):一行代码从 Hystrix 迁移到 Sentinel
  • 百度小程序遇到的问题
  • 从零开始学习部署
  • 关于 Cirru Editor 存储格式
  • 关于使用markdown的方法(引自CSDN教程)
  • 学习ES6 变量的解构赋值
  • 优化 Vue 项目编译文件大小
  • ​【已解决】npm install​卡主不动的情况
  • ​猴子吃桃问题:每天都吃了前一天剩下的一半多一个。
  • ​如何防止网络攻击?
  • ​中南建设2022年半年报“韧”字当头,经营性现金流持续为正​
  • #我与Java虚拟机的故事#连载19:等我技术变强了,我会去看你的 ​
  • $.type 怎么精确判断对象类型的 --(源码学习2)
  • %3cscript放入php,跟bWAPP学WEB安全(PHP代码)--XSS跨站脚本攻击
  • (C语言)fgets与fputs函数详解
  • (二)构建dubbo分布式平台-平台功能导图
  • (附源码)计算机毕业设计SSM疫情社区管理系统
  • (企业 / 公司项目)前端使用pingyin-pro将汉字转成拼音
  • (十三)Maven插件解析运行机制
  • (使用vite搭建vue3项目(vite + vue3 + vue router + pinia + element plus))
  • (四) 虚拟摄像头vivi体验
  • (源码版)2024美国大学生数学建模E题财产保险的可持续模型详解思路+具体代码季节性时序预测SARIMA天气预测建模
  • (转)人的集合论——移山之道
  • .net core 调用c dll_用C++生成一个简单的DLL文件VS2008
  • .NET core 自定义过滤器 Filter 实现webapi RestFul 统一接口数据返回格式
  • .NET Core6.0 MVC+layui+SqlSugar 简单增删改查
  • .NET Framework 的 bug?try-catch-when 中如果 when 语句抛出异常,程序将彻底崩溃
  • .net Signalr 使用笔记
  • .NET 实现 NTFS 文件系统的硬链接 mklink /J(Junction)
  • ??如何把JavaScript脚本中的参数传到java代码段中
  • @Autowired @Resource @Qualifier的区别
  • @JoinTable会自动删除关联表的数据
  • @RequestBody的使用