[redis]redis及其数据结构

22 阅读5分钟

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:所有元素都是整数且元素数量小于512
    • hashtable:不满足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 或 StreamList简单,Stream功能更完整
排行榜Sorted Set天然支持排序和范围查询
标签系统Set自动去重,支持集合运算
签到统计Bitmap极致节省空间
UV统计HyperLogLog内存占用极小
附近的人GEO专门的地理位置功能
去重统计Set 或 HyperLogLogSet精确,HyperLogLog节省空间

最佳实践建议

  1. 小对象优化:对于小的Hash、List等,Redis会使用ziplist等紧凑编码节省内存
  2. 避免大Key:单个String不超过10KB,集合元素不超过5000
  3. 合理设置过期时间:防止内存泄漏
  4. 选择合适编码:了解数据结构内部编码,根据数据特征优化
  5. Pipeline批量操作:减少网络往返时间

Redis的强大之处在于数据结构丰富且操作原子性,选择合适的结构可以大幅简化业务逻辑并提升性能。