文章首发到公众号:月伴飞鱼,每天分享程序员职场经验!
文章内容收录到个人网站,方便阅读:hardyfish.top/
Redis pipeline
和 MGET
的异常机制
当 Redis pipeline
和 MGET
在执行过程中遇到错误时,它们的错误处理机制有所不同,具体如下:
1. MGET
的异常机制
情况 1:某个 Key 不存在
-
MGET
对于不存在的 key,不会报错,而是返回nil
(Python 中是None
)。 -
示例:
goredis> MGET key1 key2 key3 1) "value1" 2) nil 3) "value3"
key2
不存在,但MGET
不会抛出异常 ,只是返回nil
。
情况 2:Redis 服务器崩溃
-
如果 Redis 服务器 不可用(down) ,
MGET
调用会失败,返回 连接异常。 -
Python 示例:
pythonimport redis r = redis.StrictRedis(host="127.0.0.1", port=6379, decode_responses=True) try: result = r.mget(["key1", "key2"]) print(result) except redis.exceptions.ConnectionError as e: print(f"Redis 连接失败: {e}")
- 当 Redis 宕机 时,会抛出
redis.exceptions.ConnectionError
。
- 当 Redis 宕机 时,会抛出
情况 3:跨分片查询(Redis Cluster 模式)
-
MGET
不能跨分片 ,如果 keys 在不同分片,会报CROSSSLOT
错误:vbnet(error) CROSSSLOT Keys in request don't hash to the same slot
-
解决方案:
-
确保 keys 在同一槽位 ,使用 哈希标签
{}
:sqlMGET {user}:1 {user}:2
-
2. pipeline
的异常机制
情况 1:某个命令失败
-
pipeline
不会影响整个批次,即使其中某个命令失败,Redis 仍然会继续执行其他命令。 -
示例:
pythonimport redis r = redis.StrictRedis(host="127.0.0.1", port=6379, decode_responses=True) pipe = r.pipeline() pipe.set("key1", "value1") pipe.get("non_existing_key") # 不存在的 key,不会报错,只返回 None pipe.lpush("key1", "value2") # 错误:尝试对字符串执行列表操作 pipe.get("key1") try: results = pipe.execute() print(results) except redis.exceptions.RedisError as e: print(f"Redis 命令失败: {e}")
-
如果
LPUSH key1 value2
失败,它 不会影响get key1
的执行,Redis 仍然返回部分成功的结果:css['OK', None, ResponseError('WRONGTYPE Operation against a key holding the wrong kind of value'), 'value1']
-
情况 2:Redis 服务器崩溃
-
如果 Redis 服务器宕机或连接断开:
pythontry: pipe = r.pipeline() pipe.set("key1", "value1") pipe.execute() except redis.exceptions.ConnectionError as e: print(f"Redis 连接失败: {e}")
- 所有 pipeline 命令都会失败 ,返回
redis.exceptions.ConnectionError
。
- 所有 pipeline 命令都会失败 ,返回
情况 3:跨分片查询(Redis Cluster 模式)
-
pipeline
可以跨分片执行 ,但 Redis 会自动拆分请求 并分别发送到不同分片,不会报CROSSSLOT
错误。 -
但如果 某个分片发生错误,会导致部分请求失败:
pythonimport rediscluster startup_nodes = [{"host": "127.0.0.1", "port": 6379}] rc = rediscluster.RedisCluster(startup_nodes=startup_nodes, decode_responses=True) pipe = rc.pipeline() pipe.get("user:1") # 可能在 shard1 pipe.get("order:123") # 可能在 shard2 try: results = pipe.execute() print(results) except redis.exceptions.RedisClusterException as e: print(f"Redis Cluster 失败: {e}")
- 部分 key 可能成功,部分失败,需要在应用层检查返回值。
3. pipeline
vs MGET
异常处理对比
异常情况 | MGET | pipeline |
---|---|---|
Key 不存在 | 返回 nil |
返回 None |
单个命令错误 | MGET 只有 GET ,基本不会报错 |
只影响该条命令,不影响其他命令 |
Redis 宕机 | 连接异常 (ConnectionError ) |
整个 pipeline 失败 (ConnectionError ) |
跨分片查询 | CROSSSLOT 错误 |
支持跨分片,但可能部分失败 |
部分命令失败 | N/A | 失败的命令返回 ResponseError ,其余命令不受影响 |
4. 结论
-
如果 key 可能不存在:
MGET
只会返回nil
,不会报错。pipeline
返回None
,但仍然继续执行后续命令。
-
如果 Redis 宕机:
MGET
和pipeline
都会失败 ,但pipeline
影响范围更大。
-
如果 Redis Cluster 跨分片:
MGET
不支持 ,报CROSSSLOT
错误。pipeline
支持,但部分 key 可能失败。
-
如果某个命令失败:
pipeline
不会影响其他命令 ,但需要在代码中手动处理ResponseError
。
总结
- 批量读取推荐
MGET
,如果 key 都在一个分片。 - 批量操作(读写混合)用
pipeline
,但要注意部分失败情况。 - 分布式 Redis(Cluster 模式)推荐
pipeline
,但要处理可能的部分失败情况。