初识 Redis | 青训营笔记

35 阅读5分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 8 天

为什么需要 Redis?

  • 数据从单表,演进出了分库分表

  • MySQL从单机演进出了集群

    • 数据量增长

    • 读写数据压力的不断增加

一部分放到 Redis 中,一部分放到 Mysql中

  • 数据分冷热

    • 热数据: 经常被访问到的数据
  • 将热数据存储到内存中

Redis 基本工作原理

  • 数据从内存中读写
  • 数据保存到硬盘上防止重启数据丢失

增量数据保存到AOF文件

全量数据RDB文件

  • 单线程处理所有操作命令

Redis 的实际应用场景

    1. 连续签到

String 数据结构

数据结构 - sds

  • 可以存储 字符串、数字、二进制数据

  • 通常和expire配合使用

  • 场景: 存储计数、session

    1. 消息通知

用 list 作为消息队列

List 数据结构 Quicklist

Quicklist 由一个双向链表和 listpack实现。

    1. 计数
    1. 排行榜
    1. 限流
    1. 分布式锁

Redis 使用注意事项

大 Key、热 Key

大 Key

数据类型大 Key 标准
String 类型value 的字节数大于 10 kb 即为大 Key
Hash/Set/Zset/list 等复杂数据结构类型元素个数大于5000个或总 value 字节数大于 10MB 即为大key

大 Key 的危害

  • 读取成本高
  • 容易导致慢查询(过期、删除)
  • 主从复制异常,服务阻塞 无法正常响应请求

业务侧使用大Key的表现

  • 请求Redis超时报错

消除大 Key 的方法

  1. 拆分

将大key拆分为小key。例如一个String拆分成多个string

KeyValue
拆分前article:70011abodefghigklmnoparst
拆分后article:70011[3][70011]abcdefg
article:70011_2[70011]higklmn
article:70011_3[70011]opqrst
  1. 压缩

将 value 压缩后写入 redis。读取时解压后再使用。压缩算法可以是 gzip、snappy、Iz4 等。通常情况下,一个压缩算法压缩率高、则解压耗时就长。需要对实际数据进行测试后,选择一个合适的算法。如果存储的是 JSON 字符串,可以考虑使用MessagePack进行序列化。

  1. 集合类结构 hash、list、set、set

(1) 拆分: 可以用 hash 取余、位掩码的方式决定放在哪个key中。

(2) 区分冷热: 如榜单列表场景使用 zset,只缓存前 10 页数据,后续数据走 db。

热Key的定义

用户访问一个 Key 的 QPS 特别高,导致 Server 实例出现 CPU 负载突增或者不均的情况。热 key 没有明确的标准,QPS 超过 500 就有可能被识别为热Key。

解决热Key的方法

  1. 设置Localcache

在访问 Redis 前,在业务服务侧设置 Localcache。降低访问 Redis 的 QPS。LocalCache 中缓存过期或未命中,则从 Redis 中将数据更新到 LocalCache。 Java 的 Guava、Golang 的 Bigcache 就是这类 LocalCache。

  1. 拆分

将 key:value 这一个热 Key 复制写入多份,例如 key1:value, key2:value,访问的时候访问多个 key,但 value 是同一个以此将 qps 分散到不同实例上,降低负载。代价是,更新时需要更新多个 key,存在数据短暂不一致的风险。

慢查询场景

容易导致 redis 慢查询的操作

  • (1) 批量操作一次性传入过多的 key/value,如 mset/hmset/sadd/zadd 等O(n)操作

建议单批次不要超过100。超过 100 之后性能下降明显。

  • (2) zset 大部分命令都是 O(log(n)),当大小超过 5k 以上时,简单的zadd/zrem 也可能导致慢查询。
  • (3) 操作的单个 value 过大,超过 10KB。也即,避免使用大 Key
  • (4)对大 key 的 delete/expire 操作也可能导致慢查询,Redis4.0 之前不支持异步删除 unlink,大 key 删除会阻塞 Redis。

缓存穿透、缓存雪崩

  • 缓存穿透: 热点数据查询绕过缓存,直接查询数据库
  • 缓存雪崩: 大量缓存同时过期

缓存穿透的危害

  • (1) 查询一个一定不存在的数据

通常不会缓存不存在的数据,这类查询请求都会直接打到 db,如果有系统 bug 或人为攻击,那么容易导致 db 响应慢甚至宕机。

  • (2) 缓存过期时

在高并发场景下,一个热 key 如果过期,会有大量请求同时击穿至 db,容易影响 db 性能和稳定。

同一时间有大量 key 集中过期时,也会导致大量请求落到 db 上,导致查询变慢,甚至出现 db 无法响应新的查询。

如何减少缓存穿透

  • (1)缓存空值

如一个不存在的 userID。这个id在缓存和数据库中都不存在。则可以缓存一个空值,下次再查缓存直接反空值。

  • (2) 布降过滤器

通过 bloom filter 算法来存储合法 Key,得益于该算法超高的压缩率,只需占用极小的空间就能存储大量 key 值

如何避免缓存雪崩

  • (1) 缓存空值

将缓存失效时间分散开,比如在原有的失效时间基础上增加一个随机值,例如不同 Key 过期时间,可以设置为 10 分 1 秒过期,10 分 23 秒过期,10 分 8 秒过期。单位秒部分就是随机时间,这样过期时间就分散了对于热点数据,过期时间尽量设置得长一些,冷门的数据可以相对设置过期时间短一些。

  • (2)使用缓存集群,避免单机宕机造成的缓存雪崩。