首页 > 其他分享 >架构与思维:再聊缓存击穿,面试是一场博弈

架构与思维:再聊缓存击穿,面试是一场博弈

时间:2022-12-14 14:14:15浏览次数:90  
标签:降级 缓存 数据库 击穿 用户 信息 再聊 限流

1 介绍

在之前的一篇文章《一次缓存雪崩的灾难复盘》中,我们比较清晰的描述了缓存雪崩、穿透、击穿的各自特征和解决方案,想详细了解的可以移步。
最近在配合HR筛选候选人,作为大厂的业务方向负责人,招人主要也是我们自己团队在用,而缓存是必不可少的面试选项之一。下面我们就来聊一聊在特定业务场景下缓存击穿和雪崩的应对场景!

2 问题背景

  • 一个核心的应用或者服务(比如微信、钉钉、百度APP),高峰QPS是百万甚至是千万

★ 分析:上述类型的应用具有很明显的峰值 高斯分布的特征,就是9~10点是用户早高峰。微信是,百度APP是,钉钉也是,钉钉一般给政企、教学等使用,通用是10点左右峰值期,每天的峰值如下:
image


  • 应用缓存了用户的基本信息,如(姓名、性别、职业、地址等),假设以为用户Id为Cache的key,那每个用户都有一个基础信息的缓存。
  • 因为不知名的原因,导致缓存都丢了(可能是缓存集体过期、故障导致缓存失效、程序bug导致缓存误删、服务器重启导致内存清理)。
  • 恰巧是访问高峰期(比如9点早高峰),千百万的请求狂奔而来,查不到缓存,透过缓存层直接投入数据库。
  • 基于磁盘的数据库的访问效率,性能,抗击打能力远逊于高速缓存,数据库很容易被打垮,造成服务雪崩。

4 候选人的各种答案(综合整理)

4.1 缓存预热

既然是可预见的峰值期,那么缓存预热是一个好办法,比如在9 ~ 10点是高峰期,在7 ~ 9点这两个小时中,可以均匀的把部分缓存做上。
image

缺点:这种仅仅只能解决可预见的缓存失效情况。如果是突发缓存失效情况,假设在10点高峰期因为某些原因(比如上面说的 故障导致缓存失效、程序bug导致缓存误删、服务器重启导致内存清理)是没有效果的。

4.2 非一致的过期时间

缓存既然大部分是在高峰期(9~10点)创建的(假设Cache的Expire Time都一样,比如8h),那很有可能失效时间会很接近。几乎同一时间一起失效,这样确实也会引起群起创建的情况,也会导致上面说的击穿的情况发生。
我们在创建同一类型的批次缓存的时候,会采用3-4-3 分布原则。比如一个缓存的Expire Time 是 10H,
那么就是3H + 4H * random() + 3h ,来进行错开!
image

缺点:同4.1类似,仅仅解决可预见的问题,对突发故障导致的无预期的缓存失效毫无办法。

4.3 消息聚合缓存

为什么每个用户的基本信息都独立存储一个缓存呢?可不可以按照用户类型分片,一类的用户合在一起不是只要查询一次,不会出现峰值期群起攻击数据库的情况。

说明:只有信息修改率非常低的缓存才适合聚合在一个缓存值中,大部分情况下不会这么做。比如你的缓存中聚合了1W个人的信息,Value非常大,但凡其中一个信息修改,那么这个缓存就要更新,不然应用读取到的信息就没有时效性,大Value的缓存频繁的存取是一个很不友好的事情。
用户信息还算修改频率比较低的,你的积分信息,购物车可是很高频变动的,这种的就不能这么干了。

4.4 削峰、加锁、限流

4.4.1 削峰

引进消息队列之类的中间件,将用户的请求放入队列,逐一执行,避免拥挤请求!

4.4.2 加锁

同一个用户的信息查询只让第一个请求进入,进入之后加锁,在获取到数据库信息并更新缓存之后释放锁,
这样单一个信息只请求一次!

4.4.3 限流

为了避免把服务端打挂,在上线前做一次无缓存压测,看数据库与服务端能支撑的最大值。并设置成限流的阈值,保证不会超过服务所能承载的压力,避免过载!

