为了减少数据不一致的情况,更新缓存和数据库的机制显得尤为重要,接下来带领大家踩踩坑。

Cache aside
Cache aside
也就是旁路缓存
,是比较常用的缓存策略。
(1)读请求
常见流程

应用首先会判断缓存是否有该数据,缓存命中直接返回数据,缓存未命中即缓存穿透到数据库,从数据库查询数据然后回写到缓存中,最后返回数据给客户端。
(2)写请求
常见流程

首先更新数据库,然后从缓存中删除该数据。
看了写请求的图之后,有些同学可能要问了:为什么要删除缓存,直接更新不就行了?这里涉及到几个坑,我们一步一步踩下去。
Cache aside踩坑
Cache aside策略如果用错就会遇到深坑,下面我们来逐个踩。
踩坑一:先更新数据库,再更新缓存
如果同时有两个写请求
需要更新数据,每个写请求都先更新数据库再更新缓存,在并发场景可能会出现数据不一致的情况。

如上图的执行过程:
(1)写请求1
更新数据库,将 age 字段更新为18;
(2)写请求2
更新数据库,将 age 字段更新为20;
(3)写请求2
更新缓存,缓存 age 设置为20;
(4)写请求1
更新缓存,缓存 age 设置为18;
执行完预期结果是数据库 age 为20,缓存 age 为20,结果缓存 age为18,这就造成了缓存数据不是最新的,出现了脏数据。
踩坑二:先删缓存,再更新数据库
如果写请求
的处理流程是先删缓存再更新数据库
,在一个读请求
和一个写请求
并发场景下可能会出现数据不一致情况。

如上图的执行过程:
(1)写请求
删除缓存数据;
(2)读请求
查询缓存未击中(Hit Miss),紧接着查询数据库,将返回的数据回写到缓存中;
(3)写请求
更新数据库。
整个流程下来发现数据库
中age为20,缓存
中age为18,缓存和数据库数据不一致,缓存出现了脏数据。
踩坑三:先更新数据库,再删除缓存
在实际的系统中针对写请求
还是推荐先更新数据库再删除缓存
,但是在理论上还是存在问题,以下面这个例子说明。

如上图的执行过程:
(1)读请求
先查询缓存,缓存未击中,查询数据库返回数据;
(2)写请求
更新数据库,删除缓存;
(3)读请求
回写缓存;
整个流程操作下来发现数据库age为20
,缓存age为18
,即数据库与缓存不一致,导致应用程序从缓存中读到的数据都为旧数据。
但我们仔细想一下,上述问题发生的概率其实非常低,因为通常数据库更新操作比内存操作耗时多出几个数量级,上图中最后一步回写缓存(set age 18)速度非常快,通常会在更新数据库之前完成。
如果这种极端场景出现了怎么办?我们得想一个兜底的办法:缓存数据设置过期时间
。通常在系统中是可以允许少量的数据短时间不一致的场景出现。
Read through
在 Cache Aside 更新模式中,应用代码需要维护两个数据源头:一个是缓存,一个是数据库。而在 Read-Through
策略下,应用程序无需管理缓存和数据库,只需要将数据库的同步委托给缓存提供程序 Cache Provider
即可。所有数据交互都是通过抽象缓存层
完成的。

如上图,应用程序只需要与Cache Provider
交互,不用关心是从缓存取还是数据库。
在进行大量读取时,Read-Through
可以减少数据源上的负载,也对缓存服务的故障具备一定的弹性。如果缓存服务挂了,则缓存提供程序仍然可以通过直接转到数据源来进行操作。
Read-Through 适用于多次请求相同数据的场景
,这与 Cache-Aside 策略非常相似,但是二者还是存在一些差别,这里再次强调一下:
在 Cache-Aside 中,应用程序负责从数据源中获取数据并更新到缓存。 在 Read-Through 中,此逻辑通常是由独立的缓存提供程序(Cache Provider)支持。
Write through
Write-Through
策略下,当发生数据更新(Write)时,缓存提供程序 Cache Provider
负责更新底层数据源和缓存。
缓存与数据源保持一致,并且写入时始终通过抽象缓存层
到达数据源。
Cache Provider
类似一个代理的作用。

Write behind
Write behind
在一些地方也被成为Write back
, 简单理解就是:应用程序更新数据时只更新缓存, Cache Provider
每隔一段时间将数据刷新到数据库中。说白了就是延迟写入
。

