后端存储实战课
李玥
美团高级技术专家
44005 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 30 讲
结束语 (1讲)
后端存储实战课
15
15
1.0x
00:00/00:00
登录|注册

11 | MySQL如何应对高并发(一):使用缓存保护MySQL

长时间查询
缓存预热
灰度发布
Read/Write Through模式
Cache Aside模式
注意缓存穿透引起雪崩
更新缓存的最佳方式
数据不可靠性
缓解MySQL并发请求压力
前置缓存
Redis
缓存保护
思考题
MySQL
高并发应对

该思维导图由 AI 生成,仅供参考

你好,我是李玥。
通过前面几节课的学习,相信你对 MySQL 这类关系型数据库的能力,已经有了定量的认知。
我们知道,大部分面向公众用户的互联网系统,它的并发请求数量是和在线用户数量正相关的,而 MySQL 能承担的并发读写的量是有上限的,当系统的在线用户超过几万到几十万这个量级的时候,单台 MySQL 就很难应付了。
绝大多数互联网系统,都使用 MySQL 加上 Redis 这对儿经典的组合来解决这个问题。Redis 作为 MySQL 的前置缓存,可以替 MySQL 挡住绝大部分查询请求,很大程度上缓解了 MySQL 并发请求的压力。
Redis 之所以能这么流行,非常重要的一个原因是,它的 API 非常简单,几乎没有太多的学习成本。但是,要想在生产系统中用好 Redis 和 MySQL 这对儿经典组合,并不是一件很简单的事儿。我在《08 | 一个几乎每个系统必踩的坑儿:访问数据库超时》举的社交电商数据库超时故障的案例,其中一个重要的原因就是,对缓存使用不当引发了缓存穿透,最终导致数据库被大量查询请求打死。
今天这节课,我们就来说一下,在电商的交易类系统中,如何正确地使用 Redis 这样的缓存系统,以及如何正确应对使用缓存过程中遇到的一些常见的问题。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

