第3章 特殊类型的精巧结构 章节摘要:本章跟着三个"反常识的数字"走——一亿用户的签到记录只用十几 MB、一亿个 UV 的计数只花 12KB、两个经纬度求距离是 O(1) 查表。Bitmap、HyperLogLog、Geo、Stream 这些特殊类型,是 Redis 把某个数据结构推到极致后的产物。 一条主线 一个日活一亿的 App 要做三件事:统计每日签到墙、统计每个页面的 UV、找附近 3 公里的门店。用关系型数据库做,三件事分别要一亿行的表、去重索引和地理计算全表扫。本章的主线就是看 Redis 如何用三种极端化的结构把这三件事的内存与时间成本压到原来的万分之一,顺带用一个日志结构解决可靠消息传递。 沿途站点 3.
章节摘要:本章跟着三个"反常识的数字"走——一亿用户的签到记录只用十几 MB、一亿个 UV 的计数只花 12KB、两个经纬度求距离是 O(1) 查表。Bitmap、HyperLogLog、Geo、Stream 这些特殊类型,是 Redis 把某个数据结构推到极致后的产物。
一个日活一亿的 App 要做三件事:统计每日签到墙、统计每个页面的 UV、找附近 3 公里的门店。用关系型数据库做,三件事分别要一亿行的表、去重索引和地理计算全表扫。本章的主线就是看 Redis 如何用三种极端化的结构把这三件事的内存与时间成本压到原来的万分之一,顺带用一个日志结构解决可靠消息传递。
四种结构的成本量级对比:
转折点在 3.2:HyperLogLog 教会你用误差买空间这笔交易怎么估价。工程里大量统计场景(UV、去重计数)根本不需要精确值,识别出"这里可以不精确"本身是重要的架构能力。3.3 的 Stream 则反向示范:要精确可靠时,日志结构比队列结构贵多少、换来什么。把这两笔交易放在一起看,"统计要不要精确、消息要不要可靠"的定价能力就建立起来了——它比任何单个结构的细节都更值钱。
统计类需求的选型判据浓缩成一张表,评审时按行对号:
| 需求特征 | 首选结构 | 内存量级 | 换来的代价 |
|---|---|---|---|
| 布尔状态、用户号稠密 | Bitmap | 亿级约12MB | 位运算耗时随墙体积涨 |
| 只要去重计数、看趋势 | HyperLogLog | 恒定12KB | 有误差、取不出成员 |
| 精确去重且要列举成员 | Set | 随基数线性涨 | 内存大户,大键要分批 |
| 附近搜索、距离排序 | Geo(跳表) | 每成员一个跳表条目 | 编码边界由服务端兜底 |
| 可靠消息、多下游独立消费 | Stream | 随保留条数涨 | 必须配 XTRIM 与 ACK 纪律 |
这张表的潜台词与第 2 章一脉相承:没有免费的结构,只有匹配的交易。判断顺序永远是"先问精确性要求与查询形状,再选结构,最后算内存账"——顺序颠倒了,后面全是补救。
结构讲完,主线转向结构的"动态操作安全":多条命令如何打包成原子单元、脚本如何把一串操作焊成一条。第 4 章开始进入命令的执行语义。