课程咨询: 400-996-5531 / 投诉建议: 400-111-8989
认真做教育 专心促就业
Java编程开发是目前大多数程序员都在学习的一种编程开发语言,而本文我们就通过案例分析来简单了解一下,Java程序员需要掌握哪些数据库知识。
先删除缓存,再写数据库
高并发下容易出现问题的方案,老样子A,B两个用户,同时发起请求,A打算写,B打算读。
假设A删除了缓存,然后网络卡顿,没及时更新数据库。这时B请求,缓存未命中,于是请求数据库,查到了旧值,随后写入了缓存。此时A的卡顿结束,更新了数据库。你就会发现数据库中是新值,缓存是旧值,二者不一致。
那么能不能对这个问题再进行解决呢?还真的有,那就是缓存双删,很好理解,就是写之前删除一次,写完以后再删一次,这样就能保证后面的缓存和数据库的一致性了。不过这里要注意一点,那就是二次删除一定要间隔一段时间,不能一完成数据库的更新就立马删除,因为此时数据库刚刚更新,可能有别的请求正拿着旧数据还没写完缓存,你前脚刚删它后脚就又写上了,那不是白费力气吗?所以这里必须要隔一段缓冲时间,等读了旧数据的请求都处理完了,再去二次删除缓存。
不过这里还有一个问题,如果双删的二次删除失败了怎么办呢?这里先按下不表,后面再聊。
先写数据库,再删除缓存
这个看起来非常合理,上面那个方案既然先的那一次删缓存会导致一致性失效,那么我干脆不做一次删除,更新数据库后,隔一段时间我再删除不就可以保证缓存一致性了吗?
没错,这种情况下想要出差错非常困难,只有当满足以下三个条件时才会发生错误
缓存刚好过期
在缓存过期时发生了查询请求,且查询时写请求还没完成数据库更新操作
查询请求的写缓存操作比写请求的删除操作来得更晚
在满足上面三种条件的情况下,同样还是会因为查询请求读取并更新了旧值,导致缓存一致性遭到破坏的,不过这几个条件你也可以看出,概率是相当低了。所以这个方案是非常推荐的。
问题:删除缓存的方案如果删除失败了怎么办?
答:加入重试机制,若更新数据库成功,但更新缓存失败,我们就需要重试此操作,如果重试成功,那么一切照旧没有问题,如果重试到了指定大次数还没有成功,那么我们写入数据库并等待后续处理。
但是这里的重试机制水同样很深,如果同步重试,并发量高时非常影响性能。而异步重试就引入了非常多的可能和变数。所以这里也产生了很多种用于处理删除缓存的方案。
如下
每次重试单独创建一个线程
不建议,高并发时可能会创建大量线程引发OOM问题,非常严重
将重试任务交给指定线程池
解决了可能OOM的问题,但如果宕机有丢数据风险
将重试数据写表,再使用elastic-job这样的定时任务进行
该方案执行需要先将更新数据写到重试表中,表中存在已重试次数和重试状态字段
然后隔一段指定时间就进行一次重试,若成功则返回,失败则已重试次数+1,如果超过大次数,则记录重试状态为失败,等待后续处理
优点:数据落库,缺点:实时性差
将重试作为事件发布到MQ中,等待Consumer处理
实时性较高
监听binlog
直接建立一个订阅者监听binlog的改动,每次binlog改动则由该订阅者全权负责处理删除,更新请求只需要写完数据库就可以走人,binlog订阅者可以采用上面的那些异步方式进行处理和重试,是一种优雅的解决方案。
【免责声明】本文系本网编辑部分转载,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。如涉及作品内容、版权和其它问题,请在30日内与管理员联系,我们会予以更改或删除相关文章,以保证您的权益!更多内容请加danei456学习了解。欢迎关注“达内在线”参与分销,赚更多好礼。