DEBUG.WIKI
京东云;让 AI 进入真实业务;零售 · 物流 · 客服 · 硬件;查看方案 →
ZgoCloud:多地区部署,按需选节点;日本、美国、香港、德国
Evoxt;最高 6.0GHz CPU;高频云服务器 · 免费每周备份;查看配置 →

Lettuce 缺少 jdk.net

jlink 镜像缺少 jdk.net 时,Lettuce 7.5.2 的 NIO 保活探测可能让应用启动失败。采用含修复的兼容客户端,或在原模块列表中补齐 jdk.net。

应用在普通 JDK 上能启动,换成 jlink 精简镜像后,Lettuce 初始化时报 NoClassDefFoundError: jdk/net/ExtendedSocketOptions。如果调用栈经过 ExtendedKeepAliveSupport$ExtendedNioSocketOptions,先检查镜像是否包含 jdk.net;此时异常可能发生在 Redis 连接建立之前。

Lettuce 7.5.2 的 NIO 扩展保活探测会直接引用这个类。镜像删掉模块后,类初始化失败,旧探测没有把它当成“不支持扩展选项”。7.7.0 已包含修复,核对过的 7.9.0 也会在模块缺失时退回普通 SO_KEEPALIVE。

看实际运行镜像

使用应用所在容器或发行镜像里的 Java 查看模块,不用开发机的完整 JDK 代替:

java --list-modules

确认输出中是否有 jdk.net,再核对部署产物实际解析出的 Lettuce 版本。依赖声明和最终打包版本可能不同。

这个判断还需要完整调用栈。缺失其他业务类、依赖冲突或另一条 NoClassDefFoundError,不能用添加 jdk.net 统一处理。可用的原生传输也可能绕过 NIO 探测,因此同一个精简镜像在不同传输条件下未必表现相同。

修客户端或镜像

可以按项目的依赖管理方式采用包含 7.7.0 修复的兼容版本。框架管理了 Lettuce、Netty 等依赖时,核对整组兼容关系,不只手工替换一个 JAR。修复让缺失模块成为可处理的能力缺失,而不是启动异常。

如果镜像由项目维护,并且确实需要扩展保活选项,在原来的 jlink 模块列表中加入 jdk.net,重新构建镜像,保留原有模块和启动配置。不要用一份仅包含新模块的列表覆盖旧列表。模块已经被裁掉时,给运行中的 Java 加 --add-modules=jdk.net 不会把模块安装回来。

是否接受普通保活回退,还取决于连接策略。它不等于扩展保活的空闲时间、探测间隔和次数全部有效;依赖这些参数识别失效连接的应用,需要检查回退后的实际行为。

不用改 Redis 服务端

关闭全部保活、切换原生传输或修改 Redis 超时,都不能直接修复镜像里的类缺失。尤其是类探测已经在初始化阶段发生时,后续配置一个关闭选项也未必能避开异常。

更新后用原部署方式启动,确认连接能够建立,并分别核对需要的保活能力。发布单位应是相容的应用与运行镜像;若需要撤回,恢复这组产物即可,这个问题不要求清空 Redis 数据。