redis 与 DB 的一致性 7 种策略

    • 为什么要使用 redis 做缓存?
      • 封底估算
          • 为什么是单行数据的QPS,而不是总的?
        • 什么时候使用DB,Redis,本地缓存
      • 数据的分类
      • 一致性的方案
        • 1. 先清除Redis,再更新 DB
        • 2. 先更新DB,再清除 Redis
          • 使用场景:
        • 3. 延迟删除与延迟双删
          • 使用场景
        • 4. 监听 binlog 清除
        • 5. 双写
          • 使用场景:
        • 6. 监听binlog更新
        • 7.定时刷新
          • 使用场景
      • 选择
      • 其他问题
        • 缓存穿透

为什么要使用 redis 做缓存?

高性能

  • redis压力测试: 20w QPS(瓶颈是网络 io)
  • MySQL: 2w QPS(瓶颈是磁盘io)

封底估算

是否使用缓存是有单行数据的 QPS 决定的

为什么是单行数据的QPS,而不是总的?
  • 使用(Redis)缓存主要是利用 缓存( Redis)高性能的特性减少DB的重复查询
  • 就是数据需要多次查询,并且每次查询的结果是相同的,这时候加到缓存中,可以拦截大量的请求在缓存层,减少db的请求压力
    举个例子
  • 一些 IM 系统的总的 QPS 有几十万(qq,wx 这些)
  • 但是每个人接受的消息是不同的,并且消息是一次性消费的,所以针对单行消息而言,QPS 是小于 1 的并且是一次性消费,不涉及多次重复查询,即使总的 QPS 非常高,也不会使用缓存(IM 系统会使用Redis,但是不是做缓存使用的)
什么时候使用DB,Redis,本地缓存

使用 DB

  • 当数据是部分人可见的(比如后台管理/GM 的需求):单行数据的QPS<1(是一个常数)

使用Redis 缓存

  • 数据所有用户可见,单行数据的QPS>1 ,就需要考虑 Redis 缓存了

本地缓存

  • 原因 Redis 有 20 万 QPS,但是单 key 的 QPS 只有几千;
  • 而本地内存的读写性能有千万(map 读写)
  • 所以当单行数据的 QPS>5000(参考阿里云的热 key 二级缓存标准 QPS) 就可以考虑使用本地缓存了

数据的分类

  • 热数据: 考虑极端热数据的情景(1w 的 QPS)
  • 冷数据: 0 QPS(没人访问)
  • 由冷数据突然变成热数据: QPS 0 突变-> QPS 2000

我们的核心要求是:

  1. 热数据不能失效,因为热数据失效容易造成缓存击穿的问题
  2. 冷数据不能长时间储存在缓存(redis)中: 控制成本
  3. 冷数据(没有缓存)突变到热数据(大量请求): 不能全部请求都回源(查询 DB),否则会造成缓存击穿问题

一致性的方案

1. 先清除Redis,再更新 DB
  • 存在的问题:
    • 间隙查询的不一致问题
    • 有缓存击穿的风险

举个例子:

  1. 不一致
  • 再清除 Redis 后,更新 DB 前有一个查询请求
  • 因为 DB 没有更新,查询请求查询到旧数据,然后将旧数据更新到 Redis
  • 这时 Redis 中的就是一条脏数据,造成数据不一致的问题
  1. 如果清除到一条有 1万 QPS 的 key 很容易发生击穿的问题
2. 先更新DB,再清除 Redis
  • 存在的问题:
    • 缓存击穿的问题

还是清除到 1 万 QPS 的 key 很容易发生击穿

使用场景:
  • QPS不高(单行数据QPS<20,不存在热key 的场景)的非核心业务:比如用户的主页
3. 延迟删除与延迟双删

工作流程: 先更新 DB,再等一段时间清除 Redis / 先清除 Redis,再更新 DB,再等一段时间清除 Redis

核心解决的问题: 查询从库导致的数据不一致的问题

举个例子:

  • 更新 DB 是更新的主库,从库需要一段时间进行同步
  • 但是 DB更新完后,从库没有同步好,这时有一个查询,查询到有个未同步的从库(旧数据)
  • 然后将数据更新到 Redis

所以延迟的作用就是等待从库的数据同步好,保证数据一直

延迟多久?

  • 具体要根据项目中的同步的耗时单行数据的 qps来确定是否需要延迟删除/延迟双删
使用场景
  • QPS不高(单行数据QPS<20,不存在热key 的场景)的非核心业务:比如用户的主页 (本质与方案 2 是相同的,不能有热 key; 只是增加了延迟解决从库查询的不一致问题)
