从实战出发,聊聊缓存数据库一致性

在云服务中,缓存是极其重要的一点。所谓缓存,其实是一个高速数据存储层。当缓存存在后,日后再次请求该数据就会直接访问缓存,提升数据访问的速度。但是缓存存储的数据通常是短暂性的,这就需要经常对缓存进行更新。而我们操作缓存和数据库,分为读操作和写操作。

读操作的详细流程为,请求数据,如缓存中存在数据则直接读取并返回,如不存在则从数据库中读取,成功之后将数据放到缓存中。

写操作则又分为以下 4 种:

  • 先更新缓存,再更新数据库

  • 先更新数据库,再更新缓存

  • 先删除缓存,再更新数据库

  • 先更新数据库,再删除缓存

一些一致性要求不高的数据,如点赞数等,可以先更新缓存,然后再定时同步到数据库。而在其它情况下,我们通常会等数据库操作成功,再操作缓存。

下面主要介绍更新数据库成功后,更新缓存和删除缓存这两个操作的区别和改进方案。

先更新数据库,再删除缓存

先更新数据库,再删除缓存,这种模式也叫 cache aside,是目前比较流行的处理缓存数据库一致性的方法。
它的优点是:

  • 出现数据不一致的概率极低,实现简单

  • 由于不更新缓存,而是删除缓存,在并发写写情况下,不会出现数据不一致的情况

出现数据不一致的情况出现在并发读写的场景下,详情可见下图:

这种情况发生的概率比较低,必须要在某⼀时间区间同时存在两个或多个写⼊和多个读取,所以大部分业务都容忍了这种小概率的不一致。

虽然发生的概率较低,但还是有一些方案可以让影响降到更低。

优化方案

第一种方案为:采用较短的过期时间来减少影响。这种方法有两个缺点:

  • 删除后,读请求会 miss

  • 如果缓存不一致,不一致的时间取决于过期时间设置

第二种方案则是采用延迟双删的策略,比如:1分钟以后删除缓存。这种做法也存在两个缺点:

  • 删除缓存之前的时间里可能会有不一致

  • 删除后,读请求会 miss

第三种方案为双更新策略,思路与延迟双删策略差不多。不同的点是,此方案不删除缓存而是更新缓存,所以读请求就不会发生 miss。但是另一个缺点还是存在。

先更新数据库,再更新缓存

相比先更新数据库再删除缓存的操作,先更新数据库再更新缓存的操作可以避免用户请求直接打到数据库,进而导致缓存穿透的问题。

此方案是更新缓存,我们需要关注并发读写和并发写写两个场景下导致的数据不一致。

先来看看并发读写的情况,步骤如下图所示:

可以看到由于 4 和 5 操作步骤都设置了缓存,如果步骤4发生在步骤5之前,那么会出现旧值覆盖新值的情况,也就是缓存不一致的情况。这种情况只需要修改一下步骤5,便可解决。

优化方案

可以通过在第五步不要 set cache,改用 add cache,redis 中使用 setnx 命令来进行优化。修改后步骤示意图如下:

解决完了并发读写场景导致的数据不一致,再来看看并发写写情况导致的数据不一致问题。

出现不一致的情况如下图所示,Thread A 比 Thread B 先更新完 DB,但是 Thread B 却先更新完缓存,这就导致缓存会被 Thread A 的旧值所覆盖。

这种情况也是有方法可以优化的,下面介绍两个主流方法:

  • 使用分布式锁

  • 使用版本号

使用分布式锁

要解决并发读写的问题,第一个思路就是消灭并发写。而使用分布式锁,让写操作排队执行,理论上就可以解决并发写的问题,但现在并没有可靠的分布式锁实现方案。

不管是基于 Zookeeper,etcd 还是 redis 实现分布式锁,为了防止程序挂掉而锁不能释放,我们都会给锁设置租约/过期时间,想象一种场景:如果进程卡顿几分钟(虽然概率较低),导致锁失效,而其它线程获取到锁,此时就又出现了并发读写的场景了,还是有可能会造成数据不一致。

使用版本号

并发写导致的数据不一致,是因为低版本覆盖了高版本。那么我们可以想办法不让这种情况发生,一种可行的方案是引入版本号,如果写入的数据低于现版本号,则放弃覆盖。

