高并发场景下的缓存有哪些常见的问题?

分布式缓存重建并发冲突解决方案

对于缓存生产服务,可能部署在多台机器,当redis和ehcache对应的缓存数据都过期不存在时,此时可能nginx过来的请求和kafka监听的请求同时到达,导致两者最终都去拉取数据并且存入redis中,因此可能产生并发冲突的问题,可以采用redis或者zookeeper类似的分布式锁来解决,让请求的被动缓存重建与监听主动的缓存重建操作避免并发的冲突,当存入缓存的时候通过对比时间字段废弃掉旧的数据,保存最新的数据到缓存

缓存一致性问题

当数据时效性要求很高时,需要保证缓存中的数据与数据库中的保持一致,而且需要保证缓存节点和副本中的数据也保持一致,不能出现差异现象。

这就比较依赖缓存的过期和更新策略。一般会在数据发生更改的时,主动更新缓存中的数据或者移除对应的缓存。

缓存并发

缓存过期后将尝试从后端数据库获取数据,这是一个看似合理的流程。但是,在高并发场景下,有可能多个请求并发的去从数据库获取数据,对后端数据库造成极大的冲击,甚至导致 “雪崩”现象。

此外,当某个缓存key在被更新时,同时也可能被大量请求在获取,这也会导致一致性的问题。那如何避免类似问题呢?

我们会想到类似“锁”的机制,在缓存更新或者过期的情况下,先尝试获取到锁,当更新或者从数据库获取完成后再释放锁,其他的请求只需要牺牲一定的等待时间,即可直接从缓存中继续获取数据。

缓存穿透

缓存穿透是指缓存没有发挥作用,业务系统虽然去缓存查询数据,但缓存中没有数据,业务系统需要再次去存储系统查询数据。通常情况下有两种情况:

1. 存储数据不存在

第一种情况是被访问的数据确实不存在。一般情况下,如果存储系统中没有某个数据,则不会在缓存中存储相应的数据,这样就导致用户查询的时候,在缓存中找不到对应的数据,每次都要去存储系统中再查询一遍,然后返回数据不存在。缓存在这个场景中并没有起到分担存储系统访问压力的作用。

通常情况下,业务上读取不存在的数据的请求量并不会太大,但如果出现一些异常情况,例如被黑客攻击,故意大量访问某些读取不存在数据的业务,有可能会将存储系统拖垮。

这种情况的解决办法比较简单,如果查询存储系统的数据没有找到,则直接设置一个默认值(可以是空值,也可以是具体的值)存到缓存中,这样第二次读取缓存时就会获取到默认值,而不会继续访问存储系统。

2. 缓存数据生成耗费大量时间或者资源

第二种情况是存储系统中存在数据,但生成缓存数据需要耗费较长时间或者耗费大量资源。如果刚好在业务访问的时候缓存失效了,那么也会出现缓存没有发挥作用,访问压力全部集中在存储系统上的情况。

典型的就是电商的商品分页,假设我们在某个电商平台上选择“手机”这个类别查看,由于数据巨大,不能把所有数据都缓存起来,只能按照分页来进行缓存,由于难以预测用户到底会访问哪些分页,因此业务上最简单的就是每次点击分页的时候按分页计算和生成缓存。通常情况下这样实现是基本满足要求的,但是如果被竞争对手用爬虫来遍历的时候,系统性能就可能出现问题。

具体的场景有:

分页缓存的有效期设置为 1 天,因为设置太长时间的话,缓存不能反应真实的数据。

通常情况下,用户不会从第 1 页到最后 1 页全部看完,一般用户访问集中在前 10 页,因此第 10 页以后的缓存过期失效的可能性很大。

竞争对手每周来爬取数据,爬虫会将所有分类的所有数据全部遍历,从第 1 页到最后 1 页全部都会读取,此时很多分页缓存可能都失效了。

由于很多分页都没有缓存数据,从数据库中生成缓存数据又非常耗费性能(order by limit 操作),因此爬虫会将整个数据库全部拖慢

这种情况并没有太好的解决方案,因为爬虫会遍历所有的数据,而且什么时候来爬取也是不确定的,可能是每天都来,也可能是每周,也可能是一个月来一次,我们也不可能为了应对爬虫而将所有数据永久缓存。通常的应对方案要么就是识别爬虫然后禁止访问,但这可能会影响 SEO 和推广;要么就是做好监控,发现问题后及时处理,因为爬虫不是攻击,不会进行暴力破坏,对系统的影响是逐步的,监控发现问题后有时间进行处理。

