谈谈缓存穿透雪崩和过载保护以及一致性等问题
本来很早就想记录一下这方面的问题,后来看到skynet中消息队列的过载保护处理以及目前项目中的考虑到的问题,于是就花些时间整理并系统的学习下这方面的知识。
目前skynet中的消息队列是无界的,不会出现消息丢失,乱序等问题,反而是上层业务逻辑处理不当,可能造成消息的乱序或者把重要的请求消息丢失。但是这样带来的问题是如果某个业务把线程卡死导致某个服务队列的消息堆积,造成内存耗尽或者进程被kill引起严重问题怎么办?再或者有些消息不及时处理导致超时,客户端重传,再超时,后台业务处理的消息要么都是超时的要么都是没啥用的。
一般游戏中都会有监控逻辑,达到阀值会警告或者强制处理,再或者配个高优先级队列,先处理优先级高的消息。再或者排队处理,比如游戏中的登陆,一秒登陆五十个玩家,如果一开服涌入大批玩家,一方面可能造成卡顿对用户体验不是很好,另一方面可能造成登陆失败等其他问题。如果不作些特殊处理,那么当后台业务进程处理到这些消息时,可能玩家早就跑了,此时处理的消息都没啥用。
这里不会解释消息的乱序,协程并发相关的问题,这方面的细节会在第三篇skynet源码分析中说明。也不解释缓存/内存一致性模型,这里分析是如redis进程级别的缓存,介于如mysql和上游业务server之间,缓存热点数据,或者消息之类的作用。
这里整理下以前看过的资料,会简单介绍下每个的具体含义以及相关的可行方案,毕竟这些并不是什么新鲜的技术,固定的几种。
缓存雪崩
当我们要查一个以key为键的值时,比如游戏排行榜中的玩家数据 ,一般以userid为key存储简要数据,玩家创建的时候会同步一些数据到cache中,比如这里cache由redis来处理,有数据更新时咱们先更新db,再更新cache,假设都成功,因为查cache数据时,有点延迟或不一致都没多大问题。这时由于cache进程一般和具体的场景功能是解耦的,作为独立进程存在。假设在如下情况下,一万个玩家拉取到某一页的排行简要数据,比如排名,角色id,姓名等,此时cache进程挂了,然后一万个玩家点具体的排名玩家时需要显示更为详细的信息比如装备和属性数据时,场景进程转发读cache请求,此时cache进程刚重启,那么所有的请求都落到了db那边,造成了一定的压力,当然这里的请求量不多,这就是缓存雪崩。简言之就是“当缓存服务器重启或者大量缓存集中在某一个时间段失效,这样在失效的时候,也会给后端系统带来很大压力。”
一般业务中有些功能需求是要设置超时时间的,如果对精确性不作过多要求,比如晚一秒或早一秒超时是没多大关系的,那么可以把集中超时改为分散超时这样。
也可以如缓存穿透做法,当请求量过来时,当cache数据失效时,先设置个无效值,然后放行这个请求到db查询,回来时,更新cache,而其他请求则直接查cache,发现是无效值则返回client并且可以重试等处理。
当然还有其他做法比如加锁key的查询。
缓存穿透
这个情况是查证的key压根就不存在,导致所有请求都流到db那边,造成压力。这里可以设置个特殊值到cache,并设置个超时时间,这样所有的请求都落到cache这边。
还有缓存击穿的概念,其实解决办法同上面类似或综合一下,这里不作分析。
过载保护
在游戏业务中,一般会为每个client连接配置收发消息队列,以前经历过的项目是这样的情况,但由于代码实现原理看不到,只有大概设计文档,实现貌似是一收一发环形数组队列,放在共享内存中,当消息过多时,防止溢出会丢失,不处理的,然后由客户端重传,但是这里还是有些问题的。
然后目前项目是用的skynet框架,开源的,底层实现对于收消息,是放入对应服务消息队列并等待工作线程调度,会一直收,并没有容量限制,当然这里会有问题。然后由上层实现来处理收到的消息,如果处理过慢,导致队列中的消息来不及处理并超时,那么后台服务就会做些无用功等。但是发是直接关联socket buffer的待发列表,前面的文章也分析过。相关的会在「浅析skynet底层框架下篇」中介绍。
合理的估计服务进程的能力需要多方面考虑,以下几篇腾讯wetest的分析说的挺好的,然后百度brpc也有类似的方案,这里我没有作过多的研究,这小节大概就简单介绍。
缓存与DB的一致性
以上都是基于请求查询的业务,没有设计到写请求,当并发量上来时很容易出现问题。这里举例A和B分别为读写请求,然后落到业务进程server这边,后台服务有个mysql和redis作为缓存,那么怎么处理会比较好些呢?
如果参考到MESI协议,如当core 1的cache状态为s时,如果进行本地写,那么其他core的cache控制器监听到信号时,会更新cache的状态为i,并invalid自己cache的数据,core 1并在一定的时间后刷新到内存。然后回到这里,一般最佳做法是先更新db,再淘汰cache,其他的方式都不合理,如可能查的是旧数据等。考虑到一些失败等情况,这里没有具体涉及,建议参考下面的资料缓存更新的套路。
以下是参考资料
服务器过载保护(上篇)——过载介绍
服务器过载保护(下篇)——过载处理新方案
腾讯后台开发技术总监浅谈过载保护 小心雪崩效应
缓存一致性,缓存穿透,缓存击穿,缓存雪崩解决方案分析
缓存/内存Coherence模型
如何解决微服务架构中的雪崩问题?
Cache应用中的服务过载案例研究
缓存更新的套路
缓存穿透与缓存雪崩
缓存穿透、缓存并发、缓存失效之思路变迁
缓存系列文章
高并发热点缓存数据可能出现问题及解决方案
再谈缓存穿透、缓存并发、热点缓存之最佳招式