文章目录
前言
当前许多项目中引入缓存的背景是减少对数据库的访问,防止性能降低或数据库崩溃。
关于 Redis 的详细介绍,可以参考官方文档.
一、缓存的作用
在高并发场景下,数据库往往成为系统的瓶颈。为了提升系统性能,我们通常会在数据库之上引入缓存,用Redis充当缓存中间件,主要有以下作用:
1. 提高读性能
缓存可以快速响应请求,避免频繁访问数据库,减少查询延迟。
2. 降低数据库压力
高并发情况下,直接访问数据库可能导致数据库负载过高,缓存能有效减少数据库查询次数,提高系统吞吐量。
二、什么是缓存一致性?
缓存一致性:数据库中的数据和缓存中的数据是同步的,即当数据库中的数据发生变化后,缓存中的数据也要随之变化,确保一致。
三、为什么会有缓存一致性问题?
1. 缓存与数据库的数据更新不同步
例如:当数据库的数据被更新时,缓存中的数据未被及时更新,此时用户读取到的是旧的数据,导致读取到过期数据。
2. 缓存的过期策略导致数据不一致
例如:用户查询某商品详情,缓存正好过期,此时新查询会先去数据库,但如果数据库数据正在更新,查询到的可能是错误数据。
3. 并发场景下的写入问题
- 线程一在查询商品发现缓存未命中于是查询数据库,要将查询到的数据写入缓存。
- 在写入缓存之前,线程二在商品下单后扣减库存要更新数据库,更新完数据库后要先删除旧的缓存数据。
- 线程一执行写入缓存的操作,写入旧数据,这时就会导致用户读取到过期数据。
但是场景三发生的概率极低,线程一必须是查询数据库已经完成,但是缓存尚未写入之前。线程二要完成更新数据库同时删除缓存的两个操作。要知道线程一执行写缓存的速度在毫秒之间,速度非常快,在这么短的时间要完成数据库和缓存的操作,概率极低。
四、如何保证缓存一致性?
1. 缓存更新策略
常见的缓存更新策略有 Cache Aside、Write Through、Write Back,它们在一致性保障上各有优劣。
目前使用最多的就是Cache Aside,但是无法保证数据库与缓存的强一致性。
- 读取数据时,先查缓存,若未命中,再查询数据库,并将数据写入缓存。
- 更新数据时,先更新数据库,再删除缓存。
2. TTL过期方案
给缓存加上过期时间,一旦发生缓存不一致,当缓存过期后会重新加载,数据最终还是能保证一致。
缓存过期后缓存自动失效,下次查询时缓存未命中,就会触发数据库查询,将最新数据回填缓存,从而保证缓存不会长期存储无效数据。
这样一来,即使数据库更新后缓存未更新,TTL 过期后会自动刷新缓存,作为一个兜底方案。
五、总结
缓存一致性是分布式系统中的重要问题,本文介绍了缓存和缓存一致性的基础概念、可能出现的不一致情况以及常见的解决方案。
当然,缓存一致性问题远比本文描述的更复杂,还有诸如 双写并发问题、分布式事务、MQ+缓存更新 等进阶方案值得深入探讨。
限于个人经验,文章难免有所疏漏,欢迎各位技术同仁指正交流!