Redis 学习笔记(第二期):核心数据类型与消息队列实战

Redis 学习笔记(第二期):核心数据类型与消息队列实战

本笔记为 Redis 系列第二期,基于第一期(概述、安装、配置、缓存理论)深入讲解五种核心数据类型(String、List、Set、ZSet、Hash)的完整命令、底层原理、生产案例,以及消息队列实现(List 模式、Pub/Sub 模式、Streams 简介),最后通过 Python 程序演示如何连接 Redis 并操作各种数据类型。本期额外补充了大量注释、对比表格、最佳实践和常见错误排查,适合初学者系统学习,也便于复习强化。


一、五种数据类型总览

Redis 所有的 key(键)都是字符串,而 value(值)支持以下五种基础数据类型:

数据类型 底层实现(简要) 特点 适用场景
String SDS(简单动态字符串) 二进制安全,可存整数、文本、序列化对象 缓存对象、计数器、分布式锁、验证码
List quicklist(双向链表) 有序,可重复,左右操作高效 消息队列、最新消息列表、历史记录
Set intset / hashtable 无序,唯一 标签系统、共同好友、抽奖去重
ZSet(Sorted Set) ziplist / skiplist + dict 有序,唯一,按分数排序 排行榜、延时队列、带权重的任务
Hash ziplist / hashtable 适合存储对象(多个字段) 用户信息、商品详情、配置项

记忆技巧:Redis 的 value 可以是"单值(String)"、"列表"、"集合"、"有序集合"、"对象(Hash)"。


二、String 类型(字符串)

2.1 底层结构简图

Redis 的 String 使用 SDS(Simple Dynamic String) 实现,相比 C 字符串有以下优点:

  • 预分配空间:减少内存重分配次数。
  • 惰性释放:缩短后不立即回收,便于下次追加。
  • 二进制安全:可存储任何数据(图片、序列化对象等)。

2.2 命令速查表

命令 示例 说明
`SET key value EX seconds [NX XX]` SET name "Tom"
GET key GET name 获取键值
MSET key1 val1 key2 val2 ... MSET a 1 b 2 批量设置
MGET key1 key2 ... MGET a b 批量获取
SETEX key seconds value SETEX code 60 "123456" 设置键值并指定过期时间(秒)
SETNX key value SETNX lock 1 键不存在时设置(分布式锁常用)
INCR key INCR views 值加 1(值须为整数)
INCRBY key increment INCRBY score 10 值加指定整数
DECR key DECR stock 值减 1
DECRBY key decrement DECRBY stock 2 值减指定整数
APPEND key value APPEND msg " world" 追加内容
STRLEN key STRLEN name 获取字符串长度(字节数)
GETSET key new_value GETSET counter 0 设置新值并返回旧值
DEL key DEL name 删除键(通用命令)
EXISTS key EXISTS name 判断键是否存在
EXPIRE key seconds EXPIRE name 30 设置过期时间
TTL key TTL name 查看剩余生存时间(-1 永不过期,-2 不存在)

2.3 命令详细演示

bash

复制代码
# 连接 Redis(无密码)
redis-cli
基础设置与获取

bash

复制代码
# SET / GET
127.0.0.1:6379> SET name "zhangsan"
OK
127.0.0.1:6379> GET name
"zhangsan"

# 判断类型
127.0.0.1:6379> TYPE name
string

# 带过期时间(EX 秒,PX 毫秒)
127.0.0.1:6379> SET token "abc123" EX 10
OK
127.0.0.1:6379> TTL token
(integer) 7

# 仅在 key 不存在时设置(SETNX)
127.0.0.1:6379> SETNX lock 1
(integer) 1          # 成功,key 不存在
127.0.0.1:6379> SETNX lock 2
(integer) 0          # 失败,key 已存在
127.0.0.1:6379> GET lock
"1"

# 仅在 key 存在时设置(SET ... XX)
127.0.0.1:6379> SET lock 3 XX
OK
127.0.0.1:6379> GET lock
"3"
批量操作(减少 RTT)

