redis【集群 & 开发解决方案】

本贴最后更新于 247 天前,其中的信息可能已经沧海桑田

集群

1、简介

集群架构

集群作用

2、Redis 集群结构设计

数据存储设计

集群内部通讯设计

搭建 redis 集群参考:地址

企业级解决方案

1、缓存预热

问题排查

解决方案

总结

缓存预热就是系统启动前,提前将相关的缓存数据直接加载到缓存系统。避免在用户请求的时候,先查询数据库,然后再将数据缓存的问题!用户直接查询事先被预热的缓存数据

2、缓存雪崩

数据库服务器崩溃(1)

  1. 系统平稳运行过程中,忽然数据库连接量激增
  2. 应用服务器无法及时处理请求
  3. 大量 408,500 错误页面出现
  4. 客户反复刷新页面获取数据
  5. 数据库崩溃
  6. 应用服务器崩溃
  7. 重启应用服务器无效
  8. Redis 服务器崩溃
  9. Redis 集群崩溃
  10. 重启数据库后再次被瞬间流量放倒

问题排查

  1. 在一个较短的时间内,缓存中较多的 key 集中过期
  2. 此周期内请求访问过期的数据,redis 未命中,redis 向数据库获取数据
  3. 数据库同时接收到大量的请求无法及时处理
  4. Redis 大量请求被积压,开始出现超时现象
  5. 数据库流量激增,数据库崩溃
  6. 重启后仍然面对缓存中无数据可用
  7. Redis 服务器资源被严重占用,Redis 服务器崩溃
  8. Redis 集群呈现崩塌,集群瓦解
  9. 应用服务器无法及时得到数据响应请求,来自客户端的请求数量越来越多,应用服务器崩溃
  10. 应用服务器,redis,数据库全部重启,效果不理想

问题分析

解决方案(道)

  1. 更多的页面静态化处理
  2. 构建多级缓存架构 Nginx 缓存 +redis 缓存 +ehcache 缓存
  3. 检测 Mysql 严重耗时业务进行优化 对数据库的瓶颈排查:例如超时查询、耗时较高事务等
  4. 灾难预警机制 监控 redis 服务器性能指标
    • CPU 占用、CPU 使用率
    • 内存容量
    • 查询平均响应时间
    • 线程数
  5. 限流、降级 短时间范围内牺牲一些客户体验,限制一部分请求访问,降低应用服务器压力,待业务低速运转后再逐步放开访问

解决方案(术)

  1. LRU 与 LFU 切换
  2. 数据有效期策略调整
    • 根据业务数据有效期进行分类错峰,A 类 90 分钟,B 类 80 分钟,C 类 70 分钟
    • 过期时间使用固定时间 + 随机值的形式,稀释集中到期的 key 的数量
  3. 超热数据使用永久 key
  4. 定期维护(自动 + 人工) 对即将过期数据做访问量分析,确认是否延时,配合访问量统计,做热点数据的延时
  5. 加锁 慎用!

总结

缓存雪崩就是瞬间过期数据量太大,导致对数据库服务器造成压力。如能够有效避免过期时间集中,可以有效解决雪崩现象的出现 (约 40%),配合其他策略一起使用,并监控服务器的运行数据,根据运行记录做快速调整。

3、缓存击穿

数据库服务器崩溃(2)

  1. 系统平稳运行过程中
  2. 数据库连接量瞬间激增
  3. Redis 服务器无大量 key 过期
  4. Redis 内存平稳,无波动
  5. Redis 服务器 CPU 正常
  6. 数据库崩溃

问题排查

  1. Redis 中某个 key 过期,该 key 访问量巨大
  2. 多个数据请求从服务器直接压到 Redis 后,均未命中
  3. Redis 在短时间内发起了大量对数据库中同一数据的访问

问题分析

