当前位置: 首页 > news >正文

XXL-JOB 2.5.0 多节点部署踩坑总结

场景:生产环境将 xxl-job-core 从 2.3.x 升级至 2.5.0,calculation 服务部署在双节点(11.122.187.86 / 11.122.187.87),升级后 XXL-JOB Admin 无法调用 calculation 执行器,报Connection reset


一、背景说明

SD 系统使用 XXL-JOB 做定时任务调度,整体结构如下:

┌──────────────────────────────────────────┐ │ sdms-job(调度中心 + 自身执行器) │ │ server.port = 9093 │ │ executor.appname = xxl-job-executor-sample│ │ executor.port = 9998 │ └────────────────┬─────────────────────────┘ │ 调度 ┌───────────┴──────────┐ ▼ ▼ sd-calculation sd-calculation (11.122.187.86) (11.122.187.87) server.port = 9094 server.port = 9094 executor.port = 9988 executor.port = 9988 appname = em-calculation-executor

升级 xxl-job-core 到2.5.0后,sdms-job 自身执行器正常,但调度中心调用 sd-calculation 的两个节点时持续报错:

xxl-job remoting error(Connection reset), for url : http://11.122.187.86:9988/run xxl-job remoting error(Connection reset), for url : http://11.122.187.87:9988/run

二、遇到的报错清单

升级过程中依次遭遇以下问题:

报错 1:NoClassDefFoundError: io/netty/handler/timeout/IdleStateHandler

java.lang.NoClassDefFoundError: io/netty/handler/timeout/IdleStateHandler at com.xxl.job.core.server.EmbedServer.start(EmbedServer.java:...)

原因:xxl-job-core 2.5.0 依赖 Netty,但项目原有 Netty 版本(4.1.43.Final)与 2.5.0 要求不兼容,或 Netty 未被正确传递依赖。

解决:在 pom.xml 中将 Netty 显式升级到4.1.90.Final

<dependency><groupId>io.netty</groupId><artifactId>netty-all</artifactId><version>4.1.90.Final</version></dependency>

报错 2:Optional int parameter 'triggerStatus' cannot be translated into a null value

java.lang.IllegalStateException: Optional int parameter 'triggerStatus' is present but cannot be translated into a null value due to being declared as a primitive type. Consider declaring it as object wrapper for the corresponding primitive type.

原因:xxl-job 2.5.0 Admin 页面的某些查询接口中,请求参数triggerStatus使用了基本类型int接收,但前端传参时值为空,Spring MVC 无法将空值转为int

解决:在调度中心(sdms-job)对应 Controller 的入参中,将int triggerStatus改为Integer triggerStatus


报错 3:Connection reset— 核心问题

xxl-job remoting error(Connection reset), for url : http://11.122.187.86:9988/run

这是本次升级最核心的问题,下一章详细分析。


三、核心问题:Connection reset的根本原因

3.1 XXL-JOB Executor 的通信机制

XXL-JOB Executor 内嵌了一个Netty HTTP Server,专门用于接收来自 Admin 的调度指令(/run/beat/kill等)。

Admin ──HTTP──▶ Executor 的 Netty Server(executor.port)──▶ 执行 JobHandler

这个 Netty Server 监听的端口就是配置文件中的executor.port与 Spring Boot 的server.port完全独立

3.2 IP 自动探测机制

当配置文件中executor.ipexecutor.address均为空时,XXL-JOB 会调用IpUtil.getIp()自动探测本机 IP,逻辑如下:

// XXL-JOB 源码 IpUtil.getIp()(简化)for(NetworkInterfaceiface:NetworkInterface.getNetworkInterfaces()){if(iface.isLoopback()||iface.isVirtual()||!iface.isUp())continue;for(InetAddressaddr:iface.getInetAddresses()){if(addrinstanceofInet4Address){returnaddr.getHostAddress();// 返回第一个找到的非回环 IPv4}}}

对于 86、87 两台可直接访问的宿主机而言,自动探测完全没有问题:86 节点自动探测到11.122.187.86,87 节点自动探测到11.122.187.87,各自向 Admin 注册自己的地址,Admin 可正常回调。

⚠️注意:如果是容器(Docker/K8s)部署,自动探测拿到的是容器内网 IP(如172.17.0.x),Admin 将无法路由,此时必须显式指定ipaddress

3.3 问题链路还原

本次Connection reset的根本原因是配置错误——有人试图把两个节点的地址用逗号写在同一份配置里(详见 3.4),导致注册地址非法,Admin 拿到错误的 URL 后发起调用,自然 reset。

