Redis架构之防雪崩设计:网站不宕机背后的兵法

Redis架构之防雪崩设计:网站不宕机背后的兵法

原创: 付磊,张益军 高可用架构 2017-03-24

导读:互联网系统中不可避免要大量用到缓存,在缓存的使用过程中,架构师需要注意哪些问题?本文以 Redis 为例,详细探讨了最关键的 3 个问题。

一、缓存穿透预防及优化

缓存穿透是指查询一个根本不存在的数据,缓存层和存储层都不会命中,但是出于容错的考虑,如果从存储层查不到数据则不写入缓存层,如图 11-3 所示整个过程分为如下 3 步:

  1. 缓存层不命中
  2. 存储层不命中,所以不将空结果写回缓存
  3. 返回空结果

缓存穿透将导致不存在的数据每次请求都要到存储层去查询,失去了缓存保护后端存储的意义。

缓存穿透模型

缓存穿透问题可能会使后端存储负载加大,由于很多后端存储不具备高并发性,甚至可能造成后端存储宕掉。通常可以在程序中分别统计总调用数、缓存层命中数、存储层命中数,如果发现大量存储层空命中,可能就是出现了缓存穿透问题。

造成缓存穿透的基本有两个。第一,业务自身代码或者数据出现问题,第二,一些恶意攻击、爬虫等造成大量空命中,下面我们来看一下如何解决缓存穿透问题。

缓存穿透的解决方法

1)缓存空对象

如下图所示,当第 2 步存储层不命中后,仍然将空对象保留到缓存层中,之后再访问这个数据将会从缓存中获取,保护了后端数据源。

缓存空值应对穿透问题

缓存空对象会有两个问题:

第一,空值做了缓存,意味着缓存层中存了更多的键,需要更多的内存空间 ( 如果是攻击,问题更严重 ),比较有效的方法是针对这类数据设置一个较短的过期时间,让其自动剔除。

第二,缓存层和存储层的数据会有一段时间窗口的不一致,可能会对业务有一定影响。例如过期时间设置为 5 分钟,如果此时存储层添加了这个数据,那此段时间就会出现缓存层和存储层数据的不一致,此时可以利用消息系统或者其他方式清除掉缓存层中的空对象。

下面给出了缓存空对象的实现伪代码:

2)布隆过滤器拦截

如下图所示,在访问缓存层和存储层之前,将存在的 key 用布隆过滤器提前保存起来,做第一层拦截。例如: 一个个性化推荐系统有 4 亿个用户 ID,每个小时算法工程师会根据每个用户之前历史行为做出来的个性化放到存储层中,但是最新的用户由于没有历史行为,就会发生缓存穿透的行为,为此可以将所有有个性化推荐数据的用户做成布隆过滤器。如果布隆过滤器认为该用户 ID 不存在,那么就不会访问存储层,在一定程度保护了存储层。

开发提示:

有关布隆过滤器的相关知识,可以参考: https://en.wikipedia.org/wiki/Bloom_filter

可以利用 Redis 的 Bitmaps 实现布隆过滤器,GitHub 上已经开源了类似的方案,读者可以进行参考:

https://github.com/erikdubbelboer/Redis-Lua-scaling-bloom-filter

使用布隆过滤器应对穿透问题

这种方法适用于数据命中不高,数据相对固定实时性低(通常是数据集较大)的应用场景,代码维护较为复杂,但是缓存空间占用少。

两种方案对比

前面介绍了缓存穿透问题的两种解决方法 ( 实际上这个问题是一个开放问题,有很多解决方法 ),下面通过下表从适用场景和维护成本两个方面对两种方案进行分析。

缓存空对象和布隆过滤器方案对比

 二、缓存雪崩问题优化

从下图可以很清晰出什么是缓存雪崩:由于缓存层承载着大量请求,有效的保护了存储层,但是如果缓存层由于某些原因整体不能提供服务,于是所有的请求都会达到存储层,存储层的调用量会暴增,造成存储层也会挂掉的情况。 缓存雪崩的英文原意是 stampeding herd(奔逃的野牛),指的是缓存层宕掉后,流量会像奔逃的野牛一样,打向后端存储。

缓存层不可用引起的雪崩

预防和解决缓存雪崩问题,可以从以下三个方面进行着手。

1)保证缓存层服务高可用性。

和飞机都有多个引擎一样,如果缓存层设计成高可用的,即使个别节点、个别机器、甚至是机房宕掉,依然可以提供服务,例如前面介绍过的 Redis Sentinel 和 Redis Cluster 都实现了高可用。

2)依赖隔离组件为后端限流并降级。

无论是缓存层还是存储层都会有出错的概率,可以将它们视同为资源。作为并发量较大的系统,假如有一个资源不可用,可能会造成线程全部 hang 在这个资源上,造成整个系统不可用。降级在高并发系统中是非常正常的:比如推荐服务中,如果个性化推荐服务不可用,可以降级补充热点数据,不至于造成前端页面是开天窗。

