高并发场景缓存真的可靠吗?
有一定开发经验的研发人员都知道,缓存是高并发场景解决方案中的大杀器,应用中引入了缓存可以将大部分查询流量引入到缓存上,从而降低DB的qps来保护有限的底层存储资源。
缓存提供的核心的能力是查询高性能与承受高qps,一般是纯内存(jvm缓存)或类内存(redis)操作,缓存
使用流程大概如图:
- ①web层发起查询请求
- ②service层查询是否命中缓存
- ③如果命中直接返回结果
- ④如果没有命中则查询数据库并同步缓存然后返回
缓存的使用场景一般是字典数据或者热点数据,共同的特点是查询频率特别高,并且查询频率远大于更新频率,对于缓存的使用,大多数中小型应用使用以上图中所描述的链路基本不会存在什么问题,但是我们要思考一个问题,在并发很大的场景下,单纯的使用缓存来抵抗高qps真的可靠吗?
说到这个问题相信很多人想到的是缓存穿透、缓存雪崩等一系列的点,这些点都会导致缓存不命中使流量打到DB上,在并发足够大的情况下会打满所有连接池连接,新的请求无法处理,严重的情况可能拖垮数据库。
场景描述
在很多中小型企业,应用所用缓存平台都是自己搭建,有可能每个应用都有对应缓存服务器,但是像大的平台可能很多个应用公用缓存组件,比如阿里集团各个BU的应用基本上都接入Tair缓存:
基本上所有的应用的缓存数据都存放在Tair平台上,Tair每时每刻都承受着巨大的存储量和QPS。
抛出问题
在上边所描述的场景中,多个应用使用相同的缓存中间件,每个应用对缓存的依赖程度也各有差异,比如飞猪的量肯定没有天猫和淘宝大,那么缓存的QPS也必定没有两者高,站在缓存服务端的角度来看,我虽然是一个大的缓存集群,但是也并不意味着每个接入的应用拥有无限QPS访问和无限的带宽,那么再反过来站在应用端角度来思考,如果
我介入了一个缓存集群,但是缓存的QPS和带宽都有上限,那么当我应用的并发量足够大的时候,QPS或者带宽超过限制的时候,那将意味着超过限制的部分流量无法命中缓存,会继续打在DB上,如果底层是单库单表,很容易就打挂了。
如图所示,当我们并发量很大超过缓存QPS限制或者传输数量比较大超过缓存允许带宽的时候,仍会有一部分流量不命中缓存,会直接走DB查询,那么如果访问瞬时流量暴增,比如双十一凌晨的时候,和十二号退款功能打开的时候,都会带来巨大的瞬时流量,如果我们对大促的流量预估不够精确和宽松,和前期压测结果对QPS承受能力评估不准确,那么很可能在流量暴增的时候,由于QPS过大触发缓存限流,导致查询直接走DB,拖垮数据库和应用服务器。
引发思考
相信此时大家心里都应该有了一些想法,就是说在平台大促期间,高并发问题并不能单纯的通过缓存来解决,当然我们站在使用者的来讲,我们不希望看到的是缓存对应用做限制,更希望缓存平台增加机器扩充带宽来满足绝大多数使用者的需求,但是往往事与愿违,这种理想的状态连阿里这种体量的平台都没有做到,相信国内其他中小企业也基本上不会尝试这么做,那么既然问题知道了,现状就是这样,我们当然要考虑这种极端场景的解决方案,那就是高并发场景的另外一个大杀器--限流。
限流是针对当前应用服务器的处理能力,限制并发访问量,其实是对应用和服务器的一种保护机制,可以单独使用也可以结合缓存一起使用,在上面我们面临的问题中,我们引入限流会很完美的解决问题,可以考虑在qps很高的接口上添加限流,限流指数需要参考缓存的qps限制和带宽限制,超过缓存QPS限制部分流量直接被限流限掉,这样我们就能够在充分利用缓存的前提下有效的保护我们的底层DB和服务器。
在此处输入标题
在互联网大环境中,很多复杂的场景并不能单纯的依靠一种手段来做到尽善尽美,有时候几种技术实现融合到一起能够更好地解决问题,对于本篇所讲述的高并发场景下,单纯的依靠缓存来解决高QPS问题其实是不可靠的,因为缓存实现层也不是无限的资源,这种情况下就需要根据应用服务器的承受能力,数据库层的处理能力以及缓存层的QPS流量限制,来对应用的处理能力做一个合理的评估,然后对超过处理能力的部分流量丢弃或者说削峰处理。
天冷了,记得穿秋裤。