本文介绍了如何使用Redis作为MySQL的前置缓存来应对高并发读写压力。首先介绍了Redis的高性能特点,并讨论了在设计Redis缓存时需要考虑的数据不可靠性。文章详细讨论了更新缓存的最佳方式,提出了使用Cache Aside模式来避免并发读写导致的脏数据问题。此外,还强调了注意缓存穿透引起雪崩的问题,并提出了灰度发布和缓存预热等解决方案。总的来说,本文通过实际案例和技术原理,深入浅出地介绍了如何正确地使用Redis缓存来保护MySQL数据库,对于需要解决高并发读写问题的技术人员具有一定的参考价值。文章总结了使用Redis作为MySQL的前置缓存可以提升系统的并发上限,降低请求响应时延,并强调了Cache Aside模式更新缓存的最佳选择以及注意缓存穿透引起雪崩的问题。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《后端存储实战课》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(42)

  • 最新
  • 精选
  • 李玥
    置顶
    Hi,我是李玥。 这里回顾一下上节课的思考题: 课后请你选一种你熟悉的非关系型数据库,最好是支持 SQL 的,当然,不支持 SQL 有自己的查询语言也可以。比如说 HBase、Redis 或者 MongoDB 等等都可以,尝试分析一下查询的执行过程,对比一下它的执行器和存储引擎与 MySQL 有什么不同。 谈一下我的理解: 我们拿一个分布式数据库Hive来看一下它的执行器和存储引擎。严格来说,Hive并不是一个数据库,它只是一个执行器,它的存储引擎就是HDFS加上Map-Reduce。在Hive中,一条SQL的执行过程是和MySQL差不多的,Hive会解析SQL,生成并优化逻辑执行计划,然后它就会把逻辑执行计划交给Map-Reduce去执行了,后续生成并优化物理执行计划,在HDFS上执行查询这些事儿,都是Map-Reduce去干的。顺便说一下,Hive的执行引擎(严格来说是物理执行引擎)是可以替换的,所以就有了Hive on Spark,Hive on Tez这些。
    2020-03-21
    35
  • Geek_3894f9
    数据加版本号,写库时自动增一。更新缓存时,只允许高版本数据覆盖低版本数据。

    作者回复: 👍👍👍

    2020-03-21
    19
    72
  • GaGi
    对于Cache aside和read/write through而带来的数据不一致问题,工作中是这样解决: a写线程,b读线程: b线程:读缓存->未命中->上写锁>从db读数据到缓存->释放锁; a线程:上写锁->写db->删除缓存/改缓存->释放锁; 这样来保证a,b线程并发读写缓存带来的脏数据问题;

    作者回复: 👍👍👍

    2020-03-21
    16
    41
  • 丁小明
    老师,经常看到说用布隆过滤来解决缓存穿透问题,这个方案有实际的案例吗? 如果是真的可以那么怎么去操作呢? 先初始化所有可能存到缓存里面数据的key到一个足够大的布隆过滤器,然后如果有新增数据就就继续往过滤器中放,删除就从过滤器里面删(又看到说不用bit的话支持累加删除) 如果发现不在过滤器中就表示一定不存在,就无需查询了。如果在过滤器中也有可能不存在,这个时候在配合null值。 这个方案靠谱么,希望老师能解答一下

    作者回复: 首先这是个经典的方案,靠谱是没问题的。它可以解决问题是,不用真正去查询数据集,就可以判断,请求的数据是不是,不在数据集内。如果不在就不用去查询数据集了。 不少数据库都内置了布隆过滤器来提升查询效率,比如HBase。 布隆过滤器的缺点就是有点复杂,实现难度还是挺大的。

    2020-03-27
    4
  • 任鹏斌
    老师Cache Aside应该是先删缓存后更新数据库吧?先更新数据库的话一旦缓存删除失败了,就会产生脏数据

    作者回复: 严格来说,在并发情况下,二种方式都有可能产生脏数据。Cache Aside Pattern建议,先操作数据库,再操作缓存。

    2020-05-21
    4
    3
  • 王杰
    作者回复: 你可以参考一下“GaGi”同学的留言,用锁来解决并发问题。------------------------------------------------------老师,在读线程上写锁(说独占锁比较合适),是否跟MVCC相违背,MVCC不就是为了用来解决高并发带来的读写阻塞问题吗?我这边有两种解决思路不知可否:第一用版本控制,类似MVCC,第二种用Read/Write Through,写写并发在MVCC模式下依然是阻塞的,不算违背,所以只要把更新数据库与更新缓存放入统一事务中就行。读写并发不阻塞,是因为mysql用了快照读原因,那我们可以继续写线程更新缓存,读线程采用redis的setnx方式解决覆盖

    作者回复: mvcc可以很好的解决读写冲突,但是对于写写冲突,要么加锁,要么引入冲突检测机制,否则就会导致写倾斜的问题。这个在23中有详细的说明。

    2020-04-18
    5
    3
  • image
    如果缓存时有大量命中为null如何处理?如果命中null 也进行缓存,会导致缓存增长太快,容易被攻击 如果不缓存,又容易引起大量穿透

    作者回复: 这种情况理论上也没有完美的解决方案,来说说实际上的一些处理经验。 首先,避免短时间大量人为的空值攻击,这个事儿应该在上层安全或者风控层面去解决。(即使无法判断是否空值攻击,至少要拦截住短时间大量的不正常访问请求) 剩余下来的就是业务上正常的查询返回空的情况,这种可能要从业务上来设计一下,尽量避免大量可能的空值查询。 以上2点做了之后,空值查询就会少多了,这个时候可以根据实际情况选择缓存空值,或者让空值穿透。

    2020-03-26
    3
  • 1
    是不是model的话使用缓存,列表的话是不是不适合用缓存?列表应该怎么去缓存?

    作者回复: 这个还是得看业务,很多列表也可以缓存的,比如说一些排行榜数据。

    2020-03-23
  • 蚂蚁内推+v
    Cache Aside解决的只是并发写请求导致的缓存数据不一致问题。对于读写这种场景并没有彻底解决。 A:读,缓存穿透,查库。 B:写,更新数据库。 B:写,删除缓存。 A:读,回写缓存。导致不一致。 目前针对这种问题我们这边才去的方案是写请求后用MQ延迟删除缓存。老师有什么好的方法和实践吗?

    作者回复: 你可以参考一下“GaGi”同学的留言,用锁来解决并发问题。

    2020-03-21
    2
  • 往事随风,顺其自然
    老师有个问题请教你,我这边有个业务,合同编号,存在redis 🀄️和数据库中,每次先查redis 获取合同编号后面虚寒,然好加1⃣️,保存回去,外去更新数据库,做了数据库合同编号重复,检验,但是每次还是有合通编号重复的,请问这个怎么解决?市并发导致?

    作者回复: 使用Redis命令INCR是可以保存原子性的。 如果是GET出来,在程序内加一,在SET回去,确实会存在并发问题。

    2020-03-21
    3
收起评论
显示
设置
留言
42
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部