bash

复制代码
127.0.0.1:6379> MSET key1 value1 key2 value2
OK
127.0.0.1:6379> MGET key1 key2
1) "value1"
2) "value2"
数字计数器(原子操作)

bash

复制代码
127.0.0.1:6379> SET views 100
OK
127.0.0.1:6379> INCR views
(integer) 101
127.0.0.1:6379> INCRBY views 50
(integer) 151
127.0.0.1:6379> DECR views
(integer) 150
127.0.0.1:6379> DECRBY views 20
(integer) 130

# 对不存在的 key 做 INCR,会自动初始化为 0 再加
127.0.0.1:6379> INCR new_counter
(integer) 1

# 对非数字值使用 INCR 会报错
127.0.0.1:6379> SET name "abc"
OK
127.0.0.1:6379> INCR name
(error) ERR value is not an integer or out of range
其他实用命令

bash

复制代码
# 追加
127.0.0.1:6379> SET msg "Hello"
OK
127.0.0.1:6379> APPEND msg " Redis"
(integer) 11          # 返回追加后的字节长度
127.0.0.1:6379> GET msg
"Hello Redis"

# 获取长度(字节数,中文字符按编码)
127.0.0.1:6379> STRLEN msg
(integer) 11

# GETSET:设置新值并返回旧值
127.0.0.1:6379> GETSET counter 0
"130"                 # 返回旧值 130,新值变为 0
127.0.0.1:6379> GET counter
"0"

2.4 生产案例

案例1:文章阅读量计数器

bash

复制代码
# 每次访问文章 ID=1001,增加阅读量
INCR article:1001:views

# 获取阅读量
GET article:1001:views

注意 :计数器应定期持久化,或配合 EXPIRE 设置统计周期。

案例2:分布式锁(简化版)

bash

复制代码
# 加锁:key 不存在时设置,过期 30 秒
SET lock:order:1001 "client_id" NX EX 30

# 解锁:需原子性判断并删除(实际用 Lua 脚本)
# 此处仅演示加锁部分
案例3:短信验证码存储

bash

复制代码
# 生成6位验证码,5分钟有效
SETEX sms:13800138000 300 "123456"

2.5 注意事项与最佳实践

  • 大 key 问题:String 类型建议不超过 10KB。过大的值(如存储序列化的大对象)会降低性能。
  • 避免 KEYS \* :生产环境禁止使用,会阻塞 Redis。用 SCAN 代替。
  • 整数范围:INCR/DECR 支持 64 位有符号整数。
  • 内存优化 :对于大量短字符串,可考虑开启 hash-max-ziplist-entries 等压缩配置(但 String 本身无压缩)。

三、List 类型(列表)

3.1 底层结构

Redis 3.2 之后使用 quicklist(双向链表 + ziplist 分段),兼顾内存效率和插入删除性能。特点:

  • 有序,可重复。
  • 左右两端操作(LPUSH/RPUSH、LPOP/RPOP)时间复杂度 O(1)。
  • 索引操作(LINDEX)时间复杂度 O(N),慎用。

3.2 命令速查表

命令 示例 说明
LPUSH key value [value ...] LPUSH queue a b c 从左边(头部)插入一个或多个元素
RPUSH key value [value ...] RPUSH queue x y 从右边(尾部)插入
LPOP key LPOP queue 移除并返回左边第一个元素
RPOP key RPOP queue 移除并返回右边第一个元素
LRANGE key start stop LRANGE queue 0 -1 获取指定范围元素(支持负索引)
LLEN key LLEN queue 获取列表长度
LINDEX key index LINDEX queue 1 获取指定索引的元素
LSET key index value LSET queue 1 new 修改指定索引的元素
LTRIM key start stop LTRIM queue 0 100 修剪列表,只保留指定区间
BLPOP key [key ...] timeout BLPOP queue 10 阻塞式左弹出(超时秒数)
BRPOP key [key ...] timeout BRPOP queue 10 阻塞式右弹出
RPOPLPUSH source dest RPOPLPUSH list1 list2 右弹出一个元素并左压入另一个列表
DEL key DEL queue 删除整个列表