1. sdms-calculation 配置了非法 address(逗号分隔多个 IP) 注册地址:http://11.122.187.87:9988,http://11.122.187.86:9988(整体当成一个字符串) 2. Admin 触发任务 调用:http://11.122.187.87:9988,http://11.122.187.86:9988/run ← 非法 URL! 3. 报错 Connection reset

为什么 sdms-job 主节点没问题?

sdms-job 只部署一个节点,address为空,自动探测到本机 IP 正常注册,Admin 与执行器在同一服务内调用自己,链路完全可达。

3.4 配置写成多个 IP 逗号分隔是错误的

部分同学尝试将两个节点的 IP 写在同一份配置里:

# ❌ 错误写法executor:address:http://11.122.187.87:9988,http://11.122.187.86:9988ip:11.122.187.87,11.122.187.86

这是不合法的executor.addressexecutor.ip是单值字段,代表"这个 JVM 实例自己的地址"。逗号分隔后,框架会把整个字符串当成一个 URL 去注册,导致注册异常,Admin 控制台出现非法地址。


四、多节点部署的正确配置方式

核心原则

同一个项目打一个 JAR 包,部署到多台机器。每台机器启动后,XXL-JOB 自动探测本机 IP,分别向 Admin 注册各自的地址,从而在 Admin 上形成一个多机执行器集群。

4.1 正确理解:多节点 ≠ 一份配置写多个 IP

XXL-JOB 的多节点是通过**“多个实例各自注册”**实现的,不是在一份配置里写多个地址:

同一份 application-emeaprod.yml(appname = em-calculation-executor,ip/address 留空) │ ├── 部署到 11.122.187.86 → 启动后自动注册 http://11.122.187.86:9988 │ └── 部署到 11.122.187.87 → 启动后自动注册 http://11.122.187.87:9988 ↓ 两个实例都向 Admin 注册后 ↓ Admin 中 em-calculation-executor 执行器组 ┌─────────────────────────────┐ │ http://11.122.187.86:9988 │ [在线] │ http://11.122.187.87:9988 │ [在线] └─────────────────────────────┘ 按路由策略分发任务

4.2 配置文件(两台机器共用同一份)

ipaddress留空,XXL-JOB 在每台机器上启动时自动探测本机 IP 注册,两台机器无需区分配置:

# application-emprod.ymlxxl:job:admin:addresses:http://vicoe-xs-job-prod.earth.xpaas.t.comaccessToken:uqCkJP#xB4mmiPZ3WIVvO9sQP78aXd!timeout:30executor:appname:em-calculation-executor# 两台机器相同,代表同一个执行器组address:# 留空,自动探测本机 IP 生成注册地址ip:# 留空,自动探测本机 IPport:9988# Netty 监听端口,两台机器相同logpath:/data/applogs/emeaCalculation/jobhandlerlogretentiondays:-1

为什么 86 和 87 可以留空自动探测?
因为两台机器均为可直接访问的宿主机,网络接口与业务 IP 一一对应。86 机器自动探测结果就是11.122.187.86,87 机器自动探测结果就是11.122.187.87,Admin 可以直接回调,无需手动指定。

4.3 启动命令(两台机器相同)

java-jarsdms-calculation.jar--spring.profiles.active=emeaprod

86 节点启动 → 自动注册http://11.122.187.86:9988
87 节点启动 → 自动注册http://11.122.187.87:9988

4.4 什么情况下需要显式指定 ip/address?

场景是否需要显式指定
裸机 / VM,单网卡,IP 直接可达❌ 不需要,留空自动探测即可
裸机 / VM,多网卡,需指定特定网卡✅ 需要,否则可能探测到错误网卡
容器部署(Docker/K8s),宿主机与容器 IP 不同✅ 必须指定宿主机 IP,否则注册容器内网 IP 导致 Admin 无法回调

五、实现轮询效果

两台机器都正确注册后,在XXL-JOB Admin → 任务管理中,将em-calculation-executor执行器下的任务路由策略设为:

路由策略说明
ROUND(轮询)依次调用每个在线节点,均衡分发 ✅ 推荐
RANDOM(随机)随机选一个节点
FAILOVER(故障转移)优先调用第一个在线节点,故障时切换
BUSYOVER(忙碌转移)优先调用空闲节点

六、验证步骤

步骤 1:确认 9988 端口在宿主机上监听

在 86/87 节点执行:

ss-lntp|grep9988# 或netstat-lntp|grep9988

期望输出:java ... LISTEN 0.0.0.0:9988

步骤 2:确认 Admin 可达执行器端口

在 Admin 所在机器执行:

