Redis 是什么?
Redis(Remote Dictionary Server)是一个开源的、基于内存的键值存储系统,同时也是一个数据结构服务器。它支持持久化、主从复制、事务等功能,并提供了丰富的数据结构,使其不仅仅是简单的键值存储。
Redis 主要数据结构及详细介绍
1. 字符串(String)
- 存储形式:二进制安全的字符串,最大512MB
- 特点:
- 可以存储文本、数字(整数/浮点数)或二进制数据
- 对数字类型支持原子递增/递减操作
- 可设置过期时间
- 常用命令:
SET,GET,INCR,DECR,APPEND,GETRANGE - 内部编码:
int:存储8字节长整型embstr:小于等于44字节的字符串raw:大于44字节的字符串
使用场景:
- 缓存HTML片段、用户信息
- 计数器(文章阅读量、点赞数)
- 分布式锁(SET命令配合NX参数)
- 会话存储(Session)
- 限流器(INCR + EXPIRE)
2. 哈希(Hash)
- 存储形式:键值对集合,类似于编程语言中的Map
- 特点:
- 适合存储对象
- 可单独操作某个字段,无需读取整个对象
- 每个哈希最多可存储 2^32 - 1 个字段-值对
- 常用命令:
HSET,HGET,HGETALL,HMSET,HDEL,HINCRBY - 内部编码:
ziplist:元素数量小于512且所有值小于64字节hashtable:不满足ziplist条件时使用
使用场景:
- 存储用户信息(用户名、邮箱、年龄等)
- 商品信息存储
- 配置项管理
- 对象属性频繁部分更新的场景
3. 列表(List)
- 存储形式:双向链表(但底层实现是quicklist)
- 特点:
- 按插入顺序排序
- 可从两端插入/弹出元素
- 支持阻塞式弹出(BLPOP/BRPOP)
- 常用命令:
LPUSH,RPUSH,LPOP,RPOP,LRANGE,BLPOP - 内部编码:
ziplist:元素数量小于512且所有元素小于64字节linkedlist:不满足ziplist条件时(Redis 3.2之前)quicklist:Redis 3.2之后,ziplist的链表组合
使用场景:
- 消息队列(LPUSH + RPOP)
- 最新消息排行(如朋友圈时间线)
- 记录用户最近操作
- 实现栈(LPUSH + LPOP)或队列(LPUSH + RPOP)
4. 集合(Set)
- 存储形式:无序的字符串集合,元素不重复
- 特点:
- 自动去重
- 支持集合运算(并集、交集、差集)
- 可随机获取元素
- 常用命令:
SADD,SMEMBERS,SINTER,SUNION,SISMEMBER,SRANDMEMBER - 内部编码:
intset:所有元素都是整数且元素数量小于512hashtable:不满足intset条件时
使用场景:
- 标签系统(用户标签、文章标签)
- 共同好友/共同关注(SINTER)
- 抽奖系统(SRANDMEMBER)
- 数据去重(爬虫URL去重)
5. 有序集合(Sorted Set / ZSet)
- 存储形式:元素唯一,每个元素关联一个分数(score),按分数排序
- 特点:
- 元素不重复,但分数可重复
- 可按分数范围或成员获取数据
- 支持排名操作
- 常用命令:
ZADD,ZRANGE,ZREVRANGE,ZRANGEBYSCORE,ZRANK,ZSCORE - 内部编码:
ziplist:元素数量小于128且所有元素小于64字节skiplist+dict:不满足ziplist条件时
使用场景:
- 排行榜(游戏分数排行、热度排行)
- 带权重的消息队列(分数代表优先级)
- 范围查找(如查找价格在100-200的商品)
- 延时队列(时间戳作为分数)
6. 位图(Bitmap)
- 存储形式:本质是字符串,但提供位操作
- 特点:
- 非常节省空间(1亿用户在线状态只需约12MB)
- 支持位运算(AND, OR, XOR, NOT)
- 常用命令:
SETBIT,GETBIT,BITCOUNT,BITOP - 底层实现:SDS(简单动态字符串)
使用场景:
- 用户在线状态统计
- 用户签到记录
- 活跃用户统计(DAU/MAU)
- 布隆过滤器(配合使用)
7. HyperLogLog
- 存储形式:专门用于基数统计(估算集合中不重复元素数量)
- 特点:
- 极小的内存占用(每个约12KB)
- 0.81%的标准误差率
- 只能统计,不能获取具体元素
- 常用命令:
PFADD,PFCOUNT,PFMERGE
使用场景:
- 网站UV统计
- 大规模去重计数(如搜索关键词去重)
8. 地理空间索引(GEO)
- 存储形式:基于有序集合实现,存储经纬度信息
- 特点:
- 支持添加、计算距离、查找附近位置
- 底层使用Geohash编码
- 常用命令:
GEOADD,GEODIST,GEORADIUS,GEOHASH
使用场景:
- 附近的人/商家
- 地理位置搜索
- 配送距离计算
9. 流(Stream)
- 存储形式:类似日志的数据结构(Redis 5.0+)
- 特点:
- 支持多消费者组
- 消息可持久化,支持ACK确认
- 类似Kafka的消息队列
- 常用命令:
XADD,XREAD,XREADGROUP,XRANGE
使用场景:
- 消息队列(比List更强大的功能)
- 事件溯源
- 日志收集
数据结构选择指南
| 需求场景 | 推荐数据结构 | 理由 |
|---|---|---|
| 简单键值缓存 | String | 简单高效,支持过期 |
| 存储对象 | Hash | 可单独操作字段,节省网络传输 |
| 消息队列 | List 或 Stream | List简单,Stream功能更完整 |
| 排行榜 | Sorted Set | 天然支持排序和范围查询 |
| 标签系统 | Set | 自动去重,支持集合运算 |
| 签到统计 | Bitmap | 极致节省空间 |
| UV统计 | HyperLogLog | 内存占用极小 |
| 附近的人 | GEO | 专门的地理位置功能 |
| 去重统计 | Set 或 HyperLogLog | Set精确,HyperLogLog节省空间 |
最佳实践建议
- 小对象优化:对于小的Hash、List等,Redis会使用ziplist等紧凑编码节省内存
- 避免大Key:单个String不超过10KB,集合元素不超过5000
- 合理设置过期时间:防止内存泄漏
- 选择合适编码:了解数据结构内部编码,根据数据特征优化
- Pipeline批量操作:减少网络往返时间
Redis的强大之处在于数据结构丰富且操作原子性,选择合适的结构可以大幅简化业务逻辑并提升性能。