码到成功
redis技术分享——(1)

Redis 是一个高性能的内存数据库,常被用作缓存、计数器、排行榜、消息队列、分布式锁和会话存储。
很多人刚开始使用 Redis 时,只把它当作简单的 key-value 缓存。实际上,Redis 真正强大的地方在于它提供了多种数据结构。不同的数据结构适合不同的业务场景,选对结构往往比单纯记住命令更重要。
本文主要围绕 Redis 中几种常用数据结构展开:
- String
- Hash
- List
- Set
- Sorted Set
- Bitmap
- HyperLogLog
- Stream
一、String:最基础的数据结构
String 是 Redis 中最基础、最常用的数据结构。它可以存储字符串、数字、JSON 字符串、序列化后的对象等。
常用命令
SET user:1:name "Tom"
GET user:1:name
SET count 1
INCR count
DECR count
SETEX token:abc 3600 "user-1"
TTL token:abc
常见场景
1. 缓存对象
可以把一个对象序列化成 JSON 后存入 Redis:
SET user:1 '{"id":1,"name":"Tom","age":20}'
GET user:1
这种方式简单直接,适合读取整个对象的场景。
2. 计数器
Redis 的 INCR 和 DECR 是原子操作,非常适合做计数器:
INCR article:1001:views
INCR video:2001:likes
常见用法包括:
- 文章阅读量
- 视频点赞数
- 接口调用次数
- 短信发送次数
3. 临时 Token
登录 token、验证码、短信码等通常都有过期时间,可以使用 SETEX:
SETEX login:token:abc123 7200 "user-1"
SETEX sms:code:13800000000 300 "9527"
这样 Redis 会自动删除过期数据,不需要业务代码额外清理。
二、Hash:适合存储对象字段
Hash 可以理解为一个 key 对应多个 field-value。它很适合存储对象,尤其是对象字段需要单独读写的场景。
常用命令
HSET user:1 name "Tom" age 20 city "Shanghai"
HGET user:1 name
HMGET user:1 name age
HGETALL user:1
HINCRBY user:1 age 1
HDEL user:1 city
常见场景
1. 用户信息
HSET user:1 id 1 name "Tom" age 20 level 3
HGET user:1 name
HINCRBY user:1 level 1
如果只需要修改用户的某一个字段,Hash 比整个 JSON 字符串更方便。
2. 商品库存信息
HSET product:1001 stock 500 price 99 sales 0
HINCRBY product:1001 stock -1
HINCRBY product:1001 sales 1
库存、销量、价格等字段可以独立更新。
String 和 Hash 怎么选
如果业务经常一次性读取整个对象,可以使用 String 存 JSON。
如果业务经常修改或读取对象中的某几个字段,Hash 更合适。
例如:
- 用户详情页一次性展示完整用户信息:String 可以
- 用户积分、等级、状态频繁独立更新:Hash 更合适
三、List:有序列表
List 是一个按照插入顺序排列的列表,可以从两端插入或弹出元素。
常用命令
LPUSH queue:email "job-1"
LPUSH queue:email "job-2"
RPOP queue:email
RPUSH messages "msg-1"
RPUSH messages "msg-2"
LRANGE messages 0 -1
常见场景
1. 简单消息队列
生产者写入任务:
LPUSH queue:order "order-1001"
LPUSH queue:order "order-1002"
消费者取出任务:
RPOP queue:order
也可以使用阻塞式命令:
BRPOP queue:order 10
BRPOP 在队列为空时会等待,适合消费者进程轮询任务。
2. 最新消息列表
LPUSH article:comments:1001 "comment-1"
LPUSH article:comments:1001 "comment-2"
LRANGE article:comments:1001 0 9
这种方式适合取最新评论、最新动态等。
注意点
List 适合简单队列,但如果业务要求更强的消息确认、失败重试、消费组等能力,应该优先考虑 Redis Stream,或者使用专业消息队列。
四、Set:无序且不重复的集合
Set 用来存储不重复的元素,适合去重、标签、关注关系、集合运算等场景。
常用命令
SADD user:1:tags "python" "redis" "mysql"
SMEMBERS user:1:tags
SISMEMBER user:1:tags "redis"
SREM user:1:tags "mysql"
SCARD user:1:tags
常见场景
1. 标签系统
SADD article:1001:tags "redis" "database" "cache"
SADD article:1002:tags "redis" "python"
Set 天然去重,适合保存标签。
2. 用户关注关系
SADD user:1:following 2 3 4
SADD user:2:followers 1
判断是否关注:
SISMEMBER user:1:following 2
3. 共同关注
SINTER user:1:following user:2:following
集合运算是 Set 的重要能力:
SINTER:交集SUNION:并集SDIFF:差集
例如社交系统中的共同好友、共同关注、兴趣匹配,都可以用 Set 来实现。
五、Sorted Set:带分数的有序集合
Sorted Set,也叫 ZSet。它和 Set 一样元素不重复,但每个元素都会关联一个分数 score,Redis 会根据分数排序。
常用命令
ZADD rank:game 100 "Tom"
ZADD rank:game 200 "Jerry"
ZADD rank:game 150 "Alice"
ZRANGE rank:game 0 -1 WITHSCORES
ZREVRANGE rank:game 0 9 WITHSCORES
ZINCRBY rank:game 50 "Tom"
ZRANK rank:game "Tom"
ZREVRANK rank:game "Tom"
常见场景
1. 排行榜
ZADD rank:article 100 "article-1"
ZADD rank:article 300 "article-2"
ZADD rank:article 200 "article-3"
获取前 10 名:
ZREVRANGE rank:article 0 9 WITHSCORES
增加文章热度:
ZINCRBY rank:article 1 "article-1"
2. 延迟队列
可以把时间戳作为 score:
ZADD delay:queue 1730000000 "task-1"
ZADD delay:queue 1730000060 "task-2"
消费者查询当前时间之前到期的任务:
ZRANGEBYSCORE delay:queue 0 1730000000
这种方式适合实现轻量级延迟任务。
3. 按时间排序的动态流
把发布时间作为 score:
ZADD user:1:feed 1730000000 "post-1001"
ZADD user:1:feed 1730000100 "post-1002"
按时间倒序取最新内容:
ZREVRANGE user:1:feed 0 19
六、Bitmap:适合大量布尔状态
Bitmap 本质上是基于 String 的位操作。它适合存储大量只有两种状态的数据,例如是否签到、是否在线、是否活跃。
常用命令
SETBIT sign:2026-04 0 1
GETBIT sign:2026-04 0
BITCOUNT sign:2026-04
常见场景
1. 用户签到
假设一个月最多 31 天,可以用每一位表示某一天是否签到:
SETBIT user:1:sign:2026-04 0 1
SETBIT user:1:sign:2026-04 1 1
SETBIT user:1:sign:2026-04 2 0
统计本月签到天数:
BITCOUNT user:1:sign:2026-04
2. 用户活跃状态
如果用用户 ID 作为偏移量,可以记录某天哪些用户活跃:
SETBIT active:2026-04-24 10001 1
GETBIT active:2026-04-24 10001
统计当天活跃用户数:
BITCOUNT active:2026-04-24
Bitmap 的优势是非常节省空间。对于大量布尔值场景,比用 Set 存用户 ID 更省内存。
七、HyperLogLog:基数统计
HyperLogLog 用于统计不重复元素数量,也就是基数统计。它的特点是占用空间极小,但结果有一定误差。
常用命令
PFADD uv:article:1001 user-1 user-2 user-3
PFADD uv:article:1001 user-2
PFCOUNT uv:article:1001
常见场景
1. UV 统计
PFADD uv:site:2026-04-24 user-1
PFADD uv:site:2026-04-24 user-2
PFADD uv:site:2026-04-24 user-1
PFCOUNT uv:site:2026-04-24
即使同一个用户访问多次,也只会统计一次。
注意点
HyperLogLog 适合只关心数量、不关心具体成员的场景。
如果你需要知道“哪些用户访问过”,应该使用 Set。
如果你只需要知道“大概有多少独立用户访问过”,HyperLogLog 更节省空间。
八、Stream:Redis 的消息流
Stream 是 Redis 5.0 引入的数据结构,适合实现消息队列、事件流、日志流等。
相比 List,Stream 支持消息 ID、消费组、消费确认和消息追踪。
常用命令
XADD order:stream * orderId 1001 status created
XADD order:stream * orderId 1002 status paid
XRANGE order:stream - +
XREAD COUNT 2 STREAMS order:stream 0
消费组示例
创建消费组:
XGROUP CREATE order:stream group-1 0 MKSTREAM
消费者读取消息:
XREADGROUP GROUP group-1 consumer-1 COUNT 1 STREAMS order:stream >
确认消息:
XACK order:stream group-1 1730000000000-0
常见场景
1. 订单事件流
XADD order:events * orderId 1001 event created
XADD order:events * orderId 1001 event paid
XADD order:events * orderId 1001 event shipped
不同消费者可以处理不同逻辑,例如:
- 发送通知
- 更新搜索索引
- 记录审计日志
- 触发积分发放
2. 轻量级消息队列
Stream 比 List 更适合消息队列,因为它支持:
- 消费组
- 消息确认
- 未确认消息查询
- 多消费者协作
如果项目已经使用 Redis,且消息量不算特别大,Stream 是一个实用选择。
九、不同数据结构怎么选
下面是一个简单对照表:
| 数据结构 | 适合场景 |
|---|---|
| String | 缓存值、计数器、验证码、Token |
| Hash | 用户对象、商品对象、字段独立更新 |
| List | 简单队列、最新列表、评论列表 |
| Set | 去重、标签、关注关系、集合运算 |
| Sorted Set | 排行榜、延迟队列、按分数排序 |
| Bitmap | 签到、活跃状态、布尔标记 |
| HyperLogLog | UV、去重数量统计 |
| Stream | 消息队列、事件流、消费组 |
十、Redis Key 设计建议
Redis 的 key 命名建议保持清晰和统一:
业务名:对象名:对象ID:字段
例如:
user:1
user:1:profile
user:1:following
article:1001:views
rank:article:daily
uv:site:2026-04-24
几个建议:
- 使用冒号
:分隔层级 - key 不要太长,但要能表达含义
- 临时数据设置过期时间
- 大 key 要拆分,避免一次读取过多数据
- 不要在生产环境使用
KEYS *扫描全量 key,应该使用SCAN
十一、总结
Redis 不是只能做缓存。它的多种数据结构可以覆盖很多常见业务需求。
简单来说:
- 存简单值,用 String
- 存对象字段,用 Hash
- 存队列或列表,用 List
- 存不重复集合,用 Set
- 做排行榜,用 Sorted Set
- 存大量布尔状态,用 Bitmap
- 统计 UV,用 HyperLogLog
- 做消息流,用 Stream
真正用好 Redis 的关键,不是记住所有命令,而是根据业务场景选择合适的数据结构。数据结构选对了,代码会更简单,性能也会更稳定。