Redis Pipeline 和 MGET,如果报错了,他们的异常机制是什么样的?

495 阅读3分钟

文章首发到公众号:月伴飞鱼,每天分享程序员职场经验!

文章内容收录到个人网站,方便阅读:hardyfish.top/

Redis pipeline MGET 的异常机制

当 Redis pipelineMGET 在执行过程中遇到错误时,它们的错误处理机制有所不同,具体如下:

1. MGET 的异常机制

情况 1:某个 Key 不存在

  • MGET 对于不存在的 key,不会报错,而是返回 nil(Python 中是 None)。

  • 示例:

    redis> MGET key1 key2 key3
    1) "value1"
    2) nil
    3) "value3"
    
    • key2 不存在,但 MGET 不会抛出异常,只是返回 nil

情况 2:Redis 服务器崩溃

  • 如果 Redis 服务器 不可用(down)MGET 调用会失败,返回 连接异常

  • 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 错误:

    (error) CROSSSLOT Keys in request don't hash to the same slot
    
  • 解决方案:

    • 确保 keys 在同一槽位,使用 哈希标签 {}

      MGET {user}:1 {user}:2
      

2. pipeline 的异常机制

情况 1:某个命令失败

  • pipeline 不会影响整个批次,即使其中某个命令失败,Redis 仍然会继续执行其他命令。

  • 示例:

    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 仍然返回部分成功的结果:

      ['OK', None, ResponseError('WRONGTYPE Operation against a key holding the wrong kind of value'), 'value1']
      

情况 2:Redis 服务器崩溃

  • 如果 Redis 服务器宕机或连接断开:

    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 错误。

  • 但如果 某个分片发生错误,会导致部分请求失败:

    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")  # 可能在 shard2try:
        results = pipe.execute()
        print(results)
    except redis.exceptions.RedisClusterException as e:
        print(f"Redis Cluster 失败: {e}")
    
    • 部分 key 可能成功,部分失败,需要在应用层检查返回值。

3. pipeline vs MGET 异常处理对比

异常情况MGETpipeline
Key 不存在返回 nil返回 None
单个命令错误MGET 只有 GET,基本不会报错只影响该条命令,不影响其他命令
Redis 宕机连接异常 (ConnectionError)整个 pipeline 失败 (ConnectionError)
跨分片查询CROSSSLOT 错误支持跨分片,但可能部分失败
部分命令失败N/A失败的命令返回 ResponseError,其余命令不受影响

4. 结论

  • 如果 key 可能不存在

    • MGET 只会返回 nil,不会报错。
    • pipeline 返回 None,但仍然继续执行后续命令。
  • 如果 Redis 宕机

    • MGETpipeline 都会失败,但 pipeline 影响范围更大。
  • 如果 Redis Cluster 跨分片

    • MGET 不支持,报 CROSSSLOT 错误。
    • pipeline 支持,但部分 key 可能失败。
  • 如果某个命令失败

    • pipeline 不会影响其他命令,但需要在代码中手动处理 ResponseError

总结

  • 批量读取推荐 MGET,如果 key 都在一个分片。
  • 批量操作(读写混合)用 pipeline,但要注意部分失败情况。
  • 分布式 Redis(Cluster 模式)推荐 pipeline,但要处理可能的部分失败情况。