3.3 命令详细演示

bash

复制代码
# 从左边插入
127.0.0.1:6379> LPUSH list1 tom
(integer) 1
127.0.0.1:6379> LPUSH list1 jack
(integer) 2
127.0.0.1:6379> LRANGE list1 0 -1
1) "jack"   # 后插入的在左边(头部)
2) "tom"

# 从右边插入
127.0.0.1:6379> RPUSH list2 a b c
(integer) 3
127.0.0.1:6379> LRANGE list2 0 -1
1) "a"
2) "b"
3) "c"

# 同时从左边插入多个
127.0.0.1:6379> LPUSH list3 x y z
(integer) 3
127.0.0.1:6379> LRANGE list3 0 -1
1) "z"   # 注意顺序:z y x,因为依次插入
2) "y"
3) "x"

# 弹出
127.0.0.1:6379> LPOP list3
"z"
127.0.0.1:6379> RPOP list3
"x"
127.0.0.1:6379> LRANGE list3 0 -1
1) "y"

# 获取长度
127.0.0.1:6379> LLEN list2
(integer) 3

# 按索引操作
127.0.0.1:6379> LINDEX list2 1
"b"
127.0.0.1:6379> LSET list2 1 new_b
OK
127.0.0.1:6379> LRANGE list2 0 -1
1) "a"
2) "new_b"
3) "c"

# 修剪(只保留索引 1 到 2)
127.0.0.1:6379> LTRIM list2 1 2
OK
127.0.0.1:6379> LRANGE list2 0 -1
1) "new_b"
2) "c"
阻塞式弹出(经典消息队列)

打开两个终端:

终端 A(消费者,阻塞等待)

bash

复制代码
127.0.0.1:6379> BRPOP task_queue 5   # 超时 5 秒
# 此时没有数据,阻塞等待

终端 B(生产者,推送消息)

bash

复制代码
127.0.0.1:6379> LPUSH task_queue "job1"
(integer) 1

终端 A 立即输出

text

复制代码
1) "task_queue"
2) "job1"
(2.34s)

说明BRPOP 返回的第一个元素是列表名,第二个是值。

3.4 生产案例

案例1:简单消息队列(生产者-消费者)

bash

复制代码
# 生产者(多个进程)
LPUSH order_queue "order:1001"
LPUSH order_queue "order:1002"

# 消费者(多个进程,阻塞等待)
BRPOP order_queue 0   # 0 表示无限阻塞

特点:一条消息只能被一个消费者获取,适合任务分发。

案例2:最新消息列表(如评论、动态)

bash

复制代码
# 用户发表一条动态,ID 为 5001
LPUSH user:1001:posts "5001"

# 只保留最近 50 条
LTRIM user:1001:posts 0 49

# 分页查询
LRANGE user:1001:posts 0 9   # 第一页(最新10条)

3.5 注意事项

  • 列表索引操作(LINDEXLSET)对于长列表效率较低,应尽量避免在循环中频繁使用。
  • 阻塞弹出(BLPOP/BRPOP)的超时设为 0 表示无限等待,注意客户端超时机制。
  • 列表长度超过 list-max-ziplist-size 配置时会从 ziplist 转为 quicklist 节点,但命令行为不变。

四、Set 类型(集合)

4.1 底层结构

Set 满足元素唯一性。当所有元素都是整数且数量小于 set-max-intset-entries(默认 512)时,使用 intset (紧凑数组);否则使用 hashtable

4.2 命令速查表

