首页 > 其他分享 >数据和缓存如何保持一致

数据和缓存如何保持一致

时间:2023-11-17 14:05:04浏览次数:29  
标签:方案 缓存 更新 查询 保持一致 库里 数据

目前业界里有哪些方案,让数据库和缓存的数据保持一致了?

大概有以下四种

数据和缓存如何保持一致_数据

大厂模式(监听binlog+mq)

大厂模式主要是通过监听数据库的binlog(比如mysql binlog);通过binlog把数据库数据的更新操作日志(比如insert,update,delete),采集到后,通过MQ的方式,把数据同步给下游对应的消费者;下游消费者拿到数据的操作日志并拿到对应的业务数据后,再放入缓存。

大概流程图:

数据和缓存如何保持一致_数据_02

优点:

1、把操作缓存的代码逻辑,从正常的业务逻辑里解耦出来;业务代码更加清爽和简洁,两者互不干扰和影响,独立发展。用非人类的话说,减少对业务代码的侵入性。

2、曾经有幸在大厂里实践过此种方案,速度还贼快,虽然从库到缓存经过了类canel和mq中间件,但基本上耗时都是在毫秒级,99.9%都是10毫秒内能完成库里的数据和缓存数据同步(大厂的优势出来了)

缺点:

1、技术方案和架构,非常复杂

2、中间件的运维和维护,是个不小的工作量

3、由于引入了MQ需要解决引入MQ后带来的问题。比如数据乱序问题:同一条数据先发后至,后发先至的到达消费者后,从而引起的MQ乱序消费问题。但一般都能解决(比如通过redis lua+数据的时间戳比较方案,解决并发问题和数据乱序问题)

在大厂里,不缺类似canel这种伪装为数据库slave节点的自研中间件,并且大厂里也有足够的技术高手+物料,运维资源更是不缺;对小厂来说,慎用吧。

中小厂模式(定时+增量查询)

定时更新+增量查询:主要是利用库里行数据的更新时间字段+定时增量查询。

具体为:每次更新库里的行数据,记录当前行的更新时间;然后把更新时间做为一个索引字段(加快查询速度嘛)

定时任务:会每隔5秒钟(间隔时间可自定义);把库里最近更新5秒钟的数据查询出来;然后放入缓存,并记录本次查询结束时间。

整个查询过程和放入缓存的过程都是单线程执行;所以不会存在并发更新缓存问题。另外每次同步成功后,会记录同步成功时间;下次定时任务再执行时,会拿上次同步成功时间,做为本次查询开始时间条件;当前时间做为查询结束时间,以此达到增量查询的目标。

再加上查询条件里更新时间是个索引,性能也差不到哪里去。

即使偶尔的定时任务执行失败或者没有执行,也不会丢失数据,只要定时任务恢复了。

优点:

1、实现方案,和架构很简单。是的,比起大厂那套方案,简直不要太轻量。

2、也能把缓存逻辑和业务逻辑进行解耦

3、三方依赖也比较少。如果有条件可以上个分布式定时中间件比如 xxl-job,实在不行就用redis做个分布式锁也能用

缺点:

1、数据库里的数据和缓存中数据,会在极短时间内,存在不一致,但最终会是一致的。这个极短的时间,取决于定时调度间隔时间,一般在秒级。

2、如果是分库分表的业务,编写这个查询逻辑,估计会稍显复杂。

如果业务上不是要求毫秒级的及时性,也不是类似于价格这种非常敏感的数据,这种轻量级方案还真不错。无并发问题,也无数据乱序问题;秒级数据量超过几十万的增量数据并且还需要缓存的,怕是只有大厂才有的场景吧;怎么看此方案都非常适合中小公司。

小厂原始模式(缓存单删)

小厂原始模式,即业界俗称的 缓存删除模式。在更新数据前先删除缓存;然后在更新库,每次查询的时候发现缓存无数据,再从库里加载数据放入缓存。

图 缓存删除

数据和缓存如何保持一致_数据_03

图 缓存加载

数据和缓存如何保持一致_缓存_04

此方案主要解决的是佩琪当时在面试回答方案中的弊端;为什么不更新数据时同步进行缓存的更新了?

主要是有些缓存数据,需要进行复杂的计算才能获得;而这些经过复杂计算的数据,并不一定是热点数据;所以采取缓存删除,当需要的时候在进行计算放入缓存中,节省系统开销和缓存中数据量(毕竟缓存容量有限,单价又不像磁盘那样低廉,公司有矿的请忽略这条建议)

另外一个原因:面对简单场景时,缓存删除成功,库更新失败;那么也没有关系,因为读缓存时,如果发现没有命中,会从库里再加载数据放入到缓存里。

优点:

  • 此种实现方案简单
  • 无需依赖三方中间件
  • 缓存中的数据基本能和库里的数据保持一致

缺点:

  • 缓存逻辑和正常业务逻辑耦合在一起
  • 在高并发的读流量下,还是会存在缓存和库里的数据不一致。见下图

图 缓存单删 数据不一致情况

数据和缓存如何保持一致_缓存_05

time1下: T1线程执行缓存删除

time2下: T2线程查询缓存,发现没有,查库里数据,放入缓存中