4. 监听 binlog 清除

解决的问题:

  • 将自当成 DB 的一个从节点,监听主节点的 binlog,并删除Redis
  • 服务解耦和: 与之前不同的是这种方案是低耦合实现

问题:

  • 同样只适用于 QPS<20(没有热 key 问题的需求)
  • 实现复杂: 监听 binlog 的逻辑是比较复杂的(比如 binlog 的获取,解析,消费等)
5. 双写

工作流程: 先更新 DB,再更新 Redis

  • 存在的问题与解决方案
    • 并发写的不一致问题
      • 举个例子: 有两个写请求(请求 1,将数据改为 A; 请求 2 将数据改为 B)
      • 这时请求 1 先执行,将DB 改为 A,然后请求 1 阻塞
      • 请求 2 后执行,先将 DB 改成 B , 再将 Redis 改成 B
      • 这时请求 1 阻塞恢复了,将 Redis 改成 A
      • 这时 DB 是 B,Redis(缓存)是 A,造成了一个数据不一致的问题
    • 解决方案: 加分布式锁,不允许同时更改,只能一个执行完成才能执行下一个
使用场景:
  • 完善一下

    • 热数据的过期失效问题(自动续期)
    • 冷数据突变为热数据(只放一个请求回源更新,其他请求返回空)
  • 完善后可以适用于高读,高写,高一致性的场景: 比如抢红包业务

  • 抢红包业务分析:

    • 红包发出会有大量的抢红包的操作,就涉及到大量的写(并发写)
    • 红包发出有大量的人查询抢红包的记录: 大量读
    • 抢完红包后需要所有人看到最新的记录: 高的一致性
6. 监听binlog更新

核心解决的问题

  • binlog 是有序的,如果能顺序消费 binlog 就可以解决双写中并发写的问题

如何订阅 binlog?

  1. 使用Canal组件(原理就是伪装成从节点向主节点发送 dump)

缺点:

  • 复杂,binlog 的获取,解析,消费整套是比较复杂的逻辑(比锁实现起来要更复杂),并且还要考虑过期失效的问题与冷数据突变为热数据的问题
  • 一致性没有双写好(双写使用了分布式锁,基本就是一个强一致的方案)
7.定时刷新

实现方式:

  • 储存(Redis)缓存的时候储存一个数据的更新标记(val 是一个空值),并且 更新标记的过期时间<数据的过期时间

    • 比如:更新标记 10s 过期; 数据 10 分钟过期
  • 查询的时候先使用 set nx px 命令检查更新标记是否存在,

    • 如果存在(写失败): 就使用 Redis 的数据
    • 如果不存在(写成功): 就回源(查询 DB)更新 Redis(更新数据与过期时间)

如此就可以实现数据的定时刷新(每个更新标记的存活时间刷新一次),这样可以解决一致性的问题与热数据过期失效的问题,一举两得

解决完热数据的问题还剩冷数据与冷数据突变为热数据

  1. 冷数据: 不使用会自动过期,释放空间
  2. 冷数据突变为热数据: 第一个会回源(set nx 成功),其他请求暂时返回空,知道回源完成

为什么是返回空而不是回源或者阻塞?

  1. 回源的问题: 击穿
  2. 阻塞的问题: 阻塞大量的请求(协程)(假设有 1万 QPS,回源需要 10s,就会阻塞 10 万个请求)

优点:

  1. 实现简单: 定时刷新同时解决了一致性问题与热数据的失效问题
  2. 好拓展: 不仅适用于 Redis 与 DB 的一致性,还适用于内存与 Redis 的一致性
使用场景
  1. 一致性要求不高(不敏感): 比如要求是更新后 10 分钟内可以看到数据最新的状态
  2. 读高: 有大量读并存在热点问题

比如: 短视频平台的视频数据

选择

  1. 封顶估算: 对单行数据进行封顶估算决定是否使用缓存,使用什么缓存
  2. 任务分解: 将实际需求中可能遇到的情况罗列出来(比如:热数据,冷数据,冷数据突变为热数据)
  3. 分析每一种情况,并提供对应的解决方案.

参考: https://blog.csdn.net/weixin_42338901/article/details/129231758

其他问题

上面主要解决的是击穿问题,Redis 缓存的常见的三大问题还有两个

  1. 缓存穿透: 使用不存在的 key 进行访问
  2. 缓存雪崩: 缓存大面积失效
缓存穿透