命令 示例 说明
SADD key member [member ...] SADD fruits apple banana 添加一个或多个成员
SMEMBERS key SMEMBERS fruits 获取所有成员(慎用于大集合)
SREM key member [member ...] SREM fruits apple 删除成员
SISMEMBER key member SISMEMBER fruits apple 判断成员是否存在
SCARD key SCARD fruits 获取成员数量
SINTER key1 [key2 ...] SINTER set1 set2 交集
SUNION key1 [key2 ...] SUNION set1 set2 并集
SDIFF key1 [key2 ...] SDIFF set1 set2 差集(属于 key1 不属于 key2)
SPOP key [count] SPOP fruits 2 随机弹出 count 个成员
SRANDMEMBER key [count] SRANDMEMBER fruits 3 随机返回成员(不删除)
SMOVE source dest member SMOVE set1 set2 apple 移动成员到另一集合

4.3 命令详细演示

bash

复制代码
# 添加
127.0.0.1:6379> SADD set1 v1 v2 v3
(integer) 3
127.0.0.1:6379> SADD set2 v2 v3 v4
(integer) 3

# 查看所有成员(顺序不固定)
127.0.0.1:6379> SMEMBERS set1
1) "v2"
2) "v3"
3) "v1"

# 判断存在
127.0.0.1:6379> SISMEMBER set1 v1
(integer) 1
127.0.0.1:6379> SISMEMBER set1 v5
(integer) 0

# 删除
127.0.0.1:6379> SREM set1 v1
(integer) 1
127.0.0.1:6379> SMEMBERS set1
1) "v2"
2) "v3"

# 集合运算
127.0.0.1:6379> SINTER set1 set2
1) "v2"
2) "v3"
127.0.0.1:6379> SUNION set1 set2
1) "v2"
2) "v3"
3) "v4"
127.0.0.1:6379> SDIFF set1 set2   # 只属于 set1 的
(empty list or set)               # 因为 v2,v3 都在 set2 中
127.0.0.1:6379> SDIFF set2 set1   # 只属于 set2 的
1) "v4"

# 随机弹出(抽奖)
127.0.0.1:6379> SADD lottery 101 102 103 104 105
(integer) 5
127.0.0.1:6379> SPOP lottery 2
1) "103"
2) "105"
127.0.0.1:6379> SMEMBERS lottery
1) "101"
2) "102"
3) "104"

4.4 生产案例

案例1:共同好友(社交系统)

bash

复制代码
# 用户 A 的好友集合
SADD user:1001:friends 2001 2002 2003
# 用户 B 的好友集合
SADD user:1002:friends 2002 2003 2004
# 共同好友
SINTER user:1001:friends user:1002:friends
# 推荐好友(用户 A 的好友集合中减去 B 的好友)
SDIFF user:1001:friends user:1002:friends
案例2:抽奖去重(唯一参与用户)

bash

复制代码
# 活动期间,用户每次点击参与抽奖,添加用户ID
SADD lottery:20250101 1001
SADD lottery:20250101 1002
# 抽随机获奖者
SRANDMEMBER lottery:20250101 1
# 或者弹出获奖者(消耗)
SPOP lottery:20250101 3

4.5 注意事项

  • SMEMBERS 命令在大集合(百万级)时会阻塞 Redis,应改用 SSCAN 迭代。
  • 集合运算(SINTER、SUNION、SDIFF)复杂度较高,可能阻塞,建议在从库执行或使用 SINTERSTORE 等命令存储结果。

五、ZSet 类型(有序集合)

5.1 底层结构

ZSet 内部使用 skiplist(跳表)+ dict(哈希表) ,达到 O(log N) 的查询和插入效率。每个元素关联一个 double 类型的分数(score),按分数从小到大排序,分数相同则按字典序排列。

5.2 命令速查表

