Redis架构设计

293 阅读2分钟

这是我参与11月更文挑战的第15天,活动详情查看:2021最后一次更文挑战

缓存穿透

高并发下查询key不存在的数据,每次针对此key的请求从缓存获取不到, 穿过缓存查询数据库, 导致数据库压力过大而宕机。

解决方案:

  • 对查询结果为空的情况也进行缓存,ttl设置短一点
  • 使用布隆过滤器

缓存击穿

一个热key失效,key对应的数据存在,但在redis中过期,此时若有大量并发请求过来,这些请求发现缓存过期一般都会从后端数据库加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把后端数据库压垮

解决方案:

  • 不设置超时时间的同时选择volatile-lru淘汰策略

缓存血崩

当缓存服务器重启或大量缓存集中在某个时间段失效

解决方案:

  • key 失效期分开
  • 二级缓存
  • 高可用(脏读)

数据不一致

延时双删

  • 先更新数据库同时删除缓存
  • 2秒后再删除一次缓存
  • 设置缓存过期时间
  • 将缓存删除记录到日志,利用脚本提取记录再次删除

数据并发竞争

多个redisclient同时set同一个key引起的并发问题。有两种方案解决:

  • 分布式锁+ 时间戳
  • 消息队列

Hot Key

如何发现热key

  • 预估热key
  • 在客户端进行统计
  • 在proxy端收集
  • 使用monitor, hotkeys
  • 利用storm, Spark Streaming, Flink等中间件

处理方案:

  • 分布式缓存为本地缓存
  • 在每个redis上备份热key, 随机读取
  • 使用限流熔断保护措施

Big Key

大Key会大量占用内存,性能下降,主从复制异常,删除时会引起服务阻塞

发现方案:

  • redis-cli --bigkeys
  • 获取rdb文件,通过rdbtools分析rdb生成csv

处理方案:

  • String 类型不要存redis,存mongodb或CDB, 单个简单key存储value很大,可以拆分
  • 将hash set zset list 拆分
  • 删除大key不要使用del, del 阻塞命令
  • 使用lazy delete(unlink命令)

乐观锁

  • watch监控key的状态值
  • 获取Key的值
  • 创建事务
  • value +1
  • 执行事务,如果key被修改过,回滚

Redisson 的分布式锁属于乐观锁

悲观锁

setnx 如果需要实现悲观锁,需要setnx expire lua等结合使用,自己编写相应悲观锁代码。