Redis pipeline 和 MGET,如果报错了,他们的异常机制是什么样的?
1 个回答
改变的秘密,是把所有的精力全放在新的事物上,而不是与过去抗衡。凯恩## **Redis `pipeline` 和 `MGET` 的异常机制** 当 Redis **`pipeline`** 和 **`MGET`** 在执行过程中遇到错误时,它们的错误处理机制有所不同,具体如下: ## **1. `MGET` 的异常机制** ### **情况 1:某个 Key 不存在** - `MGET` 对于不存在的 key,不会报错,而是返回 `nil`(Python 中是 `None`)。 - 示例: ```shell redis> MGET key1 key2 key3 1) "value1" 2) nil 3) "value3" ``` - `key2` 不存在,但 `MGET` **不会抛出异常**,只是返回 `nil`。 ### **情况 2:Redis 服务器崩溃** - 如果 Redis 服务器 **不可用(down)**,`MGET` 调用会失败,返回 **连接异常**。 - Python 示例: ```python import 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`。 ### **情况 3:跨分片查询(Redis Cluster 模式)** - `MGET` **不能跨分片**,如果 keys 在不同分片,会报 `CROSSSLOT` 错误: ```shell (error) CROSSSLOT Keys in request don't hash to the same slot ``` - 解决方案: - **确保 keys 在同一槽位**,使用 **哈希标签** `{}`: ```shell MGET {user}:1 {user}:2 ``` ## **2. `pipeline` 的异常机制** ### **情况 1:某个命令失败** - `pipeline` **不会影响整个批次**,即使其中某个命令失败,Redis 仍然会继续执行其他命令。 - 示例: ```python import 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 仍然返回部分成功的结果: ```shell ['OK', None, ResponseError('WRONGTYPE Operation against a key holding the wrong kind of value'), 'value1'] ``` ### **情况 2:Redis 服务器崩溃** - 如果 Redis 服务器宕机或连接断开: ```python try: pipe = r.pipeline() pipe.set("key1", "value1") pipe.execute() except redis.exceptions.ConnectionError as e: print(f"Redis 连接失败: {e}") ``` - **所有 pipeline 命令都会失败**,返回 `redis.exceptions.ConnectionError`。 ### **情况 3:跨分片查询(Redis Cluster 模式)** - `pipeline` **可以跨分片执行**,但 Redis **会自动拆分请求** 并分别发送到不同分片,不会报 `CROSSSLOT` 错误。 - 但如果 **某个分片发生错误**,会导致部分请求失败: ```python import 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`**,但要处理可能的部分失败情况。发布于 2025-03-12 16:27 •IP属地 安徽举报评论收藏
公众号进入网站体验更佳

