自己的电脑做服务器建立网站的方法,制作网站用什么语言,企业推广语句,杭州网站建设_数据库开发网站_大数据网站开发目录
什么是缓存预热、缓存雪崩、缓存击穿、缓存穿透#xff1f;
缓存预热
缓存雪崩
解决方案
针对Redis故障宕机
针对大量key同时过期
缓存击穿
解决方案
缓存穿透
解决方案
总结
数据库和缓存如何保证一致性#xff1f;
先更新缓存还是先更新数据库#xff1…目录
什么是缓存预热、缓存雪崩、缓存击穿、缓存穿透
缓存预热
缓存雪崩
解决方案
针对Redis故障宕机
针对大量key同时过期
缓存击穿
解决方案
缓存穿透
解决方案
总结
数据库和缓存如何保证一致性
先更新缓存还是先更新数据库
异常情况下引发的数据一致性问题
1.先更新数据库再更新缓存
2.先更新缓存再更新数据库
并发情况下引发的一致性问题
1.先更新数据库再更新缓存
解决方案
2.先更新缓存再更新数据库
先删除缓存再更新数据库还是先更新数据库再删除缓存
并发情况下引发的一致性问题
1.先删除缓存再更新数据库
解决方案
2.先更新数据库再删除缓存 如何保证两步都成功
1.重试机制
2.订阅数据库变更日志
总结 什么是缓存预热、缓存雪崩、缓存击穿、缓存穿透
缓存预热
缓存预热就是系统上线后提前将相关的缓存数据直接加载到缓存系统。避免在用户请求的时候先查询数据库然后再将数据缓存的问题用户直接查询事先被预热的缓存数据
缓存雪崩
当大量key同时过期或Redis故障宕机时如果有大量的用户请求都无法再Redis中处理于是全部请求都直接访问数据库从而导致数据库压力骤增严重会导致数据库宕机从而形成一系列连锁反应造成整个数据库崩溃这就是缓存雪崩。
解决方案
针对Redis故障宕机
1.采用Redis集群避免单机出现问题导致整个缓存服务都没法使用
2.服务熔断或请求限流机制因为Redis宕机而导致的缓存雪崩问题时可以启动服务熔断机制暂停业务应用对缓存服务的访问直接返回错误不再继续访问数据库从而降低对数据库的压力保证数据库系统的正常运行然后等到 Redis 恢复正常后再允许业务应用访问缓存服务。
服务熔断机制是保护数据库的正常允许但是暂停了业务应用访问缓存服系统全部业务都无法正常工作为了减少对业务的影响我们可以启用请求限流机制只是将少部分请求发送到数据库进行处理再多的请求就在入口处直接拒绝服务等到Redis恢复正常并把缓存预热完后在解除请求的限流机制。
针对大量key同时过期
1.均匀key过期时间应避免大量key同一时间过期。
2.互斥锁在线程处理业务请求时如果发现访问的数据不在Redis数据库中就加个互斥锁保证同一时间只有一个请求从数据库中读取数据再将缓存更新到Redis中。设置互斥锁时最好设置超时时间避免当请求拿到锁后这个请求发生某种情况一直阻塞无法释放锁导致其他请求也拿不到锁系统发生无响应现象。
3.后台更新缓存业务线程不再负责更新缓存缓存也不设置有效期而是让缓存“永久有效”并让更新缓存的工作交由后台线程定时更新。
缓存击穿
如果缓存中的某个热点数据过期了此时大量请求访问了该热点数据就无法从缓存中读取直接访问数据库数据库就很容易被高并发的请求冲垮这就是缓存击穿。
解决方案
1.互斥锁方案保证同一时间只有一个业务线程在更新缓存未获取互斥锁的请求要么等待锁释放后重新读取缓存要么就返回空值或者默认值。
2.不给热点数据设置过期时间由后台异步更新缓存或者在热点数据准备要过期前提前通知后台线程更新缓存以及重新设置过期时间
3.差异失效时间新建两块缓存主A从B先更新B在更新A严格按照这个顺序。当查询缓存时先查询主缓存A如果A中没有所需数据在查询从缓存B。
缓存穿透
当用户访问数据时数据既不在缓存中也不在数据库中导致请求在访问缓存时发现缓存缺失再去访问数据库时发现数据库中也没有要访问的数据没法构建缓存数据来服务后续的请求。那么当有大量这样的请求到来时数据库压力骤增这就是缓存穿透。
缓存穿透的发生一般有两种情况
1.业务操作失误缓存中的数据和数据库中的数据都被删除了所以导致缓存和数据库中都没有数据
2.黑客恶意攻击。故意大量访问不存在的数据的业务。
解决方案
1.非法请求的限制当有大量恶意请求访问不存在的数据的时候也会发生缓存穿透因此在 API 入口处我们要判断求请求参数是否合理请求参数是否含有非法值、请求字段是否存在如果判断出是恶意请求就直接返回错误避免进一步访问缓存和数据库。
2.设置空值或默认值当我们线上业务发现缓存穿透的现象时可以针对查询的数据在缓存中设置一个空值或者默认值这样后续请求就可以从缓存中读取到空值或者默认值返回给应用而不会继续查询数据库。
3.使用布隆过滤器快速判断数据是否存在避免通过查询数据库来判断数据是否存在我们可以在写入数据库数据时使用布隆过滤器做个标记然后在用户请求到来时业务线程确认缓存失效后可以通过查询布隆过滤器快速判断数据是否存在如果不存在就不用通过查询数据库来判断数据是否存在即使发生了缓存穿透大量请求只会查询 Redis 和布隆过滤器而不会查询数据库保证了数据库能正常运行Redis 自身也是支持布隆过滤器的。
需要注意的是布隆过滤器可能会存在误判的情况。总结来说就是布隆过滤器说某个元素存在小概率会误判。布隆过滤器说某个元素不在那么这个元素一定不在。
总结 数据库和缓存如何保证一致性
先更新缓存还是先更新数据库
先不考虑并发问题正常情况下无论谁先谁后都会更新成功但异常情况下可能会发生【第一步操作成功、第二步操作失败的情况】
异常情况下引发的数据一致性问题
1.先更新数据库再更新缓存
更新数据库成功更新缓存失败那么此时数据库中是最新值缓存中是旧值之后读到的就是旧值只有当缓存失效后才能从数据库中得到正确得值。
2.先更新缓存再更新数据库
更新缓存成功更新数据库失败那么此时缓存中是最新值数据库中是旧值之后读到的是缓存中的新值但当缓存失效后从数据库中又会读到旧值。
并发情况下引发的一致性问题
1.先更新数据库再更新缓存
假如有两个请求请求A和请求B同时更新同一条数据可能会出现这样的情况 请求A先将数据库中数据更新为1然后在更新缓存前请求B将数据库数据更新为2紧接着也把缓存更新为2然后 请求A将缓存更新为1此时数据库中数据为1缓存中数据为2出现了缓存和数据库中数据不一致情况。
解决方案
1.采用分布式锁在更新缓存前先加个分布式锁保证同一时间只运行一个请求更新缓存就会不会产生并发问题了当然引入了锁后对于写入的性能就会带来影响。
2.设置过期时间在更新完缓存时给缓存加上较短的过期时间这样即时出现缓存不一致的情况缓存的数据也会很快过期对业务还是能接受的。
2.先更新缓存再更新数据库
假如有两个请求请求A和请求B同时更新同一条数据可能会出现这样的情况 A 请求先将缓存的数据更新为 1然后在更新数据库前B 请求来了 将缓存的数据更新为 2紧接着把数据库更新为 2然后 A 请求将数据库的数据更新为 1。
此时数据库中的数据是 1而缓存中的数据却是 2出现了缓存和数据库中的数据不一致的现象。
先删除缓存再更新数据库还是先更新数据库再删除缓存
所以无论是「先更新数据库再更新缓存」还是「先更新缓存再更新数据库」这两个方案都存在并发问题当两个请求并发更新同一条数据的时候可能会出现缓存和数据库中的数据不一致的现象。
此时需要考虑另一种方案删除缓存。在更新数据时不更新缓存而是删除缓存中的数据。然后到读取数据时发现缓存中没了数据之后再从数据库中读取数据更新到缓存中。即Cache Aside旁路缓存策略。
对于异常情况但凡第二步操作失败肯应会引起数据不一致这里重点介绍并发问题带来的数据不一致情况。
并发情况下引发的一致性问题
1.先删除缓存再更新数据库
有两个请求请求A进行写操作请求B进行读操作
1请求A进行写操作删除redis缓存后工作正在进行中更新mysql......A还么有彻底更新完mysql还没commit
2请求B开工查询查询redis发现缓存不存在(被A从redis中删除了)
3请求B继续去数据库查询得到了mysql中的旧值(A还没有更新完)
4请求B将旧值写回redis缓存
5请求A将新值写入mysql数据库
上述情况会出现数据不一致情况 解决方案
1.延迟双删在线程 A 删除缓存、更新完数据库之后先「休眠一会」再「删除」一次缓存。
#删除缓存
redis.delKey(X)
#更新数据库
db.update(X)
#睡眠
Thread.sleep(N)
#再删除缓存
redis.delKey(X)
加了个睡眠时间主要是为了确保请求 A 在睡眠的时候请求 B 能够在这这一段时间完成「从数据库读取数据再把缺失的缓存写入缓存」的操作然后请求 A 睡眠完再删除缓存。
所以请求 A 的睡眠时间就需要大于请求 B 「从数据库读取数据 写入缓存」的时间。
2.先更新数据库再删除缓存
继续用「读 写」请求的并发的场景来分析。
假如某个用户数据在缓存中不存在请求 A 读取数据时从数据库中查询到年龄为 20在未写入缓存中时另一个请求 B 更新数据。它更新数据库中的年龄为 21并且清空缓存。这时请求 A 把从数据库中读到的年龄为 20 的数据写入到缓存中。 最终该用户年龄在缓存中是 20旧值在数据库中是 21新值缓存和数据库数据不一致。
从上面的理论上分析先更新数据库再删除缓存也是会出现数据不一致性的问题但是在实际中这个问题出现的概率并不高。
因为缓存的写入通常要远远快于数据库的写入所以在实际中很难出现请求 B 已经更新了数据库并且删除了缓存请求 A 才更新完缓存的情况。
而一旦请求 A 早于请求 B 删除缓存之前更新了缓存那么接下来的请求就会因为缓存不命中而从数据库中重新读取数据所以不会出现这种不一致的情况。 如何保证两步都成功
前面我们分析到无论是更新缓存还是删除缓存只要第二步发生失败那么就会导致数据库和缓存不一致。
1.重试机制
可以引入消息队列将第二个操作删除缓存要操作的数据加入到消息队列由消费者来操作数据。
如果应用删除缓存失败可以从消息队列中重新读取数据然后再次删除缓存这个就是重试机制。当然如果重试超过的一定次数还是没有成功我们就需要向业务层发送报错信息了。如果删除缓存成功就要把数据从消息队列中移除避免重复操作否则就继续重试。 2.订阅数据库变更日志
「先更新数据库再删缓存」的策略的第一步是更新数据库那么更新数据库成功就会产生一条变更日志记录在 binlog 里。
于是我们就可以通过订阅 binlog 日志拿到具体要操作的数据然后再执行缓存删除。
总结 文章参考
2.小林coding图解Redis介绍 | 小林coding
3. 尚硅谷Redis7实战尚硅谷Redis零基础到进阶最强redis7教程阳哥亲自带练附redis面试题_哔哩哔哩_bilibili
4.javaguide:Java 面试指南 | JavaGuide(Java面试 学习指南)
5.水滴与银弹公众号缓存和数据库一致性问题看这篇就够了 (qq.com)