缓存雪崩是指当缓存失效(过期)后引起系统性能急剧下降的情况。当缓存过期被清除后,业务系统需要重新生成缓存,因此需要再次访问存储系统,再次进行运算,这个处理步骤耗时几十毫秒甚至上百毫秒。而对于一个高并发的业务系统来说,几百毫秒内可能会接到几百上千个请求。由于旧的缓存已经被清除,新的缓存还未生成,并且处理这些请求的线程都不知道另外有一个线程正在生成缓存,因此所有的请求都会去重新生成缓存,都会去访问存储系统,从而对存储系统造成巨大的性能压力。这些压力又会拖慢整个系统,严重的会造成数据库宕机,从而形成一系列连锁反应,造成整个系统崩溃。

缓存雪崩的常见解决方法有两种:更新锁机制后台更新机制

1. 更新锁

对缓存更新操作进行加锁保护,保证只有一个线程能够进行缓存更新,未能获取更新锁的线程要么等待锁释放后重新读取缓存,要么就返回空值或者默认值

对于采用分布式集群的业务系统,由于存在几十上百台服务器,即使单台服务器只有一个线程更新缓存,但几十上百台服务器一起算下来也会有几十上百个线程同时来更新缓存,同样存在雪崩的问题。因此分布式集群的业务系统要实现更新锁机制,需要用到分布式锁,如 ZooKeeper

2. 后台更新

由后台线程来更新缓存,而不是由业务线程来更新缓存,缓存本身的有效期设置为永久,后台线程定时更新缓存。

后台定时机制需要考虑一种特殊的场景,当缓存系统内存不够时,会“踢掉”一些缓存数据,从缓存被“踢掉”到下一次定时更新缓存的这段时间内,业务线程读取缓存返回空值,而业务线程本身又不会去更新缓存,因此业务上看到的现象就是数据丢了。解决的方式有两种:

后台线程除了定时更新缓存,还要频繁地去读取缓存(例如,1 秒或者 100 毫秒读取一次),如果发现缓存被“踢了”就立刻更新缓存,这种方式实现简单,但读取时间间隔不能设置太长,因为如果缓存被踢了,缓存读取间隔时间又太长,这段时间内业务访问都拿不到真正的数据而是一个空的缓存值,用户体验一般。

业务线程发现缓存失效后,通过消息队列发送一条消息通知后台线程更新缓存。可能会出现多个业务线程都发送了缓存更新消息,但其实对后台线程没有影响,后台线程收到消息后更新缓存前可以判断缓存是否存在,存在就不执行更新操作。这种方式实现依赖消息队列,复杂度会高一些,但缓存更新更及时,用户体验更好

后台更新既适应单机多线程的场景,也适合分布式集群的场景,相比更新锁机制要简单一些。

后台更新机制还适合业务刚上线的时候进行缓存预热。缓存预热指系统上线后,将相关的缓存数据直接加载到缓存系统,而不是等待用户访问才来触发缓存加载。

缓存热点

虽然缓存系统本身的性能比较高,但对于一些特别热点的数据,如果大部分甚至所有的业务请求都命中同一份缓存数据,则这份数据所在的缓存服务器的压力也很大。例如,某明星微博发布“我们”来宣告恋爱了,短时间内上千万的用户都会来围观。

缓存热点的解决方案就是复制多份缓存副本,将请求分散到多个缓存服务器上,减轻缓存热点导致的单台缓存服务器压力。以微博为例,对于粉丝数超过 100 万的明星,每条微博都可以生成 100 份缓存,缓存的数据是一样的,通过在缓存的 key 里面加上编号进行区分,每次读缓存时都随机读取其中某份缓存。

缓存副本设计有一个细节需要注意,就是不同的缓存副本不要设置统一的过期时间,否则就会出现所有缓存副本同时生成同时失效的情况,从而引发缓存雪崩效应。正确的做法是设定一个过期时间范围,不同的缓存副本的过期时间是指定范围内的随机值。

实现方式

由于缓存的各种访问策略和存储的访问策略是相关的,因此上面的各种缓存设计方案通常情况下都是集成在存储访问方案中,可以采用“程序代码实现”的中间层方式,也可以采用独立的中间件来实现。

欢迎关注、留言。转发~~

 在此我向大家推荐一个架构学习交流群。交流学习群号:938837867 里面会分享一些资深架构师录制的视频录像:有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化、分布式架构等这些成为架构师必备的知识体系。还能领取免费的学习资源,目前受益良多

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,723评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,003评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,512评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,825评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,874评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,841评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,812评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,582评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,033评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,309评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,450评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,158评论 5 341
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,789评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,409评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,609评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,440评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,357评论 2 352

推荐阅读更多精彩内容