做者:不学无数的程序员
连接:https://www.jianshu.com/p/a8eb1412471fjava
在作系统优化时,想到了将数据进行分级存储的思路。由于在系统中会存在一些数据,有些数据的实时性要求不高,好比一些配置信息。程序员
基本上配置了好久才会变一次。而有一些数据实时性要求很是高,好比订单和流水的数据。因此这里根据数据要求实时性不一样将数据分为三级。redis
可是只要使用到缓存,不管是本地内存作缓存仍是使用 redis 作缓存,那么就会存在数据同步的问题,由于配置信息缓存在内存中,而内存时没法感知到数据在数据库的修改。这样就会形成数据库中的数据与缓存中数据不一致的问题。spring
接下来就讨论一下关于保证缓存和数据库双写时的数据一致性。sql
那么咱们这里列出来全部策略,而且讨论他们优劣性。数据库
这种场景通常是没有人使用的,主要缘由是在更新缓存那一步,为何呢?由于有的业务需求缓存中存在的值并非直接从数据库中查出来的,有的是须要通过一系列计算来的缓存值,那么这时候后你要更新缓存的话其实代价是很高的。若是此时有大量的对数据库进行写数据的请求,可是读请求并很少,那么此时若是每次写请求都更新一下缓存,那么性能损耗是很是大的。缓存
举个例子好比在数据库中有一个值为 1 的值,此时咱们有 10 个请求对其每次加一的操做,可是这期间并无读操做进来,若是用了先更新数据库的办法,那么此时就会有十个请求对缓存进行更新,会有大量的冷数据产生,若是咱们不更新缓存而是删除缓存,那么在有读请求来的时候那么就会只更新缓存一次。架构
这一种状况应该不须要咱们考虑了吧,和第一种状况是同样的。intellij-idea
该方案也会出问题,具体出现的缘由以下。ide
此时来了两个请求,请求 A(更新操做) 和请求 B(查询操做)
那么这时候就会产生数据库和 Redis 数据不一致的问题。如何解决呢?其实最简单的解决办法就是延时双删的策略。
可是上述的保证事务提交完之后再进行删除缓存还有一个问题,就是若是你使用的是 Mysql 的读写分离的架构的话,那么其实主从同步之间也会有时间差。
此时来了两个请求,请求 A(更新操做) 和请求 B(查询操做)
此时的解决办法就是若是是对 Redis 进行填充数据的查询数据库操做,那么就强制将其指向主库进行查询。
问题:这一种状况也会出现问题,好比更新数据库成功了,可是在删除缓存的阶段出错了没有删除成功,那么此时再读取缓存的时候每次都是错误的数据了。
此时解决方案就是利用消息队列进行删除的补偿。具体的业务逻辑用语言描述以下:
可是这个方案会有一个缺点就是会对业务代码形成大量的侵入,深深的耦合在一块儿,因此这时会有一个优化的方案,咱们知道对 Mysql 数据库更新操做后再 binlog 日志中咱们都可以找到相应的操做,那么咱们能够订阅 Mysql 数据库的 binlog 日志对缓存进行操做。
每种方案各有利弊,好比在第二种先删除缓存,后更新数据库这个方案咱们最后讨论了要更新 Redis 的时候强制走主库查询就能解决问题,那么这样的操做会对业务代码进行大量的侵入,可是不须要增长的系统,不须要增长总体的服务的复杂度。
最后一种方案咱们最后讨论了利用订阅 binlog 日志进行搭建独立系统操做 Redis,这样的缺点其实就是增长了系统复杂度。其实每一次的选择都须要咱们对于咱们的业务进行评估来选择,没有一种技术是对于全部业务都通用的。没有最好的,只有最适合咱们的。
近期热文推荐:
1.Java 15 正式发布, 14 个新特性,刷新你的认知!!
2.终于靠开源项目弄到 IntelliJ IDEA 激活码了,真香!
3.我用 Java 8 写了一段逻辑,同事直呼看不懂,你试试看。。
以为不错,别忘了随手点赞+转发哦!