从面试到大厂实践:如何保证缓存数据一致?

421 阅读6分钟

面试高频问题:系统中有用到缓存吗,如何保证一致性?

这类八股文已经有无数文章阐述了,那么大厂里面到底怎么实现一致性的呢?还有哪些点可以引申呢?本文就结合阿里内部的一些使用,列举几点思路,算是一个引子,供后续继续研究。

当然,不能脱离具体场景而一股脑使用一种方案。对于不需要实时/准实时更新的场景,可以通过设置过期时间实现。而对于实时/准实时场景,就需要关注缓存数据与源数据的同步。还有的特殊场景还真的不能用缓存。

常规流程

常规流程是 cache aside :

  • 对于读取的场景:读cache,有数据返回;没有数据,则从DB中拉取并缓存,然后返回;
  • 对于更新场景:先写DB,然后失效缓存;

这里推荐微软一篇文章,讲解 cache aside模式,比较清晰,点击前往。也是我们业务常用的模式。

另外的 read through、write through、write back,主要是取决于缓存组件是否支持这样的模式。

举个例子,innodb 中有 buffer pool,buffer pool 会缓存数据页,当对应数据页有更新时,实际上是只更新 buffer pool 中的数据页后就返回了。至于什么时候落盘,会有定时处理,或者pool中淘汰缓存页面时落盘等。

假如你问怎么保证pool中未落盘数据页不丢失,则有 redo 等机制保证。所以这些模式最好缓存组件内置支持,否则业务开发过于麻烦。可以进一步参考关于 innodb 内部组件机制

cache aside 问题在于失效缓存这步失败了如何处理?补偿机制。

最常规的补偿机制是使用 canel (集团内是精卫)订阅 binlog 实现失效缓存,失败一定次数告警后人工介入。

以上基本是我们熟知的,也是实际在用的。八股文也是这样写的,那么实际也差不多。当然了,更新不频繁的场景,少部分业务也会直接用事务机制处理的。

下面是个人认为需要特殊说明或者关注的。

mysql memcached plugin

官方描述链接,该插件相当于是 mysql 内部集成了 KV 缓存,部分场景实际可以使用。使用时就等同于 mysql 成了自带 write back 机制的组件。

对账

对账可以演化出另外一套系统和机制,这里简单提一下。

为什么需要对账呢?

部分业务场景对数据一致的实时性要求比较高,一般要在秒级以内,但是特殊情况下,补偿机制可能分钟级都不成功。这就需要业务及时感知处理。

一种流程可以是把监听的 binlog 写入流处理系统,进行和缓存系统的实时对账与告警。故障及时发现是非常重要的,尽可能避免资损。

预热

比如大促前,热点缓存预热是非常重要的。阿里有专门的预热系统,当然也有团队自建。

预热难点在于构建一整套机制,包括热点识别与预测,预热数据任务分发,多级缓存预热等。这些至少涉及到大数据量、分布式调度等。数据也是统计出不同维度数据,进行分阶段预热。

这里提一下毕玄的观点,大意是:不用说核心系统,就算非核心系统,也很少有人能说清楚整个的链路。这里的链路指的是从前端应用访问起始,因为阿里技术体系庞大,业务应用都够建在这样的地基上,比如机房/cdn/网络/各类平台/系统等等,非常复杂。

所以各类大促前,都需要梳理本团队业务域内的交互链路和qps。

关于热点识别,可以再简单提一下。由于缓存一般采用一致性hash等类似机制,会导致热点访问集中在一台机器上。比如 阿里 tair 缓存,可以自动识别热点key,并在每台 data server 上开启 hot zone 存储热点数据。相当于将不同的热点key打散到不同的 dataserver 上。

对于热点 key 的更新操作,可以在服务端由专门的热点线程处理,将多次写操作合并,以减少热点 key 的实际写次数。当然数据一致性会有一定延时。

特殊案例:版本号

普通系统正常方案完全可行,但是高并发系统或者特殊逻辑系统,需要结合实际来涉及和演进。

比如,对于订单缓存,订单一般设计为主子单结构。主单变化少,子单经常变化。可以通过主子单分别设置版本号,客户端校验来实现主单和子单的数据一致刷新。

再比如,可以仿照 HTTP 的机制实现客户端缓存和服务端数据的一致性。

多级缓存

多级缓存可能会涉及到应用的本地缓存,需要特殊关注。比如缓存采用堆内内存,当缓存量巨大时,GC长时间停顿;采用堆外有一定性能损耗。

再比如本地缓存组件最好操作与远程缓存组件一致,对业务代码友好。阿里 tair 缓存就有本地 tair 和 远端 tair,可以方便使用。

而且多级缓存涉及到多个缓存节点的数据对账也是需要考虑的。

数据的多机房多集群同步

多机房部署主要是在物理层面避免风险,缺点是跨机房访问延时会高一些。

多机房部署一个集群,并且没有主备,也就是数据只有单份。好处是缓存数据只有一份,不用考虑缓存数据同步。但是应用需要跨机房访问缓存数据。

多机房部署一个集群,每个数据都有多份,存在各个机房。好处是单一机房宕机不影响,缺点是数据一致性同步问题。

多机房部署独立集群,每个机房都有独立的缓存集群。源数据统一从后级数据库同步。集群之间不同步数据,应用也不需要跨机房访问。但是需要一个协调者角色,比如 tair 中的 invalid server ,来失效多个机房的机房的缓存数据。

多机房部署主备集群,也就是不同机房内部,缓存数据都是一样的。所以缓存的主备是由缓存系统实现,无需业务方关心。

小结

从一个验证面试疑惑出发,引出了一些值得关注的点。后续会考虑针对其中的某些点进一步研究。

此外,包括 cpu cache,也是一个很好的对比和进一步学习的场景。


关于 分布式原理、数据库原理可以访问我之前的系列专题:oatlmy.blog.csdn.net

关于 小白从0开始学习后端 web 开发,可以访问我之前带学生的经历沉淀下来的教程,需要有积极主动的探索精神才可以快速入门:

gitee.com/oatlmy/fast…