缺点:

  • 应用层维护版本的代价很大,大规模落地很难

  • 需修改数据模型,添加版本

  • 每次需要修改,让版本自增

不管是更新缓存还是删除缓存,优化以后都将出现数据不一致的概率降到最低了。但是有没有一种办法既简单,又不会出现数据不一致的场景呢。下面就介绍一下 Rockscache。

Rockscache

简介

Rockscache 也是一种保持缓存一致性的方法,它采用的缓存管理策略是:更新数据库后,将缓存标记为删除。主要通过以下两个方法来实现:

  • Fetch 函数实现了前面的查询缓存

  • TagAsDeleted 函数实现了标记删除的逻辑

在运行时只要读数据时调用 Fetch,并且确保更新数据库之后调用 TagAsDeleted,就能够确保缓存最终一致。这一策略有 4 个特点:

  • 不需要引入版本,几乎可以适用于所有缓存场景

  • 架构上与"更新 DB 后删除缓存”一样,无额外负担

  • 性能高:变化只是将原来的 GET/SET/DELETE,替换为 Lua 脚本

  • 强一致方案的性能也很高,与普通的防缓存击穿方案一样

在 Rockscache 策略中,缓存中的数据是包含几个字段的 hash:

  • value:数据本身

  • lockUtil:数据锁定到期时间,当某个进程查询缓存无数据,那么先锁定缓存一小段时间,然后查询 DB,然后更新缓存

  • owner:数据锁定者 uuid

证明

因为 Rockscache 方案并不更新缓存,所以只要确保并发读写数据一致性即可。下面来看看 Rockscache 是怎么解决数据不一致的问题,先回忆一遍 cache aside 模式导致的数据不一致的原因。

结合 cache aside 模式出现数据不一致的场景,来讲讲 Rockscache 是怎么解决的。

