数据库和缓存一致性问题全解析:从原理到实战

  |   0 评论   |   3,458 浏览

    今天咱们唠唠数据库和缓存为啥总闹矛盾:比如改了数据库后缓存没及时更新。咱会对比四种更新方法的优劣,再聊聊咋用过期时间、消息队列这些招儿,让数据最终保持一致。

    一、为什么缓存和数据库会闹矛盾?

    1.1 缓存加速的底层逻辑

    就像超市收银台旁边会放常用商品(方便快速结账),数据库旁边也会放一层缓存(Redis)。Redis 用内存存储数据,读数据速度比数据库快 10 倍以上 —— 比如 MySQL 每秒只能处理几千次查询,而 Redis 能处理 10 万次以上。

    1.2 一致性问题的核心矛盾

    当数据库更新后,缓存里的旧数据没及时删掉就会出问题。比如:

    • 数据库里商品价格从 100 元改成 90 元
    • 这时候如果缓存没更新,用户查到的还是 100 元
    • 就像超市改了价签,但收银台旁边的促销牌没换,顾客会搞错价格

    根本原因:数据库和缓存是两个独立的系统,没法像打包票一样同时完成更新,中间会有几毫秒的 “时差”。

    二、更新缓存的四种方案对比

    方案 1:先改数据库,再改缓存

    操作步骤

    1. 改数据库里的数据
    2. 改缓存里的数据

    问题场景
    就像两个人同时改价格:

    • 小王先把数据库价格改成 90 元
    • 小李后把数据库价格改成 80 元
    • 但小李先更新了缓存,小王后更新缓存
    • 结果缓存里是 90 元,数据库是 80 元,价格对不上

    适用场景:只有当很少人改数据时才好用

    方案 2:先改缓存,再改数据库

    操作步骤

    1. 改缓存里的数据
    2. 改数据库里的数据

    问题场景
    如果改数据库失败(比如网络断了),缓存里的新数据就成了 “假数据”。就像你先在促销牌上写了 90 元,结果仓库里没改价格,顾客结账时发现还是 100 元,会吵架。

    方案 3:先删缓存,再改数据库

    操作步骤

    1. 删掉缓存里的数据
    2. 改数据库里的数据

    问题场景
    比如你刚删掉促销牌,这时候有人来查价格:

    • 他发现促销牌没了,就去仓库查旧价格 100 元
    • 等他把旧价格写回促销牌后,你才把仓库价格改成 90 元
    • 结果促销牌还是 100 元,和仓库对不上

    改进方法:删两次缓存(等一会儿再删一次),但等多久很难把握

    方案 4:先改数据库,再删缓存(推荐方案)

    操作步骤

    1. 改数据库里的数据
    2. 删掉缓存里的数据

    优势

    • 只有删缓存前的几毫秒内,用户可能查到旧数据(比如你改完仓库价格,还没撕掉促销牌的几秒钟)
    • 下一次用户查询时,发现缓存没数据,会自动从数据库取最新数据

    推荐场景:大部分情况下都好用,尤其是买东西的人多、改价格的人少的场景

    三、保证数据最终一致的三个大招

    1. 给缓存设过期时间(必做)

    就像牛奶有保质期,缓存也该设一个 “过期时间”。比如:

    • 商品详情页缓存 300 秒
    • 超过时间自动失效,下次查询时会从数据库取最新数据
    • 就算更新缓存失败,最多 300 秒后数据也会变正确

    2. 用消息队列 “补刀”(进阶方法)

    如果删缓存失败(比如 Redis 突然断网),可以用消息队列来补救:

    • 改完数据库后,发一条 “删缓存” 的消息到队列里
    • 系统会反复尝试删缓存,直到成功为止
    • 就像你给朋友发微信没成功,微信会一直重试直到发出去

    3. 监听数据库变化(高级方法)

    有一种工具能 “偷看” 数据库的修改记录(比如 Canal),只要数据库一更新,就自动触发删缓存操作:

    • 不需要在代码里到处写删缓存的逻辑
    • 不管哪个系统改了数据库,都能统一处理
    • 就像超市装了监控,只要仓库改价格,收银台旁边的促销牌自动更新

    四、复杂场景的应对技巧

    场景 1:改一个数据要删多个缓存

    比如用户修改了个人信息,需要同时更新:

    • 个人主页缓存
    • 粉丝列表缓存
    • 积分排名缓存

    解决方案:发一条消息,里面写上所有要删的缓存名称,让专门的系统统一处理,避免代码里到处都是删缓存的代码。

    场景 2:大量用户同时查一个热门商品(缓存击穿

    比如双 11 时, tens of thousands of people 同时查某款手机的价格,可能导致缓存失效后数据库被挤爆。

    解决方案:加一把 “锁”:

    • 第一个查的人去数据库取数据,其他人等 50 毫秒
    • 避免所有人同时挤向数据库
    • 就像超市结账时,只让一个人先去仓库拿货,其他人在门口排队

    五、核心结论

    1. 没有完美方案就像做饭时很难同时做到 “快” 和 “好吃”,缓存和数据库也无法完全一致,只能尽量缩短不一致的时间。
    2. 策略选择原则
    • 如果查数据的人多、改数据的人少:用 “先改数据库,再删缓存”
    • 如果改数据的人多:可以直接查数据库,少用缓存
    1. 工程实践关键
    • 所有缓存必须设过期时间(比如 10 分钟)
    • 重要数据更新时,用消息队列确保缓存一定被删掉

    结语:技术的本质是权衡

    就像开车时要在速度和安全之间找平衡,开发系统时也要在 “数据一致性” 和 “系统性能” 之间做选择。通过本文的方法,既能让系统跑得飞快,又能把数据不一致的概率降到极低 —— 这就是分布式系统的魅力所在。

    评论

    发表评论

    validate