常见的解决方案:

  1. 布隆过滤器
    实现: 多次哈希,然后标记对应的 bit 位(变为 1)
    判断是否出现过: 多次哈希,所有 bit 位都为 1 才算

问题:

  • 不是 100% 准确的,存在误判的可能
  • 只能记录是否出现过(适合做加法,很难做减法)
    举个例子: 某个 key 开始是不存在的,加到布隆过滤器中防止穿透,后面存在了;这时候别人访问这个 key 就会拦截掉.
  1. 记录空值
  • 相同的不存在的 key 重复访问会拦截到 Redis 层

缺点:
比布隆过滤器消耗空间更大

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/71613.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用 Elasticsearch 进行集成测试初始化​​数据时的注意事项

作者&#xff1a;来自 Elastic piotrprz 在创建应该使用 Elasticsearch 进行搜索、数据聚合或 BM25/vector/search 的软件时&#xff0c;创建至少少量的集成测试至关重要。虽然 “模拟索引” 看起来很诱人&#xff0c;因为测试甚至可以在几分之一秒内运行&#xff0c;但它们实际…

【selenium工具操作web页面中的下拉框元素 】

使用F12定位下拉框中的元素 使用F12定位下拉框中的元素 1、有一类元素不是直接显示的页面上的&#xff0c;而是需要点击某些其他元素后才会显示在页面上&#xff0c;比如这里的下拉框。 2、这类元素会有一个特点&#xff1a;鼠标如果移开(没在元素上)&#xff0c;这些元素就会…

C++ set map 详解

文章目录 1. 容器2. set和multiset2.1 set2.1.1 构造函数2.1.2 insert和erase2.1.2.1 insert2.1.2.2 erase 2.1.3 查找和访问2.1.3.1 set迭代器相关2.1.3.2 find && count2.1.3.3 范围查找 2.2 multiset2.2.1 insert和erase2.2.2 find和count 2.3 set和multiset的在算法…

Unity网络开发基础 (2) 网络协议基础

本文章不作任何商业用途 仅作学习与交流 部分图片来自Unity唐老师 目录 1.虚拟模型 2.实际模型 TCP/IP 3.传输层协议 TCP/UDP TCP 协议详解 1. 核心机制 2. 头部格式&#xff08;20 字节最小&#xff09; UDP 协议详解 1. 核心特点 2. 头部格式&#xff08;固定 8 字节…

HTML label 标签使用

点击 <label> 标签通常会使与之关联的表单控件获得焦点或被激活。 通过正确使用 <label> 标签&#xff0c;可以使表单更加友好和易于使用&#xff0c;同时提高整体的可访问性。 基本用法 <label> 标签通过 for 属性与 id 为 username 的 <input> 元素…

JDBC、MyBatis 、MyBatis-Plus面试总结(一)

以下为你整理了一些 MyBatis 和 MyBatis-Plus 中 mapper.xml 相关的常见面试问题及答案&#xff1a; 基础概念类 问题 1&#xff1a;什么是 mapper.xml 文件&#xff0c;它在 MyBatis 中有什么作用&#xff1f; 答案&#xff1a;mapper.xml 文件是 MyBatis 中用于定义 SQL 语…

GCC RISCV 后端 -- GCC Passes 注释

在前面文章提到&#xff0c;当GCC 前端完成对C源代码解析完成后&#xff0c;就会使用 处理过程&#xff08;Passes&#xff09;机制&#xff0c;通过一系列的处理过程&#xff0c;将 GENERIC IR 表示的C程序 转步转换成 目标机器的汇编语言。过程描述如下图所示&#xff1a; 此…

基于Python实现的智能旅游推荐系统(Django)

基于Python实现的智能旅游推荐系统(Django) 开发语言:Python 数据库&#xff1a;MySQL所用到的知识&#xff1a;Django框架工具&#xff1a;pycharm、Navicat 系统功能实现 总体设计 系统实现 系统首页模块 统首页页面主要包括首页&#xff0c;旅游资讯&#xff0c;景点信息…

鸿蒙全栈开发 D2

课程目标 掌握ArkTS基础语法与核心概念理解声明式UI开发范式能独立开发简单鸿蒙应用组件建立规范的代码编写习惯 第一部分&#xff1a;初识ArkTS 1.1 语言全景认知 #mermaid-svg-V5mnjQN3DAHkfoBo {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size…

【YashanDB认证】yashandb23.3.1 个人版单机部署安装实践