命令 示例 说明
ZADD key score member [score member ...] ZADD rank 100 "Alice" 添加元素,可同时指定多个
ZRANGE key start stop [WITHSCORES] ZRANGE rank 0 -1 WITHSCORES 按分数升序返回索引范围内的成员
ZREVRANGE key start stop [WITHSCORES] ZREVRANGE rank 0 -1 WITHSCORES 按分数降序返回
ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT] ZRANGEBYSCORE rank 80 100 按分数范围返回(包含边界)
ZREM key member [member ...] ZREM rank Alice 删除一个或多个成员
ZCARD key ZCARD rank 获取成员数量
ZCOUNT key min max ZCOUNT rank 80 100 统计分数范围内的成员数
ZRANK key member ZRANK rank Alice 获取成员排名(升序,从 0 开始)
ZREVRANK key member ZREVRANK rank Alice 获取成员排名(降序)
ZSCORE key member ZSCORE rank Alice 获取成员的分数
ZINCRBY key increment member ZINCRBY rank 5 Alice 增加成员的分数
ZREMRANGEBYRANK key start stop ZREMRANGEBYRANK rank 0 9 删除按排名范围(前10名删除)
ZREMRANGEBYSCORE key min max ZREMRANGEBYSCORE rank 0 60 删除按分数范围

5.3 命令详细演示

bash

复制代码
# 添加课程分数
127.0.0.1:6379> ZADD course 90 linux 99 go 60 python 50 cloud
(integer) 4

# 升序查看所有(不带分数)
127.0.0.1:6379> ZRANGE course 0 -1
1) "cloud"
2) "python"
3) "linux"
4) "go"

# 带分数
127.0.0.1:6379> ZRANGE course 0 -1 WITHSCORES
1) "cloud"
2) "50"
3) "python"
4) "60"
5) "linux"
6) "90"
7) "go"
8) "99"

# 降序(从高到低)
127.0.0.1:6379> ZREVRANGE course 0 -1 WITHSCORES
1) "go"
2) "99"
3) "linux"
4) "90"
5) "python"
6) "60"
7) "cloud"
8) "50"

# 按分数范围查询(60 到 100)
127.0.0.1:6379> ZRANGEBYSCORE course 60 100 WITHSCORES
1) "python"
2) "60"
3) "linux"
4) "90"
5) "go"
6) "99"

# 统计分数≥80的人数
127.0.0.1:6379> ZCOUNT course 80 100
(integer) 2

# 查看排名(升序,0 是第一名)
127.0.0.1:6379> ZRANK course go
(integer) 3
127.0.0.1:6379> ZREVRANK course go   # 降序排名(第一名是 0)
(integer) 0

# 增加某成员分数
127.0.0.1:6379> ZINCRBY course 5 python
"65"
127.0.0.1:6379> ZSCORE course python
"65"

# 删除成员
127.0.0.1:6379> ZREM course cloud
(integer) 1

5.4 生产案例

案例1:游戏排行榜(实时)

bash

复制代码
# 用户 1001 获得 500 分
ZADD leaderboard 500 1001
# 用户 1002 获得 600 分
ZADD leaderboard 600 1002
# 用户 1001 再得 100 分(增加)
ZINCRBY leaderboard 100 1001

# 获取前三名(降序)
ZREVRANGE leaderboard 0 2 WITHSCORES

# 查看用户 1001 的排名(降序排名,0 开始)
ZREVRANK leaderboard 1001
案例2:延时队列(任务调度)

bash

复制代码
# 将任务添加到延时队列(以执行时间戳作为分数)
ZADD delay_queue 1734220800 "task:send_email:1001"
ZADD delay_queue 1734220900 "task:gen_report:2002"

# 消费者定期取到期任务(当前时间戳 now=1734220850)
ZRANGEBYSCORE delay_queue 0 1734220850 WITHSCORES
# 取出后删除
ZREMRANGEBYSCORE delay_queue 0 1734220850

5.5 注意事项

  • ZSet 的元素(member)不能重复,但分数(score)可以重复。
  • 避免在 ZSet 中存储过大的 member(如长文本),会影响性能。
  • 大量使用 ZRANGEBYSCORE 且不加 LIMIT 可能导致网络阻塞,建议分页。

六、Hash 类型(哈希)

6.1 底层结构

Hash 用于存储对象(多个字段-值对)。当字段数少且值较短时使用 ziplist ,超过阈值(hash-max-ziplist-entries 默认 512,hash-max-ziplist-value 默认 64 字节)转为 hashtable