在实际项目中,我们需要对重要的资源 ( 例如 Redis、 MySQL、 Hbase、外部接口 ) 都进行隔离,让每种资源都单独运行在自己的线程池中,即使个别资源出现了问题,对其他服务没有影响。但是线程池如何管理,比如如何关闭资源池,开启资源池,资源池阀值管理,这些做起来还是相当复杂的,这里推荐一个 Java 依赖隔离工具 Hystrix(https://github.com/Netflix/Hystrix),如下图所示。

Hystrix 是解决依赖隔离的利器,但是该内容已经超出本书的范围,同时只适用于 Java 应用,所以这里不会详细介绍。

Hystrix 示意图

3)提前演练。在项目上线前,演练缓存层宕掉后,应用以及后端的负载情况以及可能出现的问题,在此基础上做一些预案设定。

三、缓存热点 key 重建优化

开发人员使用缓存 + 过期时间的策略既可以加速数据读写,又保证数据的定期更新,这种模式基本能够满足绝大部分需求。但是有两个问题如果同时出现,可能就会对应用造成致命的危害:

  • 当前 key 是一个热点 key( 例如一个热门的娱乐新闻),并发量非常大。
  • 重建缓存不能在短时间完成,可能是一个复杂计算,例如复杂的 SQL、多次 IO、多个依赖等。

在缓存失效的瞬间,有大量线程来重建缓存 ( 如下图),造成后端负载加大,甚至可能会让应用崩溃。

热点 key 失效后大量线程重建缓存

要解决这个问题也不是很复杂,但是不能为了解决这个问题给系统带来更多的麻烦,所以需要制定如下目标:

  • 减少重建缓存的次数
  • 数据尽可能一致
  • 较少的潜在危险

1)互斥锁 (mutex key)

此方法只允许一个线程重建缓存,其他线程等待重建缓存的线程执行完,重新从缓存获取数据即可,整个过程如图 11-17。

使用互斥锁重建缓存

下面代码使用 Redis 的 setnx 命令实现上述功能。

(1) 从 Redis 获取数据,如果值不为空,则直接返回值,否则执行 (2.1) 和 (2.2)。

(2) 如果 set(nx 和 ex) 结果为 true,说明此时没有其他线程重建缓存,那么当前线程执行缓存构建逻辑。

(2.2) 如果 setnx(nx 和 ex) 结果为 false,说明此时已经有其他线程正在执行构建缓存的工作,那么当前线程将休息指定时间 ( 例如这里是 50 毫秒,取决于构建缓存的速度 ) 后,重新执行函数,直到获取到数据。

2)永远不过期

“永远不过期”包含两层意思:

  • 从缓存层面来看,确实没有设置过期时间,所以不会出现热点 key 过期后产生的问题,也就是“物理”不过期。
  • 从功能层面来看,为每个 value 设置一个逻辑过期时间,当发现超过逻辑过期时间后,会使用单独的线程去构建缓存。

整个过程如下图所示:

" 永远不过期 " 策略

从实战看,此方法有效杜绝了热点 key 产生的问题,但唯一不足的就是重构缓存期间,会出现数据不一致的情况,这取决于应用方是否容忍这种不一致。下面代码使用 Redis 进行模拟:

作为一个并发量较大的应用,在使用缓存时有三个目标:第一,加快用户访问速度,提高用户体验。第二,降低后端负载,减少潜在的风险,保证系统平稳。第三,保证数据“尽可能”及时更新。下面将按照这三个维度对上述两种解决方案进行分析。

  • 互斥锁 (mutex key):这种方案思路比较简单,但是存在一定的隐患,如果构建缓存过程出现问题或者时间较长,可能会存在死锁和线程池阻塞的风险,但是这种方法能够较好的降低后端存储负载并在一致性上做的比较好。
  • " 永远不过期 ":这种方案由于没有设置真正的过期时间,实际上已经不存在热点 key 产生的一系列危害,但是会存在数据不一致的情况,同时代码复杂度会增大。

两种解决方法对比如下表所示。

两种热点 key 的解决方法

本文列举了缓存设计中最关键的 3 个问题,节选自机械工业出版社《Redis开发与运维》第 11 章。由机械工业出版社华章IT授权。基于移动阅读的考虑,部分内容进行了排版调整,想了解缓存设计及 Redis 开发与运维全部详细内容,可以在各大书店购买。

转自高可用架构公众号:

https://mp.weixin.qq.com/s/TBCEwLVAXdsTszRVpXhVug?

原文地址:https://www.cnblogs.com/lihaodonglala/p/11369254.html

时间: 2024-10-09 10:22:14

Redis架构之防雪崩设计:网站不宕机背后的兵法的相关文章

625某电商网站数据库宕机故障解决实录(上)

