命令执行与异步管线
This content is not available in your language yet.
Redisson 的“异步”不是把同步方法包进线程池,而是让命令从编码到网络回调都沿着 RFuture/CompletionStage 传播。
先给答案:Redisson 的“异步”不是把同步方法包进线程池,而是让命令从编码到网络回调都沿着 RFuture/C…
Section titled “先给答案:Redisson 的“异步”不是把同步方法包进线程池,而是让命令从编码到网络回调都沿着 RFuture/C…”Redisson 的“异步”不是把同步方法包进线程池,而是让命令从编码到网络回调都沿着 RFuture/CompletionStage 传播。 正文沿“调用链 -> 关键数据 -> 为什么不直接暴露 Netty Future”展开:先确认入口和状态归属,再跟踪控制流或数据流的推进,最后落到对外可观察的结果。
主要失效边界集中在“decoder 不匹配、Future 回调阻塞、批处理误当事务”这些场景。它们破坏的是容量、顺序、并发或生命周期前提;排查时应先确认状态是否仍由正确对象持有,再核对推进条件和清理路径。
RLock.tryLockAsync -> CommandAsyncExecutor.evalWriteSyncedNoRetryAsync -> CommandAsyncService.evalWriteAsync -> command + codec + keys/params -> connection manager selects node -> Netty write / decoder -> RFuture completionCommandAsyncService 在 redisson/src/main/java/org/redisson/command/CommandAsyncService.java:68 定义核心实现;脚本入口 evalWriteAsync 位于 :471-494。对象层通过接口而非具体连接类型依赖它。
| 数据 | 来源 | 用途 |
|---|---|---|
| key | 对象的 getRawName() |
路由和 Redis key |
Codec |
对象或客户端配置 | 参数编码、结果解码 |
RedisCommand |
RedisCommands 常量 |
返回值类型和 decoder |
RFuture |
执行器返回 | 组合重试、通知、异常 |
一次脚本调用必须同时提供返回类型和 decoder;同一段 Lua 可以用 EVAL_NULL_BOOLEAN、EVAL_LONG 等不同命令描述,从而决定 Java 侧如何解释 nil、整数和布尔值。
为什么不直接暴露 Netty Future
Section titled “为什么不直接暴露 Netty Future”替代方案:业务对象直接返回 Netty 的 Future。
为什么不行:上层会被 Netty 类型、线程模型和异常转换绑死,批处理、同步等待和 Reactive 适配也难以统一。
证据:Redisson 对外使用 RFuture,对象实现通过 CompletableFutureWrapper 在 RedissonBaseLock.java:162-177 等位置转换阶段结果。
批处理与一致性
Section titled “批处理与一致性”批处理不是自动事务。命令可以先进入 CommandBatchService,再由 executeAsync() 发送;是否原子取决于批处理选项、Redis 模式和脚本边界。锁释放时还会根据执行器类型处理 unlock latch,见 RedissonBaseLock.java:218-250。
| 场景 | 现象 | 原因 | 规避 |
|---|---|---|---|
| decoder 不匹配 | 类型转换异常或 nil 语义错误 | Lua 返回值与 RedisCommand 不一致 |
选择正确的 EVAL_* 命令 |
| Future 回调阻塞 | Netty 线程延迟扩大 | 在完成回调中做同步 IO | 回调只做状态推进,重活转业务 executor |
| 批处理误当事务 | 中间命令可见或部分成功 | pipeline 与 transaction 语义不同 | 需要原子性时用 Lua 或事务 |
协议客户端的异步 API 应把“编码、路由、发送、解码、异常”抽象成一条可组合流水线,而不是单独提供一个 async 后缀。这样同步 API 只是对 Future 的等待适配。
面试锚点
RedisCommand为什么不仅是命令名?RFuture和直接线程池异步有什么区别?- pipeline、transaction 和 Lua 的原子性边界如何区分?