6.2 命令速查表

命令 示例 说明
HSET key field value [field value ...] HSET user:1001 name "Tom" age 25 设置一个或多个字段
HGET key field HGET user:1001 name 获取指定字段的值
HMSET key field value [field value ...] HMSET user:1002 name "Jerry" age 30 批量设置(Redis 4.0+ 可用 HSET 替代)
HMGET key field [field ...] HMGET user:1001 name age 批量获取
HGETALL key HGETALL user:1001 获取所有字段和值(慎用)
HKEYS key HKEYS user:1001 获取所有字段名
HVALS key HVALS user:1001 获取所有值
HDEL key field [field ...] HDEL user:1001 age 删除字段
HEXISTS key field HEXISTS user:1001 name 判断字段是否存在
HINCRBY key field increment HINCRBY user:1001 score 10 对整数字段自增
HLEN key HLEN user:1001 获取字段数量

6.3 命令详细演示

bash

复制代码
# 设置用户信息
127.0.0.1:6379> HSET user:9527 name "zhouxingxing" age 20
(integer) 2
127.0.0.1:6379> TYPE user:9527
hash

# 获取单个字段
127.0.0.1:6379> HGET user:9527 name
"zhouxingxing"

# 批量设置
127.0.0.1:6379> HMSET user:9527 city "hongkong" gender male
OK

# 获取多个字段
127.0.0.1:6379> HMGET user:9527 name age
1) "zhouxingxing"
2) "20"

# 获取所有字段和值
127.0.0.1:6379> HGETALL user:9527
1) "name"
2) "zhouxingxing"
3) "age"
4) "20"
5) "city"
6) "hongkong"
7) "gender"
8) "male"

# 获取所有字段名
127.0.0.1:6379> HKEYS user:9527
1) "name"
2) "age"
3) "city"
4) "gender"

# 获取所有值
127.0.0.1:6379> HVALS user:9527
1) "zhouxingxing"
2) "20"
3) "hongkong"
4) "male"

# 自增操作(分数)
127.0.0.1:6379> HINCRBY user:9527 score 5
(integer) 5
127.0.0.1:6379> HGET user:9527 score
"5"

# 判断字段存在
127.0.0.1:6379> HEXISTS user:9527 age
(integer) 1

# 删除字段
127.0.0.1:6379> HDEL user:9527 age
(integer) 1
127.0.0.1:6379> HGETALL user:9527
1) "name"
2) "zhouxingxing"
3) "city"
4) "hongkong"
5) "gender"
6) "male"
7) "score"
8) "5"

6.4 生产案例

案例1:用户信息存储

bash

复制代码
HSET user:1001 name "张三" age 25 email "zhang@example.com"
# 获取用户年龄
HGET user:1001 age
# 更新用户邮箱
HSET user:1001 email "new@example.com"
案例2:购物车(简单版)

bash

复制代码
# 用户 1001 添加商品 2001 数量 2
HSET cart:1001 2001 2
# 增加商品 2001 数量 1
HINCRBY cart:1001 2001 1
# 查看购物车
HGETALL cart:1001
# 删除商品
HDEL cart:1001 2001

6.5 注意事项

  • HGETALL 在 Hash 很大时会阻塞,应使用 HSCAN 迭代。
  • Hash 适合存储对象,每个字段独立操作,比用 String 序列化整个对象更灵活。
  • 合理设置 hash-max-ziplist-entrieshash-max-ziplist-value 以平衡内存和性能。

七、消息队列深度对比

教材中介绍了 List 实现的简单消息队列和 Pub/Sub 模式,这里补充两者的对比以及 Streams(Redis 5.0+)简介。

7.1 List 模式(生产者/消费者)

特点

  • 一个消息只能被一个消费者消费(竞态)。
  • 支持阻塞弹出(BRPOP),避免轮询。
  • 消息不持久化(若消费者未消费而 Redis 宕机,消息可能丢失)。

