xxl-job执行器自动注册是怎么做的?

804 阅读4分钟

最近遇到了一个 xxl-job 执行器自动注册 ip 错误的问题,结合源码分析了一下 xxl-job 执行器的自动注册流程,分享给大家。

这里我用 xxl-job 最新的 v2.4.2 版本源码用做本文代码示例分析。

一、xxl-job 执行器自动注册 ip 错误

先说一下问题发生的场景,这个问题来自我们测试 xxl-job 后管新增一个执行器时,新增执行器时选择的是自动注册机制,也就是由 xxl-job 自动填写我们的执行器 ip 地址。

相信使用过 xxl-job 的众多开发同学里,有很多人新增执行器时都是跟我们一样选择自动注册。这个操作在容器化部署来临之前没什么问题,但是随着后来 docker 容器的流行,线上服务大多以容器方式放行。

容器的 ip 都是虚拟 ip,不代表物理机真实通信地址的 ip,这里就有一个问题,如果 xxl-job 后管跟执行器不在同一个服务器部署,并且执行器自动注册提交的是容器 ip,那么就会产生定时任务执行失败的问题,因为 xxl-job 后管调用不通执行器。

这里给大家画一个 xxl-job 调用执行器的示意图,方便大家理解,

画板

给大家讲一下示意图:

  1. xxl-job 执行器在启动时会向 xxl-job 后管提交当前服务器 ip,获取逻辑在 com.xxl.job.core.util.IpUtil#getIp 方法中,这个方法在最新版本里默认优先使用 JDK 提供的 InetAddress.getLocalHost() 方法获取本机 ip。获取不到的话再使用 JDK 提供的 NetworkInterface.getNetworkInterfaces() 方法遍历本机网卡获取 ip。

InetAddress.getLocalHost() 的一些坑:

  1. 在 Linux 环境通过获取 /etc/hosts 和 /etc/resolv.conf 文件内容,如果在 /etc/hosts 文件内容中没有匹配到对应的 ip 地址,则通过 /etc/resolv.conf 中配置的 DNS 地址,向 DNS 服务器发出域名解析请求;
  2. 如果访问 DNS 服务存在性能问题;
  3. InetAddress.getLocalHost() 实现中还加了 synchronized 锁,并发环境中会影响性能。
  1. 调用 xxl-job 后管提供的 api/registry 接口,传递 xxl-job 执行器名称以及通信地址。
  2. xxl-job 后管触发定时任务时,会调用 xxl-job 执行器提供的 /run 接口来执行对应任务。

在上面流程中,因为第二步提交的 xxl-job 执行器通信地址错误,因而导致第三步执行失败。那么怎么解决这个问题嘞,其实很简单,xxl-job 后管使用手动注册填写可以联通的执行器地址即可。

二、xxl-job执行器自动注册流程

xxl-job 执行器的自动注册流程其实很简单,这里给大家梳理一下,

画板

三、执行器注册

客户端在引入 xxl-job 执行器启动时,xxl-job 执行器会启动 ExecutorRegistryThread 线程,

这个线程是专门来做执行器注册的,它会每隔 30 秒调用 xxl-job 后管的 /api/register 接口提交执行器地址和名称。

xxl-job 后管收到执行器的注册信息后,会通过 registryOrRemoveThreadPool 线程池异步保存执行器信息并发送成功响应。

registryOrRemoveThreadPool 线程池会判断是否已经存在当前执行器注册记录,不存在就新建,存在就更新执行器最新注册时间。

所以当我们在 xxl-job 后管新增执行器,选择自动注册的时候,执行器的地址就是这么来的。

四、执行器移除

移除有两个方式,一种是正常结束 xxl-job 执行器,比如停止应用程序,xxl-job 执行器就会调用 /api/registryRemove 接口用来移除当前执行器注册信息。还有一种 xxl-job 后管启动的 registryMonitorThread 线程自动检测注册时间已经超期的执行器注册信息。

registryMonitorThread 线程会查询所有自动注册类型的执行器,然后查询它们对应的注册记录最新时间是否超期,在xxl-job中,这个超期时间是90秒。超过 90 秒后就会移除执行器。

移除时会同时删除 xxl_job_group、xxl_job_registry 表的执行器信息。

四、最后关于IpUtil.getIp() 的一点思考

其实查看 xxl-job 执行器获取执行器 ip 的 com.xxl.job.core.util.IpUtil 文件的提交历史,我们可以发现,早在 18 年就有人发现了这个问题,并向官方提交了 issue 和 pr,并且这个 pr 也被官方认可合并了。

然而官方在 2020 的提交记录中又修改了 com.xxl.job.core.util.IpUtil.getIp 方法,

把本来放到方法末尾的 InetAddress.getLocalHost() 方法又提到了方法开头。。。

看了提交历史和上面关于InetAddress.getLocalHost() 一些坑的朋友,此处应该一脸疑问。。。

这里就暂且当作者基于某种考虑这么做,至于为什么,我已经去 github 提交了 issue,帮大家问了。。。


👨‍💻 技术成长是一场持续的旅程。如果你喜欢这篇文章,欢迎关注我的公棕号「程序员wayn」,技术成长社群正招募热爱coding的你,加入我们,一起深入探讨技术、分享经验、共同成长!