TT Lab
开始
学习 学习路径 课程

Redis 与缓存

操作 Redis 的数据结构

在 TT Lab 中继续学习

目标

按各自的用途使用 Redis 的六种数据结构,并亲手练熟生产环境中绝对不能用的命令及其替代方案。

为什么重要

只把 String 当作 Redis 用的代码到处都是:全部序列化成 JSON 存进去、再取出来。这样能跑,但哪怕只想改一个字段,也得读出整体、解析、再写回去,而如果两个请求同时这样做,其中一个就会悄悄地把另一个覆盖掉。用 Hash 的话,单个字段就能以原子方式修改。光是选对一种数据结构,就能消除一个竞争条件。此外,这个实验还有一点必须刻在脑子里——Redis 以单线程处理命令,所以一个 O(N) 的命令就会造成全面停顿。在拥有数百万个键的实例上,一次 KEYS * 就会让所有请求停上好几秒。第 7 步中的 SCAN 就是为此而存在的。

步骤

  1. 把 redis-cli PING 的结果保存到 /root/rd/ping.txt。
  2. 让 app:hits 增加 3 次。值必须是 3。
  3. 在 user:42 这个 Hash 中放入 name、email、plan 三个字段。HLEN user:42 的结果是 3。
  4. 往 feed:42 这个 List 中放入 12 条动态,并裁剪成只保留最近的 10 条。LLEN feed:42 的结果是 10。
  5. 创建 tag:redis 和 tag:cache 两个集合,把交集保存到 /root/rd/inter.txt。交集必须有 2 个元素。
  6. 往 score:game1 这个有序集合中放入 5 个带分数的成员。ZCARD 的结果是 5,ZSCORE score:game1 p3 的结果是 30。
  7. 用 /root/rd/scan.sh 通过 SCAN 找出所有匹配 user:* 模式的键,写入 /root/rd/scan.out。脚本中不能出现 KEYS 字符串。
  8. 在 /root/rd/mem.md 中创建一个 Markdown 表格。行标题是 string、hash、list、set、zset 五个,在 bytes 列中写入 MEMORY USAGE 的结果。

参考

确认连接

把 redis-cli PING 的结果保存到 /root/rd/ping.txt。

redis-cli 不带参数运行时是交互式的。在脚本中,把命令作为参数传入更好。

用 String 做计数器

让 app:hits 增加 3 次。值必须是 3。

递增命令即使键不存在,也会从 0 开始。它是原子的,这正是这种数据结构能做计数器的原因。

用 Hash 存储对象

在 user:42 这个 Hash 中放入 name、email、plan 三个字段。HLEN user:42 的结果是 3。

按字段存入和取出。想想这与把 JSON 整体存进去有什么不同。

用 List 保留最近的动态

往 feed:42 这个 List 中放入 12 条动态,并裁剪成只保留最近的 10 条。LLEN feed:42 的结果是 10。

新条目从前面放入,并把列表裁剪掉,使它不会变长。裁剪有专门的命令。

用 Set 求标签交集

创建 tag:redis 和 tag:cache 两个集合,把交集保存到 /root/rd/inter.txt。交集必须有 2 个元素。

有专门的命令用来求两个集合的共同元素。不要在应用里用循环去做。

用 ZSet 管理分数

往 score:game1 这个有序集合中放入 5 个带分数的成员。ZCARD 的结果是 5,ZSCORE score:game1 p3 的结果是 30。

分数和成员一起放入。放入之后,可以只查询某个成员的分数。

用 SCAN 代替 KEYS 来遍历

用 /root/rd/scan.sh 通过 SCAN 找出所有匹配 user:* 模式的键,写入 /root/rd/scan.out。脚本中不能出现 KEYS 字符串。

重复执行,直到游标回到 0。也有模式匹配的选项。

制作各数据结构的内存对比表

在 /root/rd/mem.md 中创建一个 Markdown 表格。行标题是 string、hash、list、set、zset 五个,在 bytes 列中写入 MEMORY USAGE 的结果。

把同样的数据用不同的结构存储,测出实际用量。有命令可以告诉你每个键的用量。