适用场景:简单的异步任务队列,对消息可靠性要求不高。

7.2 Pub/Sub 模式(发布/订阅)

特点

  • 一个消息被所有订阅者接收(广播)。
  • 消息实时,但不持久化(订阅者离线期间的消息会丢失)。
  • 不支持消息确认和重试。

适用场景:实时通知、聊天室、广播。

7.3 Streams(Redis 5.0+)

特点

  • 持久化消息,支持消费者组、消息确认、消息重放。
  • 功能类似 Kafka,但更轻量。

教材未详细讲解,此处仅作补充知识(不展开命令)。如需可靠消息队列,可学习 Streams。

7.4 对比表格

特性 List (BRPOP) Pub/Sub Streams
消息持久化 ✅ (AOF/RDB)
消息确认机制 ✅ (XACK)
消费关系 一条消息一个消费者 一条消息多个消费者 消费者组(可分组)
历史消息 ❌ (消费后删除)
复杂度 中高

八、Python 连接 Redis 实战

8.1 安装 redis-py

bash

复制代码
pip install redis

8.2 连接池配置与基本操作

python

复制代码
import redis

# 使用连接池(推荐)
pool = redis.ConnectionPool(
    host='192.168.108.172',
    port=6379,
    password='123456',
    db=0,
    max_connections=10
)
r = redis.Redis(connection_pool=pool)

# 测试连接
print(r.ping())  # True 表示成功

8.3 完整脚本:演示五种数据类型

python

复制代码
import redis

# 连接 Redis(无密码示例)
r = redis.Redis(host='127.0.0.1', port=6379, db=0)

# ========== String ==========
print("=== String ===")
r.set('name', 'Alice')
print(r.get('name'))           # b'Alice' (bytes)
print(r.incr('counter'))       # 1
print(r.incrby('counter', 5))  # 6

# ========== List ==========
print("\n=== List ===")
r.lpush('tasks', 'task1', 'task2')
r.rpush('tasks', 'task3')
print(r.lrange('tasks', 0, -1))  # [b'task2', b'task1', b'task3']
print(r.brpop('tasks', timeout=1))  # (b'tasks', b'task3')

# ========== Set ==========
print("\n=== Set ===")
r.sadd('tags', 'python', 'redis', 'database')
r.sadd('tags', 'redis')  # 重复添加无效
print(r.smembers('tags'))  # {b'database', b'redis', b'python'}
print(r.sismember('tags', 'python'))  # True

# ========== ZSet ==========
print("\n=== ZSet ===")
r.zadd('rank', {'Alice': 100, 'Bob': 90, 'Charlie': 95})
print(r.zrange('rank', 0, -1, withscores=True))
# [(b'Bob', 90.0), (b'Charlie', 95.0), (b'Alice', 100.0)]
print(r.zrevrank('rank', 'Alice'))  # 0 (第一名)

# ========== Hash ==========
print("\n=== Hash ===")
r.hset('user:1', mapping={'name': 'Tom', 'age': 25})
r.hset('user:1', 'city', 'Beijing')
print(r.hgetall('user:1'))
# {b'name': b'Tom', b'age': b'25', b'city': b'Beijing'}
print(r.hincrby('user:1', 'age', 1))  # 26

运行输出示例

text

复制代码
=== String ===
b'Alice'
1
6

=== List ===
[b'task2', b'task1', b'task3']
(b'tasks', b'task3')

=== Set ===
{b'database', b'redis', b'python'}
True

=== ZSet ===
[(b'Bob', 90.0), (b'Charlie', 95.0), (b'Alice', 100.0)]
0

=== Hash ===
{b'name': b'Tom', b'age': b'25', b'city': b'Beijing'}
26

8.4 注意事项(Python)

  • redis-py 默认返回 bytes 类型,如需字符串可设置 decode_responses=True
  • 密码参数建议从环境变量读取,不要硬编码。
  • 使用连接池提高并发性能。

九、速查表与常见错误汇总