我们要解决的核心问题是,防止旧值写入到缓存中。Rockscache 的解决方案是这样的:

  • 查询请求,如果缓存中读不到数据,还要做一个操作:锁定缓存,为key设置一个uuid(代码示例:https://github.com/dtm-labs/rockscache/blob/main/client.go#L191)

  • 写请求在删除缓存的时候,需要把锁删了(代码示例:https://github.com/dtm-labs/rockscache/blob/main/client.go#L96)

  • 读请求在设置缓存的时候,通过uuid比对,发现上锁的不是自己,说明有写请求把数据更新了,则放弃修改缓存(代码示例:https://github.com/dtm-labs/rockscache/blob/main/client.go#L160)

至此我们已经完成了 rockscache 策略下的缓存更新。不过和其他缓存更新策略一样,我们都默认操作数据库成功后,操作缓存肯定成功。但是这是不对的,在实际操作过程即便操作数据库成功,也可能出现缓存操作失败的情况,因此可以通过以下 3 种方式来保证缓存更新成功:

  • 本地消息表

  • 监听 binlog

  • dtm 的二阶段消息

除了缓存更新,Rockscache 还有以下两种功能:

  • 防止缓存击穿

  • 防止防止穿透和缓存雪崩

这都是非常实用的功能,推荐大家实际使用操作试试看。

参考资料

  • https://dtm.pub/app/cache.html

  • https://smartkeyerror.oss-cn-shenzhen.aliyuncs.com/Psyduck/redis/%E7%BC%93%E5%AD%98%E6%9B%B4%E6%96%B0%E7%9A%84%E7%AD%96%E7%95%A5.pdf

相关推荐

3 分钟了解 NVIDIA 新出的 H200

英伟达在 2023 年全球超算大会上发布了备受瞩目的新一代 AI 芯片——H200 Tensor Core GPU。相较于上一代产品 H100,H200 在性能上实现了近一倍的提升,内存容量翻倍,带宽也显著增加……

github_36774378的博客 2380

深入了解浮点运算——CPU 和 GPU 算力是如何计算的

算力最基本的计量单位是 FLOPS,英文 Floating-point Operations Per Second,即每秒执行的浮点运算次数。浮点运算其实就是带小数的加减乘除运算。

github_36774378的博客 5104

加速计算,为何会成为 AI 时代的计算力“新宠”

加速计算是指使用专用硬件来执行某些类型的计算,其效率要比仅使用通用中央处理器(CPU)高。利用图形处理单元(GPU)、专用集成电路(ASIC)(包括张量处理单元(TPU))和现场可编程逻辑门阵列(FPGA)等设备的强大功能,以更高的速度执行计算,从而加速计算过程,一般我们也将这些设备称之为加速器。这些加速器尤其适用于可被分解为较小并行任务的项目,如高性能计算 (HPC)、深度学习、机器学习、人工智能和大数据分析。通过将指定类型的工作分派到这些专用加速计算硬件上,大大提高了系统的性能和效率。

github_36774378的博客 1072

NVIDIA RTX4090,你能用它做什么?

如果女生选择给男生送礼,我相信一块 RTX4090 就足以让他高兴得死去活来。RTX4090 到底是何方神圣?它凭什么赢得所有男生的“芳心”?

github_36774378的博客 2353

3 分钟看完 NVIDIA GPU 架构及演进

近期随着 AI 市场的爆发式增长,作为 AI 背后技术的核心之一 GPU(图形处理器)的价格也水涨船高。GPU 在人工智能中发挥着巨大的重要,特别是在计算和数据处理方面。目前生产 GPU 主流厂商其实并不多,主要就是 NVIDIA、AMD、Intel、高通等厂家。本文将主要聊聊 NVIDIA GPU 的核心架构及架构演进。

github_36774378的博客 1983

聊聊 GPU 产品选型那些事

随着人工智能的飞速崛起,随之而来的是算力需求的指数级增加,CPU 已经不足以满足深度学习、大模型计算等场景的海量数据处理需求。GPU 作为一种强大的计算工具,无论是高性能计算、图形渲染还是机器学习领域,在各个领域展现出了巨大的潜力和应用前景。说起 GPU,绕不过的当然是 NVIDIA 这个公司了,现在市面上火热的 A100/A800、H100 等 GPU 全是他家的产品。但当你有业务需求或者个人需求,想要采购 GPU 的时候,你会发现各个型号的 GPU 令你眼花缭乱。

github_36774378的博客 985

巅峰对决:英伟达 V100、A100/800、H100/800 GPU 对比

近期,不论是国外的 ChatGPT,还是国内诸多的大模型,让 AIGC 的市场一片爆火。而在 AIGC 的种种智能表现背后,均来自于堪称天文数字的算力支持。以 ChatGPT 为例,据微软高管透露,为 ChatGPT 提供算力支持的 AI 超级计算机,是微软在 2019 年投资 10 亿美元建造一台大型顶尖超级计算机,配备了数万个 NVIDIA A100 GPU,还配备了 60 多个数据中心总共部署了几十万个 NVIDIA GPU 辅助。

github_36774378的博客 1万+

InfiniBand 的前世今生

今年,以 ChatGPT 为代表的 AI 大模型强势崛起,而 ChatGPT 所使用的网络,正是 InfiniBand,这也让 InfiniBand 大火了起来。那么,到底什么是 InfiniBand 呢?下面,我们就来带你深入了解 InfiniBand。

github_36774378的博客 865

揭秘神秘的字符串匹配工具——正则表达式

每个正则表达式都有一个有限自动机(也称为状态机),它接受表达式指定的语言,并使用 Thompson 构造算法将正则表达式转化为一个与之等价的非确定有限状态自动机(NFA)。同时,对于每个有限自动机来说,还有一个描述该自动机所接受语言的正则表达式。该表达式可以通过克莱恩算法或高斯消元法生成。正则表达式的一个著名应用是文本编辑器中的搜索和替换功能,计算机先驱 Ken Thompson( UNIX 操作系统的开发者之一)首先在 20 世纪 60 年代的面向行编辑器 QED 中实现了该功能。

github_36774378的博客 382

深入了解 GPU 互联技术——NVLINK

随着人工智能和图形处理需求的不断增长,多 GPU 并行计算已成为一种趋势。对于多 GPU 系统而言,一个关键的挑战是如何实现 GPU 之间的高速数据传输和协同工作。然而,传统的 PCIe 总线由于带宽限制和延迟问题,已无法满足 GPU 之间通信的需求。为了解决这个问题,NVIDIA 于 2018 年推出了 NVLINK,以提高 GPU 之间的通信效率。

github_36774378的博客 3874

各快 100 倍?4G、5G、6G 相差这么多吗

二狗子今天晚上有点 emo,为什么呢?原来是二狗子心心念很久的一个手游上线了,二狗子兴冲冲地下载了 40 多分钟,终于下载完了游戏。结果打开游戏一看,发现游戏内部的更新写着预计 30 分钟完成更新。这就把二狗子搞得 emo 了。二狗子突然发现自己的室友已经在这款游戏的新手村大杀四方了。“你怎么这么快?”二狗子问。“我用手机流量下载的,5G,当然快。”室友都没看二狗子一眼,沉浸在自己的游戏世界里。5G 真的有这么快吗?好学的二狗子就让游戏保持着后台更新,在网上冲浪学习下知识充实自己。

github_36774378的博客 468

为什么大家都在用 WebP?

WebP 是谷歌在 2010 年提出的一种新型的图片格式,放到现在来讲,已经不算是“新”技术了,毕竟已经有了更新的 JPEG XL 和 AVIF。但是在日常工作中,大家时常会碰到保存下来的图片的后缀是 .webp。那么 WebP 到底有什么魔力,让越来越多的网站“抛弃”常用的 PNG、JPG 而青睐它呢?

github_36774378的博客 958

从驾考科目二到自动驾驶,聊聊 GPU 为什么对自动驾驶很重要

这些数据包含前车和本车的距离,左右两边的道路指示标志,周围汽车的距离,前方道路指示标志,红绿灯信号,马路边行人,非机动车等信息等,大量的图像和视频信息被转换成电脑能处理的二进制信息,这就需要 CPU 和 GPU 的共同加持才能完成安全稳定的自动驾驶工作。

github_36774378的博客 361

聊透 GPU 通信技术——GPU Direct、NVLink、RDMA

AI 技术对算力的需求是非常庞大的,虽然 GPU 的计算能力在持续提升,但是对于 AI 来说,单卡的计算能力就算再强,也是有极限的,这就需要多 GPU 组合。而 GPU 多卡的组合,主要分为单个服务器多张 GPU 卡和多个服务器,每个服务器多张卡这两种情况,无论是单机多卡还是多机多卡,GPU 之间需要有超强的通信支持。

github_36774378的博客 2569

这个 AI 机器人会怼人,它是怎么做到的?

人工智能可以定义为计算机科学的一个分支,其目标是创造与人类智力相当的技术。但智力到底是什么?如何利用技术来复制智力?这个疑问并不存在单一的理解,目前已经有了许多理论和方法来回答这些问题。人工智能的实现方式主要有两种:一种是基于规则的人工智能,通过预先编写的规则和逻辑来实现特定的任务;另一种是基于机器学习的人工智能,通过让计算机从数据中学习和优化算法,来实现特定的任务。

github_36774378的博客 717

如何评估计算机的算力:从 CPU 到 GPU 的演变

这就是 CPU 和 GPU 在计算能力上的区别,这是由它们的架构决定的,CPU 可以执行任何程序,而 GPU转为多任务而生,并发能力强。当然,上面的两张图并不是说 GPU 比 CPU 厉害,事实上,CPU 和 GPU 各自具有不同的特点和优势,选择哪种设备取决于具体的应用场景和需求。其中,CPU(中央处理器)和 GPU(图形处理器)是计算机中最为核心的两个组件,它们的算力和性能对于计算机的整体性能具有决定性的影响。CPU 是计算机的核心组件之一,它的主要功能是执行指令、控制计算机的运行和处理数据等任务。

github_36774378的博客 2390

浅谈 Linux 下 vim 的使用

底线模式的进入方法为:在命令模式下按":“键,Vim 窗口的左下方会出现一个”:"符号,这时就可以输入相关的指令进行操作了。在此模式下可以使用上、下、左、右键或者k、j、h、l键进行光标的移动,还可以对文件内容进行复制、粘贴、替换、删除等操作。当编辑完成,就可以按 Esc 退出插入模式,进入到命令模式。p : 黏贴,此命令是在命令模式下,按照上面的命令复制后,然后光标移动到想要复制的位置,然后按 p 黏贴。直接到某行:在底线模式下直接输入数字就可以到想到的行,如果输入的数字比文档的行数多就会到最后一行。

github_36774378的博客 1311

如何高效实现 MySQL 与 elasticsearch 的数据同步

MySQL 自身简单、高效、可靠,是又拍云内部使用最广泛的数据库。但是当数据量达到一定程度的时候,对整个 MySQL 的操作会变得非常迟缓。而公司内部 robin/logs 表的数据量已经达到 800w,后续又有全文检索的需求。这个需求直接在 MySQL 上实施是难以做到的。

github_36774378的博客 724

国密证书 VS 传统 SSL 证书,到底区别在哪?

国密算法,即国家商用密码算法。是我国自主研发创新的一套数据加密处理系列算法。从 SM1-SM4 分别实现了对称、非对称、摘要等算法功能。尤其适用于嵌入式物联网等相关领域,完成身份认证和数据加解密等功能。

github_36774378的博客 1310

又拍云邵海杨 - 25年Linux老兵,聊聊运维的“术”与“道”

邵海杨,从1998年开始使用Linux至今快25年了,资深Linux系统运维/架构师,DevOps八荣八耻倡导者,喜欢交流分享,活跃于社区,一直积极投身于开源活动的组织和传播。

github_36774378的博客 745

从 AI 绘画到 ChatGPT,聊聊生成式 AI

无论是 AI 绘画,还是现在风靡全球的 ChatGPT,它们都属于 AI 的一个分支——生成式AI(Generative AI)。相较于传统的 AI 模型,生成式 AI 是一种特定类型的 AI,它专注于创建新内容。

github_36774378的博客 5755

从 B 站出发,用 Chrome devTools performance 分析页面如何渲染

页面是如何渲染的?从 Chrome 的性能工具开始,具体看看一个页面是如何进行渲染的,以及进行页面优化时需要关注哪些指标。

github_36774378的博客 1136

【白话科普】聊聊网络架构变革的关键——SDN

SDN 即软件定义网络,它描述了一种网络架构,可以使用软件对单个硬件组件进行集中、智能的管理和控制,使用 OpenFlow 等开放协议允许访问网络设备,如交换机、路由器或防火墙等。

github_36774378的博客 1838

二狗子翻车了,只因上了这个网站……

通过 fetch API 或 XMLHttpRequest 等方式发起的 HTTP 请求,必须要遵守同源策略 ,那什么是同源策略呢?为什么这个策略会导致我们的信息在浏览器上被盗用。

github_36774378的博客 659

一文读懂 Kubernetes 存储设计

在 Docker 的设计中,容器内的文件是临时存放的,通过在 docker run 启动容器时,使用 --volume/-v 参数来指定挂载卷,将容器内部的路径挂载到主机,来保证即便容器被删除,保存到主机路径中的数据也仍然存在。

github_36774378的博客 545

当谈论 React hook,我们究竟说的是什么?

React hook是什么,所谓 React hook,就是增强函数组件能力特性的钩子,把不同的特性「钩」进纯函数。React hook 的由来,其实也可以看作是前端技术不断演进的结果。

github_36774378的博客 589

视频网站节约 30% 成本的秘密在这里

今年,爱奇艺宣布2022年第一季度首次实现季度盈利,长视频行业发展十几年来,一直深陷亏损旋涡。爱奇艺的首次实现季度盈利,也意味着降本增效将成为视频平台的发展方向。

github_36774378的博客 965

【白话科普】从“熊猫烧香”聊聊计算机病毒

到底什么是计算机病毒呢?它是什么途径传播的,又会带来哪些危害,我们又该如何在日常使用电脑中防止感染病毒呢?

github_36774378的博客 1642

【实操日记】使用 PyQt5 设计下载远程服务器日志文件程序

PyQt5 是一套 Python 绑定 Digia Qt5 应用的框架,是最强大的 GUI 库之一,使用 PyQt5 我们能够很容易的开发桌面应用,我们如何用 PyQt5 设计一个下载服务器指定日期日志文件的程序。

github_36774378的博客 1117

又拍云之 Keepalived 高可用部署

Keepalived 是什么,它一款基于 VRRP 协议的高可用软件,借助它可以让多台服务器能像路由器一样做 VIP 虚拟地址的冗余转移,从而提升后端服务器的高可靠性。

github_36774378的博客 1288
上一篇: 当谈论 React hook,我们究竟说的是什么?
下一篇: 一文读懂 Kubernetes 存储设计
又拍云 UPYUN
又拍云 UPYUN 又拍云官方账号 又拍云官方账号
博客等级 码龄10年 153粉丝 174原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值