惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

G
Google Developers Blog
人人都是产品经理
人人都是产品经理
腾讯CDC
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
WordPress大学
WordPress大学
S
SegmentFault 最新的问题
小众软件
小众软件
B
Blog
博客园 - 叶小钗
Microsoft Azure Blog
Microsoft Azure Blog
Apple Machine Learning Research
Apple Machine Learning Research
A
About on SuperTechFans
J
Java Code Geeks
Blog — PlanetScale
Blog — PlanetScale
博客园 - 司徒正美
博客园 - 【当耐特】
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
Recent Announcements
Recent Announcements
宝玉的分享
宝玉的分享
Martin Fowler
Martin Fowler
Hugging Face - Blog
Hugging Face - Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Last Week in AI
Last Week in AI
V
V2EX

祈雨的笔记

安全多方计算MPC spark原理解析 kueue执行源码分析 spark on k8s执行源码分析 spark-operator源码解析 我的世界PC与安卓联机 蚂蚁金服流量投放平台的AIG改造 G1大对象致Old区占用率高 日志打印导致接口响应率下跌分析 Groovy加载类导致OOM分析 ERROR日志打印导致CPU满载 记OceanBase死锁超时 应用发版期间服务响应超时 Ark Serverless初探 系统优化复盘一二三 The user specified as a definer does not exist Kong网关初探 API网关选型调研 CPU火焰图常用工具 配置中心选型调研 root操作Nginx导致用户组错误 基于Proxifier使用代理 FastJSON字段智能匹配踩坑 Nacos初探 记一次Nginx服务器CPU满荷载故障 基于券系统分库分表的思考 limit不参与SQL成本计算致索引失效 Linux常用性能监控命令 golang低版本http2偶现400 hostname in certificate didn't match
系统压测遇到的缓存击穿问题
祈雨的笔记 · 2023-03-18 · via 祈雨的笔记

背景

香港业务方计划在4月初做消费券活动,预计在4月有一波大促流量并且远超去年双12的流量水位,因此对香港业务方的核心链路重新做一次新流量水位的压测,保障当前集群能满足预期的流量水位需求。

经过两次实验性压测后,通过公式计算出新流量水位预计下上下游每个应用预计的集群大小和入口流量大小,并对各个上下游应用执行机房扩容和入口流量限流阈值调整。

万事俱备后,3月15日晚开始执行压测,按梯度逐渐将入口流量提升到45%时整个集群的资源使用情况十分稳定符合预期,但当流量水位从45%调整到55%时突然大量报错请求返回失败,因此中断压测排查问题。

排查

查看报错日志后,发现错误原因为DB连接池耗尽。压测的核心链路理论上应该全部使用缓存,于是去查看压测期间对应的监控记录,如下图,发现问题:

  1. 22:48时应用入口流量增长18%
  2. 22:48时远端缓存读取增长27%
  3. 22:48时DB查询增长1300%

应用入口流量增长后对远端缓存的读取量同比增长符合预期,但DB查询量却突然暴增13倍,第一反应是缓存击穿导致大量DB查询请求,然后致使数据库慢查询而耗尽DB连接池,最终导致当前的问题。

image

image

image

于是剩下的就只剩验证了,首先故障应用没有使用本地缓存,因此集群所有机器对每一个数据都共用一份远端缓存,一旦远端缓存过期失效,则瞬间集群所有集群读取不到缓存后会同时请求DB查询数据,符合DB查询增长的监控情况。

然后挑了一个单机节点查询故障时刻的DB查询日志,发现几乎全是对同一条记录的查询操作,也符合缓存击穿的猜想。

解决

确定了是因为远端缓存失效而导致的缓存击穿问题,后续的解决就很简单了。实际上这个问题去年压测的时候就已经暴露过,但由于去年水位远低于本次的水位,因此实际上去年在监控上看也仅仅是压测期间偶尔会出现DB调用次数的尖刺和DB耗时尖刺,无实际影响,所以一直把这个缓存击穿问题的优化方案给搁置了。

根本原因是应用使用的缓存均为远端缓存,无本地缓存。压测期间当远端缓存一旦过期,会导致瞬间大量DB查询请求,然后DB出现慢查询后耗尽数据库连接池,造成大量请求失败的问题。
因此需要对缓存做治理,防止出现远端缓存失效后,瞬时DB查询暴增的问题:

  1. 添加本地缓存,并且本地缓存过期时长有一定随机性,保证集群内每个单机的同一个本地缓存不会同时过期
  2. 添加远端缓存刷新逻辑,即使远端缓存还没过期,也定时强制刷新远端远程给远端缓存主动续期,防止热门远端缓存自动过期

改造后缓存读取流程如下图:

  1. 新增本地缓存,优先使用本地缓存,本地缓存不存在则使用远端缓存,远端缓存也不存在则执行数据库回查
  2. 本地缓存的有效期为5-10秒随机数,令整个集群的本地缓存不会同一时间过期
  3. 防止远端缓存过期,每个单机内存在一个计数器,每个周期(20-40秒随机数)内每个缓存的第一次读取强制执行数据库回查,实现远端缓存自动刷新,实现热门远端缓存永久不过期

image

未来

以上方案虽然解决了缓存过期后的击穿问题,但没有解决数据未预热场景下,突然流量导致的击穿问题。因此未来还需要实现预热能力,通过定时任务对数据库中可能为热点数据的记录做预热,提前加载到远端缓存中,防止突发流量击穿。