9.1 五种数据类型命令速查表(一页精华)

类型 增/改 其他常用
String SET, MSET, SETEX, SETNX GET, MGET, STRLEN DEL INCR, DECR, APPEND
List LPUSH, RPUSH, LSET LRANGE, LINDEX, LLEN LPOP, RPOP, LTRIM BLPOP, BRPOP
Set SADD SMEMBERS, SISMEMBER, SCARD SREM, SPOP SINTER, SUNION, SDIFF
ZSet ZADD, ZINCRBY ZRANGE, ZREVRANGE, ZSCORE, ZRANK ZREM, ZREMRANGEBYRANK ZRANGEBYSCORE
Hash HSET, HMSET, HINCRBY HGET, HMGET, HGETALL, HKEYS, HVALS HDEL HEXISTS, HLEN

9.2 常见错误与解决方案

错误信息 原因 解决方法
WRONGTYPE Operation against a key holding the wrong kind of value 对 key 使用了错误类型的命令(如对 String 执行 LPUSH) TYPE key 查看类型,再用正确命令
ERR value is not an integer or out of range 对非数字值执行 INCR / DECR 确保值可转为整数,或先 SET 数字
(error) CLUSTERDOWN The cluster is down 集群模式下槽位未全覆盖或部分节点故障 检查集群状态 CLUSTER INFO
MISCONF Redis is configured to save RDB snapshots 磁盘空间不足或权限问题 检查 dir 目录权限和磁盘空间
ERR unknown command 'FLUSHALL' 生产环境禁用了危险命令 检查配置文件 rename-command 设置
Python 返回 b'value' decode_responses 未开启 创建 Redis 对象时加 decode_responses=True
阻塞操作超时 BRPOPBLPOP 超时设置太小 调大超时值或设为 0(无限阻塞)

十、本期知识点一览表

模块 核心内容 关键命令/案例
String 底层 SDS,原子计数器,分布式锁基础 SET NX EX, INCR, MSET, GETSET
List quicklist,左右端操作,阻塞队列 LPUSH + BRPOP, LTRIM 保持长度
Set intset/hashtable,集合运算 SADD, SINTER 共同好友,SPOP 抽奖
ZSet skiplist + dict,排行榜,延时队列 ZADD, ZREVRANGE, ZINCRBY, ZRANGEBYSCORE
Hash ziplist/hashtable,对象存储 HSET, HGETALL, HINCRBY
消息队列 List 模式 vs Pub/Sub vs Streams 生产者-消费者,发布-订阅
Python 连接 redis-py 库 连接池,各类型操作示例
速查与排错 命令速查表,常见错误 类型不匹配、数字转换、集群状态

下一期预告:Redis 持久化(RDB、AOF)与主从复制(一主两从搭建、复制原理)。将深入讲解数据安全与高可用的基础。

相关推荐
南岸的水1 小时前
ubuntu里面SDK编译指令及报错处理
linux·运维·ubuntu
lsyeei1 小时前
MySQL常用索引
数据库·mysql
keira6741 小时前
个人健康日程表(小时级行为系统)
学习·生活
爱网络爱Linux1 小时前
Linux 服务器开机慢?启动链路优化实战
linux·运维·redhat·rhce·rhca·红帽认证
江屿风1 小时前
C++图论基础拓扑排序算法流食般投喂
开发语言·c++·笔记·算法·排序算法
呦呦鹿鸣Rzh1 小时前
Redis Lua 脚本:从入门到避坑指南
redis·junit·lua
buhuizhiyuci1 小时前
【Linux篇】数字世界的底层认识, 它是底层的地基——进程概念的认识
linux·运维·服务器
YangYang9YangYan1 小时前
专科大数据技术学习数据分析的价值分析
大数据·学习·数据分析
BizViewStudio1 小时前
2026 年 GEO 成为企业线上流量增长核心风口|2026 品牌 GEO 运营指南,6 家全链路优化服务商解析
运维·网络·人工智能·microsoft·ai