string、hash 最多个 2^32 个 key。每个 key 最大 512MB,value 最大 512MB。
list、set、zset 最多 2^32 个元素。
1 string
1.1 使用场景
1.1.1 选举
- 节点抢占 leaderKey SET leaderKey hostId NX EX 30
- 节点每20秒查询一次 GET leaderKey
如果自己是 master,做一次续约 EXPIRE leaderKey 30
1.1.2 分布式锁
1.1.3 分布式ID
可以使用 INCR 每次自增1,但这样发号,客户端要请求一次 Redis,影响性能。
推荐号段生成:INCRBY 步长,如果 key 不存在,从 0 开始自增;如果 key 存在,返回自增后的数值。
-
1.2 数据结构
简单动态字符串,Simple Dynamic String 有 free、len 两个字段:
len 的作用: 二进制安全。不同于 c字符串通过 ‘\0’ 判断字符串长度,SDS 通过 len 记录长度
free 的作用:- 空间预分配。当进行 concat 等扩展操作时,SDS 会预留 free 空间,避免连续扩展带来的内存分配消耗
- 惰性释放空间。当进行字符串缩减操作时候,SDS 并不会马上收回空间,避免后续有扩展操作带来内存分配消耗
2 hash
2.1 使用场景
2.2.1 统计 PV、UV
- 用户110 访问 index.html HINCRBY index.html0527 110 1
- 用户110 再次访问 index.html HINCRBY index.html0527 110 1
- 查询 index.html 5月27日 PV HGETALL index.html0527,然后算总和(不建议,HGETALL 时间复杂度 O(n),会阻塞主线程)
查询 index.html 5月27日 UV HLEN index.html0527
2.2.2 统计 UV(BitMap)
用户110 访问 index.html SETBIT index.html0527 110 1
- 用户233 访问 index.html SETBIT index.html0527 233 1
查询 index.html 5月27日 UV BITCOUNT index.html0527
2.2.3 统计 UV(HyperLogLog)
用户 110、233 访问 index.html PFADD index.html0527 110 233
- 查询 index.html 5月27日 UV PFCOUNT index.html0527
2.2 数据结构
dict
哈希表,元素数量多于64 使用。链地址法
3 set
3.1 使用场景
3.1.2 共同关注
- 用户110 关注用户996 SADD follow110 996
- 用户110、233 的共同关注 SUNION follow110 follow233
3.2 数据结构
dict
哈希表,元素数量多于64 使用。value 存储 null
4 list
4.1 使用场景
4.1.2 限流(令牌桶)
- 固定速率生成令牌 LEFTPUSH limit UUID
- 达到上限,停止生成令牌 LLEN limit
- 消耗令牌 RIGHTPOP limit
4.2 数据结构
quicklist
双向链表,每一个节点都是 ziplist
5 zset
5.1 使用场景
5.1.1 限流(滑动窗口)
- 用户110 请求进来 ZADD limit110 UUID cur_time
- 时间范围内的请求 ZRANGEBYSCORE limit110 cur_time - interval cur_time
删除历史请求记录 ZREMRANGEBYSCORE limit110 0 cur_time - interval
5.1.2 排行榜
用户110 获得 99分 ZADD board 99 110
- 查询前100名高分用户 ZREVRANGE board 0 99
-
5.1.3 延时队列
按任务时间戳升序 ZADD delay timpestamp A
- while 检查第一个元素 ZRANGE delay 0 0
- 比较时间戳,如果能执行,就删除第一个元素 ZREM delay A
5.2 数据结构
dict
哈希表,key 是 member,value 是 score。zskiplist
跳表。0层存储完整数据,随机建新层,最高32层就可以容纳 2^64 个元素。
对比红黑树:
命令 | 红黑树 | 跳表 | 说明 |
---|---|---|---|
ZADD | O(logN) | O(logN) | 并发环境,跳表需要锁定的粒度更少 |
ZSCORE | O(1) | O(1) | 引入 dict |
ZRANK | O(logN) | O(logN) | 复杂度一样,跳表实现更简单 |
ZRANGE | O(N) | O(logN+k) | 跳表更高效 |
6 压缩数据结构
intset
当 set 元素数量少于64 使用zipmap
当 hash 元素数量少于64 使用ziplist
当 zset 元素数量少于64 使用。list 的节点就是 ziplist