BLMOVE 是 Redis 6.2 替代 BRPOPLPUSH 的唯一推荐阻塞式列表搬运命令,参数更清晰、支持同 Key 旋转与集群槽约束;其 timeout 固定第五位,方向参数须大写,source 与 destination 必须同槽,超时返回 nil,destination 不存在时自动创建。

BLMOVE 是 Redis 6.2 中替代 BRPOPLPUSH 的唯一推荐阻塞式列表搬运命令,它完全兼容原语义,但参数结构更清晰、方向控制更明确,且支持同 Key 旋转和集群槽约束检查。
BLMOVE 与 BRPOPLPUSH 的参数映射关系
BRPOPLPUSH source destination timeout 的行为,等价于 BLMOVE 的以下组合:
-
BLMOVE source destination RIGHT LEFT timeout→ 原 BRPOPLPUSH(右弹左推) -
BLMOVE source destination LEFT RIGHT timeout→ 相当于“左弹右推”,即反向轮询场景 -
BLMOVE source source RIGHT RIGHT timeout→ 同 Key 旋转(类似 BRPOPLPUSH source source timeout)
注意:timeout 必须是数字,不能为字符串;0 表示无限等待,非 0 值单位为秒(Redis 6.0+ 支持浮点数,如 0.1)。
集群环境下 BLMOVE 的槽位限制必须显式处理
BLMOVE 要求 source 和 destination 必须位于同一哈希槽,否则报错 CROSSSLOT Keys in request don't hash to the same slot。这不是可选优化,而是强制约束。
- 若使用键名带花括号(如
task:{user123}:pending和task:{user123}:processing),Redis 会自动按{user123}计算槽位,通常满足要求 - 若键名无一致性哈希标签(如
queue:src和queue:dst),需手动确保二者在相同节点,或改用CLUSTER KEYSLOT验证 - 跨槽调用会直接失败,不会降级或重试
常见误用:把 BLMOVE 当作 LMOVE 加 timeout 使用
BLMOVE 不是 “LMOVE + 阻塞”,它的阻塞逻辑只作用于 source 列表为空时;一旦 source 有数据,它立刻执行并返回元素,不等待 destination 准备就绪(destination 不存在会自动创建)。
- 错误认知:“加了 timeout 就能保证两端都 ready” → 实际上 destination 创建是原子的,无需预热
- 典型陷阱:在 Lua 脚本中混用
BLMOVE和EXISTS判断 destination,脚本内无法阻塞,应避免 - 超时返回值是
nil(空回复),不是空数组或空字符串,客户端需用== nil或isNull()判断
迁移旧 BRPOPLPUSH 代码时最易忽略的细节
BRPOPLPUSH 在 source 为空且超时后,如果 destination 原本不存在,它不会创建;而 BLMOVE 即使超时,只要执行过一次搬运(哪怕超时前没发生),destination 就已存在。但更重要的是:
- BRPOPLPUSH 的 timeout 参数位置固定为第三位;BLMOVE 的 timeout 固定为第五位,中间两个方向参数不可省略
- 方向参数必须全大写:
LEFT/RIGHT,小写或混合大小写(如left)会导致ERR unknown command - 没有
BLMOVE的“非阻塞变体”——想做非阻塞搬运,必须用LMOVE,不能靠设 timeout=0 模拟
真正棘手的地方在于:BLMOVE 的原子性涵盖“弹出 + 推入 + 超时判断”全过程,但它的日志/监控埋点很难拆解哪一步耗时,线上排查阻塞延迟时,得结合 SLOWLOG 和 client list 的 flags=b 状态综合看。