如上图,应用程序更新两个数据,Cache Provider 会立即写入缓存中,但是隔一段时间才会批量写入数据库中。
这种方式有优点也有缺点:
优点
是数据写入速度非常快,适用于频繁写的场景。缺点
是缓存和数据库不是强一致性,对一致性要求高的系统慎用。
总结一下
学了这么多,相信大家对缓存更新的策略都已经有了清晰的认识。最后稍稍总结一下。
缓存更新的策略主要分为三种:
Cache aside Read/Write through Write behind
Cache aside 通常会先更新数据库,然后再删除缓存,为了兜底通常还会将数据设置缓存时间。
Read/Write through 一般是由一个 Cache Provider 对外提供读写操作,应用程序不用感知操作的是缓存还是数据库。
Write behind简单理解就是延迟写入,Cache Provider 每隔一段时间会批量输入数据库,优点是应用程序写入速度非常快。
好了,今天先到这里了,大家学会了吗?
以上是高并发场景下,到底先更新缓存还是先更新数据库?的详细内容。更多信息请关注PHP中文网其他相关文章!

javaispopularforcross-platformdesktopapplicationsduetoits“ writeonce,runanywhere”哲学。1)itusesbytbytybytecebytecodethatrunsonanyjvm-platform.2)librarieslikeslikeslikeswingingandjavafxhelpcreatenative-lookingenative-lookinguisis.3)

在Java中编写平台特定代码的原因包括访问特定操作系统功能、与特定硬件交互和优化性能。1)使用JNA或JNI访问Windows注册表;2)通过JNI与Linux特定硬件驱动程序交互;3)通过JNI使用Metal优化macOS上的游戏性能。尽管如此,编写平台特定代码会影响代码的可移植性、增加复杂性、可能带来性能开销和安全风险。

Java将通过云原生应用、多平台部署和跨语言互操作进一步提升平台独立性。1)云原生应用将使用GraalVM和Quarkus提升启动速度。2)Java将扩展到嵌入式设备、移动设备和量子计算机。3)通过GraalVM,Java将与Python、JavaScript等语言无缝集成,增强跨语言互操作性。

Java的强类型系统通过类型安全、统一的类型转换和多态性确保了平台独立性。1)类型安全在编译时进行类型检查,避免运行时错误;2)统一的类型转换规则在所有平台上一致;3)多态性和接口机制使代码在不同平台上行为一致。

JNI会破坏Java的平台独立性。1)JNI需要特定平台的本地库,2)本地代码需在目标平台编译和链接,3)不同版本的操作系统或JVM可能需要不同的本地库版本,4)本地代码可能引入安全漏洞或导致程序崩溃。

新兴技术对Java的平台独立性既有威胁也有增强。1)云计算和容器化技术如Docker增强了Java的平台独立性,但需要优化以适应不同云环境。2)WebAssembly通过GraalVM编译Java代码,扩展了其平台独立性,但需与其他语言竞争性能。

不同JVM实现都能提供平台独立性,但表现略有不同。1.OracleHotSpot和OpenJDKJVM在平台独立性上表现相似,但OpenJDK可能需额外配置。2.IBMJ9JVM在特定操作系统上表现优化。3.GraalVM支持多语言,需额外配置。4.AzulZingJVM需特定平台调整。

平台独立性通过在多种操作系统上运行同一套代码,降低开发成本和缩短开发时间。具体表现为:1.减少开发时间,只需维护一套代码;2.降低维护成本,统一测试流程;3.快速迭代和团队协作,简化部署过程。


热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

Video Face Swap
使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

热工具

SublimeText3 英文版
推荐:为Win版本,支持代码提示!

ZendStudio 13.5.1 Mac
功能强大的PHP集成开发环境

MinGW - 适用于 Windows 的极简 GNU
这个项目正在迁移到osdn.net/projects/mingw的过程中,你可以继续在那里关注我们。MinGW:GNU编译器集合(GCC)的本地Windows移植版本,可自由分发的导入库和用于构建本地Windows应用程序的头文件;包括对MSVC运行时的扩展,以支持C99功能。MinGW的所有软件都可以在64位Windows平台上运行。

适用于 Eclipse 的 SAP NetWeaver 服务器适配器
将Eclipse与SAP NetWeaver应用服务器集成。

Atom编辑器mac版下载
最流行的的开源编辑器