解决方案(术)

  1. 预先设定
    以电商为例,每个商家根据店铺等级,指定若干款主打商品,在购物节期间,加大此类信息 key 的过期时长
    注意:购物节不仅仅指当天,以及后续若干天,访问峰值呈现逐渐降低的趋势
  2. 现场调整
    • 监控访问量,对自然流量激增的数据延长过期时间或设置为永久性 key
  3. 后台刷新数据
    • 启动定时任务,高峰期来临之前,刷新数据有效期,确保不丢失
  4. 二级缓存
    • 设置不同的失效时间,保障不会被同时淘汰就行
  5. 加锁 分布式锁,防止被击穿,但是要注意也是性能瓶颈,慎重!

总结

缓存击穿就是单个高热数据过期的瞬间,数据访问量较大,未命中 redis 后,发起了大量对同一数据的数据库问,导致对数据库服务器造成压力。应对策略应该在业务数据分析与预防方面进行,配合运行监控测试与即时调整策略,毕竟单个 key 的过期监控难度较高,配合雪崩处理策略即可

恶意请求

我们的数据库中的主键都是从 0 开始的,即使我们将数据库中的所有数据都放到了缓存中。当有人用 id=-1 来发生恶意请求时,因为 redis 中没有这个数据,就会直接访问数据库,这就称谓缓存穿透

解决办法

布隆过滤器简介

想要尽量避免缓存穿透,一个办法就是对数据进行预校验,在对 Redis 和数据库进行操作前,**先检查数据是否存在,如果不存在就直接返回。**如果我们想要查询一个元素是否存在,要保证查询效率,可以选择 HashSet,但是如果有 10 亿个数据,都用 HashSet 进行存储,内存肯定是无法容纳的。这时就需要布隆过滤器了

布隆过滤器(英语:Bloom Filter)是 1970 年由布隆提出的。它实际上是一个很长的二进制向量(bit 数组)和一系列随机映射函数(hash)。布隆过滤器可以用于检索一个元素是否在一个集合中

因为是基于位数组和 hash 函数的,所以它的优点空间效率和查询时间都远远超过一般的算法。但缺点也很明显,那就是有一定的误识别率和删除困难。但是可以通过增加位数组的大小和增加 hash 函数个数来降低误识别率(只能降低,没法避免

放入过程

布隆过滤器初始化后,位数组中的值都为 0。当一个变量将要放入布隆过滤器时,会通过多个 hash 函数映射到位数组的各个位上,然后将对应位置为 1

查询过程

查询依然是通过多个 hash 函数映射到位数组的各个位上,如果各个位都为 1,说明该元素可能存在,注意是可能存在!!。但是如果通过映射后,位数组对应位上不为 1,那么该元素肯定不存在

放入过程图解

比如我们的布隆过滤器位一个 8 位的位数组,并且有 3 个 hash 函数对元素进行计算,映射到数组中的各个位上

我们将字符串”Nyima”放入布隆过滤器中

接下来将字符串”Cpower”放入布隆过滤器中

查询过程图解

比如我们要查询字符串”Cpower”是否存在,通过 3 个 hash 函数映射到了位数组的三个位置上, 三个位置都为 1,那么该字符串可能存在

比如我们要查询字符串”SWPU”是否存在,通过 3 个 hash 函数映射到了位数组的三个位置,发现有一个位置不为 1,那么该字符串肯定不存在

比如我们要查询字符串”Hulu”是否存在,通过 3 个 hash 函数映射到了位数组的三个位置,发现所有位置都为 1,但是我们前面并没有将字符串”Hulu”放入布隆过滤器中,所以这里发生了误判

增加位数组的大小和 hash 函数个数可以降低误判率,但是无法避免误判

转载地址,谢谢博主

  • Redis

    Redis 是一个开源的使用 ANSI C 语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value 数据库,并提供多种语言的 API。从 2010 年 3 月 15 日起,Redis 的开发工作由 VMware 主持。从 2013 年 5 月开始,Redis 的开发由 Pivotal 赞助。

    250 引用 • 244 回帖 • 568 关注

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...