缺点:

  • 但凡用锁,排队之类的方案,无一例外的会大幅度降低服务的吞吐率,造成用户长时间等待,体验感下降,这在各大型APP(淘宝、微信、百度APP)上是完全不允许的,也不会这么干。
  • 限流也是一样的道理,限流一般是对服务的限流,而难以细粒度到只对某个信息类型的限流。而服务级别限流会误伤其他操作,比如获取排班、排课、获取购物车等非瓶颈的宽松的查询也被限了。当然,现在的限流也可以细粒度到某个或者某几个接口,所以可以将查询用户信息合在一个接口里做一下限流。但是限流也代表部分用户拿不到正确的信息,是一种降级的行为。

备注:数据库也有限流方案,细粒度到这个层级更好

4.5 短暂降级之备选缓存

你的缓存层存在主备场景,他们之间定时异步同步,所以存在短暂数据不一致。
当你的主服务挂了之后,降级去读备服务,数据时效性没那么高,但是也避免了数据库被打穿的情况发生。
image

4.6 短暂降级值客户端缓存(Redis 6.0)

参考Redis 6.0的 Client Side Cache,看我这篇《追求性能极致:客户端缓存带来的革命》。
类似4.5做法,客户端缓存时效性会差一点,毕竟存在订阅跟同步的过程,数据没那么新。但是避免大量的请求直接上缓存服务,又因无效的缓存服务有把压力转移给数据库。
image

4.7 短暂降级之空初始值

这是一种短暂降级的方式,大概流程如下:
image
可以看出,整个过程中我们牺牲了A、B、C、D的请求,他们拿回了一个空值或者默认值,但是这局部的降级却保证整个数据库系统不被拥堵的请求击穿。

5 总结

在不同的场景下各种方法都有各自的优缺点,我们要做的就是根据实际的应用场景来判断和抉择。

标签:降级,缓存,数据库,击穿,用户,信息,再聊,限流
From: https://www.cnblogs.com/wzh2010/p/16929808.html

相关文章

  • redis缓存穿透、缓存雪崩、缓存击穿【项目总结】
    Redis项目总结--缓存穿透、缓存雪崩、缓存击穿目录Redis项目总结--缓存穿透、缓存雪崩、缓存击穿一.缓存穿透1.什么是缓存穿透2.缓存穿透解决方案3.流程二.缓存雪崩1.什么......
  • 【前端】VUE路由缓存
    全部缓存<keep-alive>  <router-view></router-view></keep-alive>缓存单个指定路由<keep-aliveinclude="该路由的name名称">  <router-view></router-view></ke......
  • 解读JVM级别本地缓存Caffeine青出于蓝的要诀2 —— 弄清楚Caffeine的同步、异步回源方
    大家好,又见面了。本文是笔者作为掘金技术社区签约作者的身份输出的缓存专栏系列内容,将会通过系列专题,讲清楚缓存的方方面面。如果感兴趣,欢迎关注以获取后续更新。上......
  • webpack学习笔记之优化缓存、合并、懒加载
    除了的webpack基本配置,还可以进一步添加配置,优化合并文件,加快编译速度。下面是生产环境配置文件webpack.production.js,与wenbpack.config.js相比其不需要一些dev-tools,dev......
  • .NET4.0的可扩展缓存系统
    .NETFramework中,叫做System.Runtime.Caching,这不仅是个缓存库,还是个框架,可以在上面开发自己的库。ObjectCache定义了所有缓存都要实现的通用操作。与之......
  • 【FAQ】HarmonyOS JavaUI中使用terminate()后重新打开AbilitySlice页面存在缓存
    【前言】同一个Ability下的两个不同的AbilitySlice,官方给的JavaUI中是通过present跳转AbilitySlice,使用AbilitySlice.terminate方法关闭Slice,具体可以参考官方给的示例代码......
  • Ansible最佳实践之 AWX 启用facts缓存和模板问卷调查
    写在前面分享一些AWX启用facts缓存和模板问卷调查的笔记博文内容涉及:启动facts缓存相关配置Demo启用模板调查来设置变量demo食用方式:需要了解Ansible理解不足小伙伴......
  • gradle缓存清除
    强制清除gradle的缓存问题:有时在开发中我们会上传一些开发jar到远程仓库,当我们打包时版本号不变时有时候我们跟新不到新的jar问题分析:这个问题一般是因为gradle的缓存机制......
  • 动态组件-缓存怎么做
    设置动态组件需要添加component组件定义形式<component:is='给定的组件名称'/>组件缓存:定义keep-alive组件即可;如果组件缓存了会有两个钩子钩子可以使用:activated:当它......
  • 高速缓存
    局部性原理(locality)时间局部性与空间局部性局部性通常有两种不同的形式,时间局部性(temporallocality)和空间局部性(spatiallocality)。在一个具有良好时间局部性的程......