YCA报名链接如下: YashanDB|崖山数据库系统YashanDB学习中心-YCA认证详情 目前免费 主要参考文档&#xff1a; 单机&#xff08;主备&#xff09;部署 | YashanDB Doc 另外还参考摩天轮文章&#xff1a; YashanDB 23.2.9.101 企业版安装步骤抢先看&#xff01; - 墨天轮 …

【蓝桥杯】每天一题,理解逻辑(3/90)【Leetcode 快乐数】

闲话系列&#xff1a;每日一题&#xff0c;秃头有我&#xff0c;Hello&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;,我是IF‘Maxue&#xff0c;欢迎大佬们来参观我写的蓝桥杯系列&#xff0c;我好久没有更新博客了&#xff0c;因为up猪我寒假用自己的劳动换了…

爬虫Incapsula reese84加密案例:Etihad航空

声明: 该文章为学习使用,严禁用于商业用途和非法用途,违者后果自负,由此产生的一切后果均与作者无关 一、找出需要加密的参数 1.js运行 atob(‘aHR0cHM6Ly93d3cuZXRpaGFkLmNvbS96aC1jbi8=’) 拿到网址,F12打开调试工具,随便搜索航班,切换到network搜索一个时间点可以找…

缓存雪崩 缓存击穿 缓存穿透

1. redis使用场景-缓存-缓存穿透 在实际开发中&#xff0c;Redis 被广泛应用于缓存&#xff0c;以提高系统性能和响应速度。然而&#xff0c;在使用缓存时&#xff0c;需要注意一些问题&#xff0c;其中 缓存穿透 是一个常见且需要重点关注的场景。 什么是缓存穿透 ● 缓存穿…

【YOLOv12改进trick】多尺度大核注意力机制MLKA模块引入YOLOv12,实现多尺度目标检测涨点,含创新点Python代码,方便发论文

🍋改进模块🍋:多尺度大核注意力机制(MLKA) 🍋解决问题🍋:MLKA模块结合多尺度、门控机制和空间注意力,显著增强卷积网络的模型表示能力。 🍋改进优势🍋:超分辨的MLKA模块对小目标和模糊目标涨点很明显 🍋适用场景🍋:小目标检测、模糊目标检测等 🍋思路…

better-sqlite3之exec方法

在 better-sqlite3 中&#xff0c;.exec() 方法用于执行包含多个 SQL 语句的字符串。与预编译语句相比&#xff0c;这种方法性能较差且安全性较低&#xff0c;但有时它是必要的&#xff0c;特别是当你需要从外部文件&#xff08;如 SQL 脚本&#xff09;中执行多个 SQL 语句时。…

电路基础:【1】PN结二极管制作电桥点亮LED灯

第一章&#xff1a;PN结二极管制作电桥点亮LED灯 文章目录 第一章&#xff1a;PN结二极管制作电桥点亮LED灯前言一、电路原理二、电路图与元器件1.电路图 做实验总结 前言 在本章中&#xff0c;我们将探讨如何通过PN结二极管制作电桥电路&#xff0c;并利用该电路点亮LED灯。L…

XHR请求解密:抓取动态生成数据的方法

在如今动态页面大行其道的时代&#xff0c;传统的静态页面爬虫已无法满足数据采集需求。尤其是在目标网站通过XHR&#xff08;XMLHttpRequest&#xff09;动态加载数据的情况下&#xff0c;如何精准解密XHR请求、捕获动态生成的数据成为关键技术难题。本文将深入剖析XHR请求解密…

机器学习数学基础:42.AMOS 结构方程模型(SEM)分析的系统流程

该流程图完整呈现了 AMOS 结构方程模型&#xff08;SEM&#xff09;分析的系统流程&#xff0c;具体步骤及内涵如下&#xff1a; 1. 模型设定 基于理论基础或研究假设&#xff0c;构建结构方程模型的初始框架&#xff0c;明确潜变量与显变量的关系、测量模型&#xff08;因子…

以太网通讯

接口开发笔记-WebApi-CSDN博客 以太网常用通讯协议 1、modbus tcp using EasyModbus; using System;class Program {static void Main(string[] args){// 创建Modbus客户端实例ModbusClient modbusClient new ModbusClient("192.168.1.100"); // IP地址modbusCli…

Arcgis中添加脚本工具箱

文章目录 准备资料1、打开arcmap2、找到目录窗口3、复制粘贴工具箱的路径4、添加或者确认python脚本路径准备资料 (1)工具箱 (2)python脚本 1、打开arcmap 2、找到目录窗口 3、复制粘贴工具箱的路径 4、添加或者确认python脚本路径 脚本上右键属性(注意:脚本内容和路径…