提前排雷!分布式缓存的25个优秀实践与线上案例

2019-09-10 15:59:12 采集侠

作者介绍
杨彪,蚂蚁金服技术专家,《分布式服务架构:原理、设计与实战》和《可伸缩服务架构:框架与中间件》作者。近10年互联网和游戏行业工作经验,曾在酷我音乐盒、人人游戏和掌趣科技等上市公司担任核心研发职位,做过日活跃用户量达千万的项目,也做过多款月流水千万以上的游戏。
本文节选自即将出版的《可伸缩服务架构:框架与中间件》一书,作者:李艳鹏、杨彪、李海亮、贾博岩、刘淏

本文主要介绍使用分布式缓存的优秀实践和线上案例。这些案例是笔者在多家互联网公司里积累并形成的优秀实践,能够帮助大家在生产实践中避免很多不必要的生产事故。

一、缓存设计的核心要素

我们在应用中决定使用缓存时,通常需要进行详细的设计,因为设计缓存架构看似简单,实则不然,里面蕴含了很多深奥的原理,如果使用不当,则会造成很多生产事故甚至是服务雪崩之类的严重问题。

笔者在做设计评审的过程中,总结了所有与缓存设计相关的设计点,这里列出来供大家参考。

1、容量规划

缓存内容的大小

缓存内容的数量

淘汰策略

缓存的数据结构

每秒的读峰值

每秒的写峰值

2、性能优化

线程模型

预热方法

缓存分片

冷热数据的比例

3、高可用

复制模型

失效转移

持久策略

缓存重建

4、缓存监控

缓存服务监控

缓存容量监控

缓存请求监控

缓存响应时间监控

5、注意事项

是否有可能发生缓存穿透

是否有大对象

是否使用缓存实现分布式锁

是否使用缓存支持的脚本(Lua)

是否避免了Race Condition

笔者在这里把这些设计点提供给读者,请读者在做缓存设计时把每一项作为一个思考的起点,思考我们在设计缓存时是否想到了这些点,以避免在设计的过程中因忽略某一项而导致严重的线上事故发生。

二、缓存设计的优秀实践

笔者在做设计评审的过程中,总结了一些开发人员在设计缓存系统时的优秀实践,如下所述:

优秀实践1

缓存系统主要消耗的是服务器的内存,因此,在使用缓存时必须先对应用需要缓存的数据大小进行评估,包括缓存的数据结构、缓存大小、缓存数量、缓存的失效时间,然后根据业务情况自行推算在未来一定时间内的容量的使用情况,根据容量评估的结果来申请和分配缓存资源,否则会造成资源浪费或者缓存空间不够。

优秀实践2

建议将使用缓存的业务进行分离,核心业务和非核心业务使用不同的缓存实例,从物理上进行隔离,如果有条件,则请对每个业务使用单独的实例或者集群,以减小应用之间互相影响的可能性。笔者就经常听说有的公司应用了共享缓存,造成缓存数据被覆盖以及缓存数据错乱的线上事故。

优秀实践3

根据缓存实例提供的内存大小推算应用需要使用的缓存实例数量,一般在公司里会成立一个缓存管理的运维团队,这个团队会将缓存资源虚拟成多个相同内存大小的缓存实例。

例如一个实例有4GB内存,在应用申请时可以按需申请足够的实例数量来使用,对这样的应用需要进行分片,详情请参考《可伸缩服务架构:框架与中间件》中4.4.3的内容。这里需要注意,如果我们使用了RDB备份机制,每个实例使用4GB内存,则我们的系统需要大于8GB内存,因为RDB备份时使用了 copy-on-write 机制,需要fork出一个子进程,并且复制一份内存,因此需要双份的内存存储大小。

优秀实践4

缓存一般是用来加速数据库的读操作的,一般先访问缓存后访问数据库,所以缓存的超时时间的设置是很重要的。笔者曾经在一家互联网公司遇到过由于运维操作失误导致缓存超时设置得较长,从而拖垮服务的线程池,最终导致服务雪崩的情况。

优秀实践5

所有的缓存实例都需要添加监控,这是非常重要的,我们需要对慢查询、大对象、内存使用情况做可靠的监控。

优秀实践6

我们不推荐多个业务共享一个缓存实例,但是由于成本控制的原因,这种情况经常出现,我们需要通过规范来限制各个应用使用的key有唯一的前缀,并进行隔离设计,避免产生缓存互相覆盖的问题。

优秀实践7

任何缓存的key都必须设定缓存失效时间,且失效时间不能集中在某一点,否则会导致缓存占满内存或者缓存雪崩。

优秀实践8

低频访问的数据不要放在缓存中,如我们前面所说的,我们使用缓存的主要目的是提高读取性能。