time3下: T1线程更新库

time4下: 此时数据库数据是最新数据,而缓存中数据还是老版本数据

此方案非常适合业务初期,或者工期较紧的项目;读流量并发不高的情况下,属于万能型方案。

小厂优化模式(延迟双删)

延迟双删其实是为了解决缓存单删,在高并发读情况下,数据不一致的问题。具体过程为: 操作数据前,先删除缓存;接着操作DB;然后延迟一段时间,再删除缓存。

此种方案好是好,可是延迟一段时间是延迟多久了?延迟时间不够长,还是存在单删时,缓存和数据不一致的问题;延迟时间足够长又担心影响业务响应速度。实在是一个充满了玄学的延时时间

优点

2、不依赖三方中间件

3、操作速度上挺快的,直接操作DB和缓存

缺点

2、缓存操作逻辑和业务逻辑进行了耦合

此种方案放那个厂子,估计都不太合适,脑壳痛。

方案这么多,我该选择那种方案了?

为了方便大家选择,列了个每种方案的对比图。请根据自身情况进行选择

数据和缓存如何保持一致_数据_06

总结

数据库和缓存数据保持一致的问题,本质上还是数据如何在多个系统间保持一致的问题。

标签:方案,缓存,更新,查询,保持一致,库里,数据
From: https://blog.51cto.com/u_16299440/8441270

相关文章

  • 工业智能网关实现MQTT协议与物联网平台的数据通信
    随着工业物联网技术的不断发展,越来越多的设备和系统需要实现数据共享。MQTT是一种基于发布/订阅模式的轻量级消息传输协议,在物联网各种场景应用广泛,成为许多设备与物联网平台通信的标准协议之一。 物通博联推出的工业智能网关具备多样设备接入、数据采集和传输的边缘计算网关,支持......
  • 金蝶云星空签出元数据提示“数据中心业务对象版本高于应用版本”
    一、签出元数据报错 二、建议每次签出元数据前,先获取最新的代码后再签出,如果还是提示,那就根据你的情况选择版本。......
  • 自然语言处理预训练——用于预训练词嵌入的数据集
    读取数据集  下采样 提取中心词和上下文词 下面的get_centers_and_contexts函数从corpus中提取所有中心词及其上下文词。它随机采样1到max_window_size之间的整数作为上下文窗口。对于任一中心词,与其距离不超过采样上下文窗口大小的词为其上下文词。 #@savedefge......
  • 有序数据结构的交与并
    需要注意:1:求并集和交集前,需要将两个数组先进行排序(int或者vector都需要),否则结果有误2:需要定义vector的size,否则可能无法得到结果 vector的并#include<bits/stdc++.h>usingnamespacestd;intmain(){ inta[4]={1,2,3,4};//已经有序,若无序,需要排序! intb[......
  • 2023年11月中国数据库排行榜:OPO组合持续两月,亚信、中兴闯进前十
    长夜之中蓄力待,势如破晓初光披。 2023年11月的 墨天轮中国数据库流行度排行 火热出炉,本月共有283个数据库参与排名。本月排行榜前十名变动较大,TiDB上升一位居第4,达梦奋勇向前重归第6,亚信AntDB、中兴GoldenDB势如破竹进军10强。 墨天轮十巨头之争白热化,中国数据库行业将迎......
  • 记一次mysqlbinlog恢复数据库数据
    因为一些意外操作,用旧的备份覆盖了最新的数据库数据,导致最近几天内的数据被覆盖掉了。百度了一圈。。用mysqlbinlog恢复比较靠谱,网上查感觉操作也比较简单。。实际吧。费点劲。。 MySQL的Binlog是用于记录数据库中所有操作的日志文件。通过检查日志文件,可以找到误删除的......
  • 数据分析该用什么工具?
    数据分析可以使用多种工具,常见的包括Excel、Python(如pandas、NumPy、Matplotlib等库)、R语言、Datainside、PowerBI等。这些工具各有特点,选择哪个工具取决于具体的需求、数据类型、分析目的以及个人偏好。Excel:优势:易学易用,适合快速数据处理和简单分析,具备较强的数据可视化功能......
  • SqlServer中获取数据库中每个表的行数
    SqlServer中获取数据库中每个表的行数CREATETABLE#RowCounts(NumberOfRowsBIGINT,TableNameVARCHAR(128))EXECsp_MSForEachTable'INSERTINTO#RowCountsSELECTCOUNT_BIG(*)ASNumberOfRows,''?''asTableNameFROM?'SELECTTableName,Numbe......
  • Lumen框架 之数据库迁移
    一、基本操作1、/database/migrations/目录下生成一个php文件,这个文件主要包括两个函数,在up()函数中根据你的需求定义数据库字段phpartisanmake:migrationcreate_users_table--create=users<?phpuseIlluminate\Database\Migrations\Migration;useIlluminate\Database\Sch......
  • jq 数组对象,重复数据进行合并
    var bindif = [{        "ifname": "Ge0/2/1",        "ip": "20.1.1.1",        "mask": "255.255.255.0"    }, {        "ifname": "Ge0/2/5",        "ip6addr": &q......