作者:牛牛码特
链接:https://juejin.cn/post/684490...
背景
缓存是软件开发中一个十分有用的概念,数据库缓存更是在我的项目中必然会遇到的场景。而缓存一致性的保障,更是在面试中被重复问到,这里进行一下总结,针对不同的要求,抉择恰到好处的一致性计划。
缓存是什么
存储的速度是有区别的。缓存就是把低速存储的后果,长期保留在高速存储的技术。
如图所示,金字塔更下面的存储,能够作为上面存储的缓存。
咱们本次的探讨,次要针对数据库缓存场景,将以redis作为mysql的缓存为案例来进行。
举荐一个开源收费的 Spring Boot 最全教程:
https://github.com/javastacks/spring-boot-best-practice
为什么须要缓存
存储如mysql通常反对残缺的ACID个性,因为可靠性,持久性等因素,性能广泛不高,高并发的查问会给mysql带来压力,造成数据库系统的不稳固。同时也容易产生提早。依据局部性原理,80%申请会落到20%的热点数据上,在读多写少场景,减少一层缓存十分有助晋升零碎吞吐量和健壮性。
存在问题
存储的数据随着工夫可能会发生变化,而缓存中的数据就会不统一。具体能容忍的不统一工夫,须要具体业务具体分析,然而通常的业务,都须要做到最终统一。
redis作为mysql缓存
通常的开发模式中,都会应用mysql作为存储,而redis作为缓存,减速和爱护mysql。然而,当mysql数据更新之后,redis怎么放弃同步呢。
强一致性同步老本太高,如果谋求强统一,那么没必要用缓存了,间接用mysql即可。通常思考的,都是最终一致性。
解决方案
计划一
通过key的过期工夫,mysql更新时,redis不更新。 这种形式实现简略,但不统一的工夫会很长。如果读申请十分频繁,且过期工夫比拟长,则会产生很多长期的脏数据。
长处:
- 开发成本低,易于实现;
- 治理成本低,出问题的概率会比拟小。
有余
- 齐全依赖过期工夫,工夫太短容易缓存频繁生效,太长容易有长时间更新提早(不统一)
计划二
在计划一的根底上扩大,通过key的过期工夫兜底,并且,在更新mysql时,同时更新redis。
长处
- 绝对计划一,更新提早更小。
有余
- 如果更新mysql胜利,更新redis却失败,就进化到了计划一;
- 在高并发场景,业务server须要和mysql,redis同时进行连贯。这样是损耗双倍的连贯资源,容易造成连接数过多的问题。
计划三
针对计划二的同步写redis进行优化,减少音讯队列,将redis更新操作交给kafka,由音讯队列保障可靠性,再搭建一个生产服务,来异步更新redis。
长处
- 音讯队列能够用一个句柄,很多音讯队列客户端还反对本地缓存发送,无效解决了计划二连接数过多的问题;
- 应用音讯队列,实现了逻辑上的解耦;
- 音讯队列自身具备可靠性,通过手动提交等伎俩,能够至多一次生产到redis。
有余
- 仍旧解决不了时序性问题,如果多台业务服务器别离解决针对同一行数据的两条申请,举个栗子,a = 1; a = 5;,如果mysql中是第一条先执行,而进入kafka的程序是第二条先执行,那么数据就会产生不统一。
- 引入了音讯队列,同时要减少服务生产音讯,老本较高。
计划四
通过订阅binlog来更新redis,把咱们搭建的生产服务,作为mysql的一个slave,订阅binlog,解析出更新内容,再更新到redis。
长处
- 在mysql压力不大状况下,提早较低;
- 和业务齐全解耦;
- 解决了时序性问题。
毛病
- 要独自搭建一个同步服务,并且引入binlog同步机制,老本较大。
总结
计划选型
- 首先确认产品上对提早性的要求,如果要求极高,且数据有可能变动,别用缓存。
- 通常来说,计划1就够了,笔者征询过4,5个团队,根本都是用计划1,因为能用缓存计划,通常是读多写少场景,同时业务上对提早具备肯定的包容性。计划1没有开发成本,其实比拟实用。
- 如果想减少更新时的即时性,就抉择计划2,不过没必要做重试保障之类的。
- 计划3,计划4针对于对延时要求比拟高业务,一个是推模式,一个是拉模式,而计划4具备更强的可靠性,既然都违心花功夫做解决音讯的逻辑,不如一步到位,用计划4。
论断
个别状况,计划1够用。若延时要求高,间接抉择计划4。如果是面试场景,从简略讲到简单,面试官会一步一步诘问,咱们就一点点推导,宾主尽欢。
近期热文举荐:
1.1,000+ 道 Java面试题及答案整顿(2022最新版)
2.劲爆!Java 协程要来了。。。
3.Spring Boot 2.x 教程,太全了!
4.别再写满屏的爆爆爆炸类了,试试装璜器模式,这才是优雅的形式!!
5.《Java开发手册(嵩山版)》最新公布,速速下载!
感觉不错,别忘了顺手点赞+转发哦!