curl-vhttp://11.122.187.86:9988/ --max-time3curl-vhttp://11.122.187.87:9988/ --max-time3

只要没有Connection reset/Connection refused即为可达(返回什么 HTTP 状态码不重要)。

步骤 3:查看执行器启动注册日志

在 sdms-calculation 日志中搜索:

xxl-job registry success

确认打印的注册地址是http://11.122.187.86:9988而不是http://172.17.x.x:9988

步骤 4:Admin 控制台确认

执行器管理 → emea-calculation-executor,机器地址列表应显示:

http://11.122.187.86:9988 [在线] http://11.122.187.87:9988 [在线]

七、总结

问题原因解决方案
NoClassDefFoundError: IdleStateHandlerNetty 版本不兼容 2.5.0升级netty-all4.1.90.Final
triggerStatus cannot be translated into nullAdmin Controller 参数类型用int接收空值改为Integer包装类型
Connection reset无法调用执行器address/ip用逗号写了两个节点的地址,框架将整个字符串当成非法 URL 注册,Admin 调用失败留空让每台机器自动探测各自 IP,两台机器用相同appname各自注册即可组成集群
多节点配置误区认为在一份配置里写多个 IP 就能"告知"两台机器,实际上address/ip是当前实例自身地址的单值字段同一 JAR 包部署到多台机器,每台各自启动注册,Admin 自动感知所有在线节点

核心记住一句话:

XXL-JOB 多节点集群的正确做法:同一份配置(ip/address留空)+ 同一个appname,部署到多台可直接访问的机器,每台机器启动后自动探测本机 IP 向 Admin 注册,Admin 按路由策略(轮询/随机等)在所有在线节点间分发任务。

http://www.zskr.cn/news/1443090.html

相关文章:

  • 为什么你的Sora 2微调总失败?:3个被官方文档隐藏的因果嵌入约束条件(含PyTorch底层hook代码)
  • 3步玩转AMD Ryzen超频:SMU Debug Tool终极指南
  • 收藏!AI创业团队早期最容易犯的错:缺了这个角色,demo再好也白搭!
  • BitCPM-CANN架构详解:从自定义三值算子到昇腾910B分布式训练的完整栈
  • 如何免费下载国家中小学智慧教育平台电子课本:tchMaterial-parser终极指南
  • 智慧树自动刷课插件:3步安装,释放90%学习时间
  • 如何永久保存你的微信聊天记录?WeChatMsg完全指南让数据真正属于你
  • StreamCap:免费开源的多平台直播录制工具终极指南
  • 基于GreenPAK的智能占空比控制器设计:实现物联网设备超低功耗电源管理
  • 【Sora 2虚拟场景搭建实战指南】:20年AI基建专家亲授5大避坑法则与实时渲染优化黄金参数
  • 【电子书】琼瑶作品全集(共60册)
  • 推荐成都护栏网厂家供应商品牌实力深度对比解析 - 速递信息
  • 20252907-2025-2026-2-网络攻防实践课程总结
  • 如何用世界最强将棋AI YaneuraOu快速提升棋艺?完整入门教程
  • 洛阳市 涧西区 水电维修 上门施工|维小达电路维修、水管漏水抢修、管道疏通、马桶维修、暖气维修一站式服务 - 维小达科技
  • 第二章:面向对象编程(基础)
  • 2026年重庆除甲醛:口碑好的厂家怎么选更靠谱? - GrowthUME
  • Arduino传感器融合实战:超声波与PIR构建智能安防系统
  • 5个简单步骤:使用Video2X轻松实现视频画质全面升级
  • 突破性Mac版百度网盘SVIP破解插件:技术原理与高速下载完整指南
  • 从一次Kafka连接失败排查说起:手把手教你定位Spring-Kafka与Kafka-Client版本冲突问题
  • 2026年出国留学机构推荐:五家优选品牌全方位解析 - 科技焦点
  • 如何永久保存微信聊天记录?三大核心功能深度解析
  • 2026年本科留学咨询机构推荐:五家优选品牌深度解析 - 科技焦点
  • 2026年泰州装修公司|泰州家装公司服务品质拆解 - 奔跑123
  • 2026年泰州家装公司服务调研:本土与连锁品牌的服务对比 - 奔跑123
  • 告别Cascade!在UE5.0.1中高效迁移并升级你的老粒子特效到Niagara
  • 专业的万向球厂家 - GrowthUME
  • 新手也能上手!高效论文写作全流程AI论文网站推荐(2026 最新)
  • 告别串口线!用STC8H的USBCDC功能实现USB虚拟串口调试(Keil C51配置详解)