前言
这是我参与「第五届青训营 」伴学笔记创作活动的第 17 天
今日学习内容:
- Redis 基本工作原理
- Redis 实际应用场景以及 Redis 常用数据结构
- Redis 使用注意事项
正文
什么是 Redis
为什么需要 Redis
- 数据从单表,演进出了分库分表
- MySQL 从单机演进出了集群
- 数据量增长
- 读写数据压力的不断增加
- 数据分冷热
- 冷数据:不常被访问到的数据
- 热数据:经常被访问到的数据,将热数据存储到内存中
Redis 基本工作原理
- 数据从内存中读写
- 数据保存到硬盘上防止重启数据丢失
- 增量数据保存到 AOF 文件
- 全量数据保存到 RDB 文件
- 单线程处理所有操作命令
Redis 应用案例
连续签到
数据结构 sds(Simple Dynamic String)
- 可以存储字符串、数字、二进制数据
- 通常和 expire 配合使用
- 场景:存储技术、Session
消息通知
用 list 作为消息队列
- 使用场景:消息通知,例如当文章更新时,将更新后的文章推送到 ES,用户就能搜索到最新的文章数据。
List 数据结构 - Quicklist
Quicklist 由一个双向链表和 listpack 实现
计数
如果一个用户有多项计数需求,可通过 hash 结构存储
Hash 数据结构 dict
排行榜
积分变化时,排名要实时变更
zset 数据结构 zskiplist (跳表)
限流
分布式锁
Redis 使用注意事项
大 key 的定义
| 数据类型 | 大 key 的标准 |
|---|---|
| String 类型 | value 的字节数大于 10 KB 即为大 key |
| Hash/Set/Zset/list 等复杂数据结构类型 | 元素个数大于 5000 个或总 value 字节数大于 10 MB 即为大 key |
大 key 的危害
- 读取成本高
- 容易导致慢查询(过期,删除)
- 主从复制异常,服务阻塞,无法正常响应请求
消除大 key 的方法
热 key 的定义
用户访问一个 key 的 QPS 特别高,导致 Server 实例出现 CPU 负载突增或者不均的情况。
热 key 没有明确的标准,QPS 超过 500 就有可能被识别为热 key。
解决热 key 的方法
- 设置 LocalCache
在访问 Redis 前,在业务服务侧设置 LocalCache,降低访问 Redis 的 QPS。LocalCache 中缓存过期或未命中,则从 Redis 中将数据更新到 LocalCache。Java 的 Guava、Golang 的 Bigcache 就是这类 LocalCache。
- 拆分
将 key:value 这一个热 key 复制写入多份,例如 key1:value,key2:value,访问的时候访问多个 key,但 value 是同一个,以此将 QPS 分散到不同实例上,降低负载。代价是,更新时需要更新多个 key,存在数据短暂不一致的风险。
- 使用 Redis 代理的热 key 承载能力
Redis 访问代理就具备热 key 承载能力,本质上是结合了 “热 key 发现”、“LocalCache” 两个功能
慢查询场景
容易导致 Redis 慢查询的操作:
- 批量操作一次性传入过多的 key/value,如 mset/hmset/sadd/zadd 等 O(n) 操作,建议单批次不要超过 100,超过 100 之后性能下降明显。
- zset 大部分命令都是 O(log(n)),当大小超过 5k 以上时,简单的 zadd/zrem 也可能导致慢查询
- 操作的单个 value 过大,超过 10KB。也即,避免使用大 key。
- 对大 key 的 delete/expire 操作也可能导致慢查询,Redis4.0 之前不支持异步删除 unlink,大 key 删除会阻塞 Redis
缓存穿透、缓存雪崩
- 缓存穿透:热点数据查询绕过缓存,直接查询数据库
- 缓存雪崩:大量缓存同时过期
缓存穿透的危害
(1)查询一个一定不存在的数据
通常不会缓存不存在的数据,这类查询请求都会直接达到 db,如果有系统 bug 或者人为攻击。
(2)缓存过期时
在高并发场景下,一个热 key 如果过期,会有大量请求同时击穿至 db,容易影响 db 性能和稳定。同一时间有大量 key 集中过期时,也会导致大量请求落到 db 上,导致查询变慢,甚至出现 db 无法响应新的查询。
如何减少缓存穿透
(1)缓存空值
如一个不存在的 userId。这个 userId 在缓存和数据库中都不存在,则可以缓存一个空值,下次再查询,直接返回缓存中的空值。
(2)布隆过滤器
通过 bloom filter 算法来存储合法 key,得益于该算法超高的压缩率,只需占用极小的空间就能存储大量 key 值。
如何避免缓存雪崩
(1)缓存空值
将缓存失效时间分散开,比如在原有的失效时间基础上增加一个随机值,例如不同 key 的过期时间,可以设置为 10 分 1 秒过期,10 分 20 秒过期,10 分 40 秒过期。时间的秒数部分就是随机时间,这样过期时间就分散了。对于热点数据,过期时间尽量设置得长一些,冷门的数据可以相对设置过期时间短一些。
(2)使用缓存集群,避免单机宕机造成的缓存雪崩