文章首发到公众号:月伴飞鱼,每天分享程序员职场经验!
文章内容收录到个人网站,方便阅读: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,但要处理可能的部分失败情况。