博客编辑器越来越用不好了,伙伴们将就看,需要排版更好的文档请加Q群246054962. 625某电商网站数据库特大故障解决实录(上) 这是一次,惊心动魄的企业级电商网站数据库在线故障解决实录,故障解决的过程遇到了很多问题,思想的碰撞,解决方案的决策,及实际操作的问题困扰,老男孩尽量原汁原味的描述恢复的全部过程及思想思维过程!老男孩教育版权所有,本内容禁止商业用途. 目录: 625某电商网站数据库特大故障解决实录... 1 1接到电商客户报警... 1 1.1与客户初步沟通... 1 1.2深入沟

625某电商网站数据库宕机故障解决实录(下)

1.4开始进行故障恢复***** 1.重新初始化建库 [[email protected] data]# mkdir mysql [[email protected] data]# chown -R mysql.mysql mysql [[email protected] data]# /install/mysql/scripts/mysql_install_db--basedir=/install/mysql/ --datadir=/data/mysql/ --user=mysql Insta

(转)625某电商网站数据库宕机故障解决实录(下)

1.4开始进行故障恢复***** 1.重新初始化建库 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 [[email protected] data]# mkdir mysql [[email protected] data]# chown -R mysql.mysql mysql [ro[email protected] data]# /install/mysql/sc

(转)625某电商网站数据库宕机故障解决实录(上)

625某电商网站数据库特大故障解决实录(上) 原文:http://oldboy.blog.51cto.com/2561410/1431161 这是一次,惊心动魄的企业级电商网站数据库在线故障解决实录,故障解决的过程遇到了很多问题,思想的碰撞,解决方案的决策,及实际操作的问题困扰,老男孩尽量原汁原味的描述恢复的全部过程及思想思维过程!老男孩教育版权所有,本内容禁止商业用途. 目录: 625某电商网站数据库特大故障解决实录... 1 1接到电商客户报警... 1 1.1与客户初步沟通... 1 1.

Redis的KEYS命令引起RDS数据库雪崩,RDS发生两次宕机,造成几百万的资金损失

最近的互联网线上事故发生比较频繁,20180919顺丰发生了一起线上删库事件,在这里就不介绍了. 在这里讲述一下最近发生在我公司的事故,以及如何避免,并且如何处理优化. 间接原因还有很多,技术跟不上业务的发展,由每日百万量到千万级是一个大的跨进,公司对于系统优化的处理优先级不高,技术开发人手的短缺 第一次宕机20180913某个点,公司某服务化项目的RDS实例连接飙升,CPU升到100%,拒绝了其他应用的所有请求服务整个过程如下: 监控报警,显示RDS的CPU使用率达到80%以上,DBA介入,准

细说分布式Redis架构设计和踩过的那些坑

摘要:本文章主要分成五个步骤内容讲解 Redis.RedisCluster和Codis; 我们更爱一致性; Codis在生产环境中的使用的经验和坑们; 对于分布式数据库和分布式架构的一些看法; Q & A环节. Codis是一个分布式Redis解决方案,与官方的纯P2P的模式不同,Codis采用的是Proxy-based的方案.今天我们介绍一下Codis及下一个大版本RebornDB的设计,同时会介绍一些Codis在实际应用场景中的tips.最后抛砖引玉,会介绍一下我对分布式存储的一些观点和看法

[转载] Codis作者黄东旭细说分布式Redis架构设计和踩过的那些坑们

原文: http://mp.weixin.qq.com/s?__biz=MzAwMDU1MTE1OQ==&mid=208733458&idx=1&sn=691bfde670fb2dd649685723f7358fea&scene=1&key=c76941211a49ab58cb17c68ecaeeda0f1c083d9508a0f6629461fff9025fd87de4706bd9c1730e0ddbab70568b34b16a&ascene=0&

Nginx+Lua+Redis整合实现高性能API接口 - 网站服务器 - LinuxTone | 运维专家网论坛 - 最棒的Linux运维与开源架构技术交流社区! - Powered by Discuz!

Nginx+Lua+Redis整合实现高性能API接口 - 网站服务器 - LinuxTone | 运维专家网论坛 - 最棒的Linux运维与开源架构技术交流社区! - Powered by Discuz! log.latermoon.com/

Codis作者黄东旭细说分布式Redis架构设计和踩过的那些坑们

本次分享的内容主要包括五个大部分: Redis.RedisCluster和Codis; 我们更爱一致性; Codis在生产环境中的使用的经验和坑们; 对于分布式数据库和分布式架构的一些看法; Q & A环节. ??Codis是一个分布式Redis解决方案,与官方的纯P2P的模式不同,Codis采用的是Proxy-based的方案.今天我们介绍一下Codis及下一个大版本RebornDB的设计,同时会介绍一些Codis在实际应用场景中的tips.最后抛砖引玉,会介绍一下我对分布式存储的一些观点和看