1. 项目概述为什么非得用 PostgreSQL 跑 xxl-job我第一次在生产环境把 xxl-job 换成 PostgreSQL 是因为 MySQL 的锁表问题直接卡死了调度中心。当时线上任务积压超 2000 条每次执行xxl_job_log表的DELETE FROM xxl_job_log WHERE trigger_time 2024-01-01就导致整个调度界面卡顿 3 分钟以上——不是慢是彻底无响应。后来查监控发现MySQL 在执行这个 delete 时会锁住整张表而 xxl-job-admin 的 UI 页面每 5 秒轮询一次xxl_job_log_count结果就是“删日志”和“查总数”两个操作在抢同一把表级锁。这不是配置问题是 MySQL 的 InnoDB 在大表 delete 场景下的固有行为。换成 PostgreSQL 后同样的清理逻辑跑完只耗时 1.7 秒且全程不影响调度、注册、执行状态上报。原因很简单PostgreSQL 的 MVCC 实现更彻底delete 操作本质是标记 tuple 为过期不阻塞其他事务读写配合VACUUM策略还能把空间回收控制在后台异步完成。这不是理论优势是我在金融类客户现场实测出来的——他们每天产生 80 万 条执行日志MySQL 方案撑不过 3 个月就必须做分库分表而 PostgreSQL 配合分区表PARTITION BY RANGE (trigger_time)跑了一年半单表数据量稳定在 1.2 亿行查询延迟始终低于 80ms。所以“支持 PostgreSQL 的 xxl-job 安装部署”绝不是换个数据库连接字符串那么简单。它背后是一整套适配方案SQL 语法兼容性改造、索引策略重设计、事务隔离级别调整、连接池参数优化、以及最关键的——避免踩 PostgreSQL 特有坑点。比如 xxl-job 原生 SQL 里大量使用LIMIT 0,10这种 MySQL 写法在 PostgreSQL 里必须改成LIMIT 10 OFFSET 0又比如xxl_job_registry表的update_time字段MySQL 默认允许ON UPDATE CURRENT_TIMESTAMP但 PostgreSQL 必须显式定义触发器或用DEFAULT NOW() 应用层更新逻辑。这些细节官方文档一句没提但线上一出错就是调度失灵、任务漏跑、注册节点消失——你根本找不到报错日志因为错误全被 Tomcat 的 JDBC 连接池吞掉了。这篇文章就是我把过去三年在 7 个不同行业金融、物流、制造、政务、教育、医疗、电商落地 PostgreSQL 版 xxl-job 的全部经验浓缩出来。不讲原理堆砌只说你装的时候会遇到什么、为什么这么配、哪个参数改错会导致任务注册失败、哪条 SQL 不改就永远查不到执行日志。如果你正准备在 Linux 或 Windows 上部署用的是 Tomcat 9/10目标是让 xxl-job-admin 稳定跑满一年不重启那接下来的内容每一行都是我踩过的坑、调过的参数、验证过的 SQL。2. 整体架构与选型逻辑为什么必须用 Tomcat PostgreSQL 组合2.1 为什么不用 Spring Boot 内嵌容器xxl-job-admin 官方提供两种启动方式Spring Boot 内嵌 Tomcat 和独立 Tomcat 部署。很多人图省事选前者但我在线上环境一律禁用。原因有三个硬伤第一内存泄漏风险不可控。Spring Boot 内嵌 Tomcat 在热部署、JNDI 查找、ClassLoader 卸载场景下极易残留线程和静态引用。我们曾在一个政务云项目中发现连续 12 天未重启后xxl-job-admin的Metaspace区域增长到 1.8GBGC 频率从每小时 2 次飙升至每分钟 3 次最终 OOM 导致调度线程池被 kill。而独立 Tomcat 通过catalina.sh的JAVA_OPTS-XX:MaxMetaspaceSize512m可精准限制且 Tomcat 自身的StandardContext生命周期管理比 Spring Boot 更成熟。第二JDBC 连接池无法深度定制。内嵌模式下 HikariCP 的配置项被 Spring Boot AutoConfigure 层层封装像connection-timeout、validation-timeout、leak-detection-threshold这些关键参数你改了application.properties也未必生效——因为 xxl-job-admin 的XxlJobAdminConfig类里硬编码了部分连接池初始化逻辑。而独立 Tomcat 可以直接在context.xml里定义Resource完全绕过 Spring Boot 的自动装配所有参数直通 JDBC 驱动。第三日志隔离困难。内嵌模式下 Tomcat 日志、Spring 日志、JDBC 日志全混在同一个logs/catalina.out里排查慢 SQL 时要 grep 十几万行日志。独立部署则能用logging.properties分离org.apache.tomcat.jdbc.pool的 DEBUG 日志到单独文件配合logrotate按天切割运维同学查问题效率提升 5 倍以上。提示如果你坚持用 Spring Boot至少把spring.profiles.activeprod加上并在application-prod.properties中显式关闭spring.devtools.restart.enabledfalse否则开发环境改代码触发的 restart 会把生产环境的连接池搞崩。2.2 为什么 PostgreSQL 版本不能低于 12xxl-job 3.1.1 的 SQL 脚本tables_postgres.sql里用了GENERATED ALWAYS AS IDENTITY语法定义主键自增列这是 PostgreSQL 10 引入的特性但真正稳定支持是在 12 版本。我们试过在 10.22 上部署xxl_job_info表创建成功但插入第一条任务时抛出ERROR: column id is not nullable——因为旧版 identity 列在某些 JDBC 驱动版本下无法正确识别SERIAL的隐式约束。更关键的是分区表支持。xxl_job_log表的数据膨胀速度极快金融客户平均每天新增 60 万行。PostgreSQL 12 开始支持PARTITION BY RANGE (trigger_time)的原生分区而 11 及之前版本只能靠继承表模拟维护成本极高。比如删除 3 个月前的日志在 12 版本只需DROP TABLE IF EXISTS xxl_job_log_p2023_q4;而在 11 版本要写 20 行 PL/pgSQL 脚本遍历子表并TRUNCATE且无法保证原子性。我们实测过 PostgreSQL 14.10 和 15.5 两个版本结论是14.x 系列稳定性更高15.x 在pg_stat_statements扩展的统计精度上有提升但对 xxl-job 这种 OLTP 场景影响微乎其微。所以推荐直接上 14.10当前 LTS 版本避免用 15.x 的早期小版本如 15.0~15.2它们在pg_dump导出大分区表时存在锁表时间过长的问题。2.3 Tomcat 版本选择9.0.85 还是 10.1.22Tomcat 9 和 10 的核心差异在于 Servlet 规范支持9.x 对应 Servlet 4.010.x 对应 Servlet 5.0。xxl-job-admin 3.1.1 编译目标是 Java 8依赖的javax.servlet-api是 4.0.1 版本所以 Tomcat 10.x 会报java.lang.NoClassDefFoundError: javax/servlet/Filter——因为 10.x 把包名从javax.*改成了jakarta.*。解决方案只有两个要么降级到 Tomcat 9.0.85我们线上主力版本要么手动替换 xxl-job-admin 的pom.xml把servlet-api依赖改成jakarta.servlet-api并升级到 5.0.0。后者看似先进但实际踩坑更多jakarta.servlet-api5.0.0 的HttpServletRequest.getRemoteAddr()方法在某些反向代理场景下返回空字符串导致 xxl-job 的XxlJobRemoteHttp调度请求无法获取执行器 IP任务永远处于“运行中”状态。所以我的建议很明确用 Tomcat 9.0.85搭配 OpenJDK 8u392 或 11.0.21。这两个组合经过我们 37 个生产环境验证无一例因容器层引发的调度异常。别迷信新版本稳定压倒一切。2.4 为什么必须用独立的 PostgreSQL 用户很多人图方便直接用postgres超级用户连接 xxl-job这在测试环境没问题但上线即埋雷。PostgreSQL 的权限模型比 MySQL 严格得多超级用户能绕过所有行级安全策略RLS而 xxl-job 的xxl_job_user表未来可能启用 RLS 控制多租户数据隔离。一旦用postgres用户后续加 RLS 规则时会报ERROR: permission denied for table xxl_job_user。更严重的是连接池污染。postgres用户的连接默认开启default_transaction_isolation read committed但某些 JDBC 驱动版本如 pgjdbc 42.5.0在复用连接时会继承该会话级别的隔离级别而 xxl-job 的XxlJobScheduler类里有一段逻辑需要REPEATABLE READ隔离级别来保证任务状态更新的原子性。结果就是用postgres用户时xxl_job_info表的next_trigger_time字段偶尔更新失败任务重复触发。正确的做法是创建专用用户CREATE USER xxl_job WITH PASSWORD StrongPass2024; CREATE DATABASE xxl_job OWNER xxl_job; \c xxl_job GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO xxl_job; GRANT USAGE ON SCHEMA public TO xxl_job; -- 关键设置默认隔离级别 ALTER ROLE xxl_job SET default_transaction_isolation repeatable read;这样既满足最小权限原则又规避了隔离级别冲突。3. 核心细节解析从 tables_postgres.sql 到 xxl-job-admin.properties 的逐行拆解3.1 tables_postgres.sql 的 5 处必须修改点官方提供的tables_postgres.sql脚本看似开箱即用但实际部署时至少有 5 处必须手动调整否则第二天就会出现任务注册失败、日志查不到、调度延迟等问题。第一处xxl_job_registry表的update_time字段原脚本update_time datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,问题PostgreSQL 不支持ON UPDATE CURRENT_TIMESTAMP语法且datetime类型不存在。修正后update_time TIMESTAMP WITHOUT TIME ZONE DEFAULT NOW(),但光改类型不够还得加触发器保证更新时自动刷新CREATE OR REPLACE FUNCTION update_updated_at_column() RETURNS TRIGGER AS $$ BEGIN NEW.update_time NOW(); RETURN NEW; END; $$ language plpgsql; CREATE TRIGGER update_xxl_job_registry_updated_at BEFORE UPDATE ON xxl_job_registry FOR EACH ROW EXECUTE PROCEDURE update_updated_at_column();注意这个触发器必须在CREATE TABLE xxl_job_registry之后立即创建否则建表时DEFAULT NOW()只作用于 INSERTUPDATE 时字段值不会变导致执行器心跳超时被踢出。第二处xxl_job_log表的trigger_code字段长度原脚本trigger_code int NOT NULL COMMENT 调度结果0-成功1-失败,问题PostgreSQL 的int类型没有COMMENT且trigger_code实际存储的是枚举值0/1/-1/200但 xxl-job 源码里用Integer接收如果数据库字段太小会导致DataTruncation异常。修正后trigger_code INTEGER NOT NULL, COMMENT ON COLUMN xxl_job_log.trigger_code IS 调度结果0-成功1-失败-1-执行失败200-丢失;同时在xxl-job-admin.properties中增加# 避免 JDBC 驱动把 smallint 当 short 处理 spring.datasource.hikari.connection-init-sqlSET application_name xxl-job-admin第三处xxl_job_group表的address_type字段默认值原脚本address_type tinyint NOT NULL DEFAULT 0 COMMENT 执行器地址类型0自动注册、1手动录入,问题PostgreSQL 没有tinyint且DEFAULT 0的字符串写法在严格模式下会报错。修正后address_type SMALLINT NOT NULL DEFAULT 0, COMMENT ON COLUMN xxl_job_group.address_type IS 执行器地址类型0自动注册、1手动录入;第四处所有COMMENT语句的语法兼容原脚本中大量使用COMMENT ON COLUMN xxl_job_info.executor_timeout IS 任务超时时间单位秒;这本身没问题但如果你用psql -f tables_postgres.sql执行而脚本开头没加\set ON_ERROR_STOP on某条 COMMENT 失败比如字段名拼错会导致后续建表中断。必须在脚本最顶部加上\set ON_ERROR_STOP on SET client_encoding UTF8;第五处xxl_job_log_report表的分区键原脚本没建分区但生产环境必须分。在CREATE TABLE xxl_job_log_report后立即加-- 按 report_date 分区每月一个分区 CREATE TABLE xxl_job_log_report_y2024_m01 PARTITION OF xxl_job_log_report FOR VALUES FROM (2024-01-01) TO (2024-02-01); -- 创建分区索引 CREATE INDEX idx_log_report_y2024_m01 ON xxl_job_log_report_y2024_m01 (report_date);否则SELECT COUNT(*) FROM xxl_job_log_report WHERE report_date 2024-01-01会全表扫描1000 万行数据查 12 秒。3.2 xxl-job-admin.properties 的 7 个关键参数详解xxl-job-admin.properties是整个调度中心的命脉80% 的线上故障都源于这里配错。下面逐个说明每个参数的实际影响和推荐值。xxl.job.admin.addresses官方文档说“调度中心地址”但真实含义是所有调度中心节点的 HTTP 访问地址列表用于执行器反向注册和任务回调。如果只部署单节点填http://localhost:8080/xxl-job-admin即可如果是集群必须填所有节点地址用逗号分隔如http://node1:8080/xxl-job-admin,http://node2:8080/xxl-job-admin绝对不能填内网 IP 或域名别名因为执行器是通过这个地址主动发起 HTTP 请求的填http://xxl-job.internal会导致执行器 DNS 解析失败。spring.datasource.url标准格式jdbc:postgresql://127.0.0.1:5432/xxl_job?currentSchemapublicreWriteBatchedInsertstrueprepareThreshold5currentSchemapublic强制指定 schema避免跨 schema 查询失败reWriteBatchedInsertstruePostgreSQL 的批量插入优化开关开启后INSERT INTO ... VALUES (...),(...)会被重写为INSERT INTO ... SELECT ... UNION ALL SELECT ...性能提升 3 倍prepareThreshold5JDBC 驱动预编译阈值小于 5 次的 SQL 走普通执行大于等于 5 次走预编译避免小批量操作的预编译开销。spring.datasource.hikari.maximum-pool-size计算公式最大连接数 (CPU 核数 × 2) 有效磁盘数。例如 4 核 1 块 SSD 的服务器推荐值是4×219但我们实测发现xxl-job-admin 的并发瓶颈不在数据库而在 Tomcat 的maxThreads。所以更合理的算法是min(9, Tomcat maxThreads × 0.8)我们的生产环境统一设为8从未出现连接池耗尽。xxl.job.logretentiondays日志保留天数默认30。但注意这个参数只控制 UI 界面的展示过滤不控制物理删除。真正的清理逻辑在XxlJobLogDao的clearLog方法里它会根据xxl.job.logretentiondays值生成DELETE语句。所以如果你设成7代码会执行DELETE FROM xxl_job_log WHERE trigger_time NOW() - INTERVAL 7 days。xxl.job.accessToken访问令牌用于执行器与调度中心的鉴权。必须设为 16 位以上随机字符串如XxlJob2024SecureKey!绝对不能留空或设为简单值否则任何知道调度中心地址的人都能伪造执行器注册请求造成任务劫持。spring.redis.host和spring.redis.portxxl-job 用 Redis 存储执行器注册信息和任务触发队列。如果 Redis 单机填127.0.0.1:6379如果 Redis 集群必须用redis://协议如redis://192.168.1.10:7000,192.168.1.11:7001关键参数spring.redis.timeout2000毫秒避免 Redis 响应慢拖垮整个调度线程。xxl.job.triggerpool.fast.max和xxl.job.triggerpool.slow.max这是 xxl-job 最容易被忽视的性能开关。fast.max控制高频任务如每秒触发的线程池大小默认200slow.max控制低频任务如每天一次的线程池大小默认100如果你的任务大多是定时任务非实时触发把fast.max降到50slow.max提到200能显著降低 CPU 占用率。3.3 Tomcat 配置的 3 个致命细节Tomcat 不只是个容器它是 xxl-job-admin 的资源调度中枢。以下配置不调好轻则响应慢重则任务丢弃。conf/server.xml中的 Connector 配置原生配置Connector port8080 protocolHTTP/1.1 connectionTimeout20000 redirectPort8443 /必须改为Connector port8080 protocolorg.apache.coyote.http11.Http11NioProtocol connectionTimeout30000 redirectPort8443 maxThreads200 minSpareThreads20 acceptCount100 compressionon compressionMinSize2048 noCompressionUserAgentsgozilla, traviata compressableMimeTypetext/html,text/xml,text/plain,application/json,application/javascript /maxThreads200xxl-job-admin 的调度线程池默认 100 个但 UI 请求、API 请求、心跳请求都要占线程200 是底线acceptCount100当所有线程忙时最多排队 100 个请求超过的直接拒绝避免请求堆积导致 OOMcompressionon调度中心返回的 JSON 数据平均压缩率 65%带宽节省一半。conf/web.xml中的 session 配置默认的session-config会导致 UI 登录态频繁失效session-config session-timeout30/session-timeout /session-config必须改为session-config session-timeout1440/session-timeout !-- 24 小时 -- cookie-http-onlytrue/cookie-http-only cookie-securefalse/cookie-secure !-- 如果没配 HTTPS必须设 false -- /session-config否则运维同学登录后台看 30 分钟监控就得重新登录极其影响体验。bin/setenv.sh中的 JVM 参数这是 Tomcat 性能的基石。我们的标准配置export JAVA_OPTS-server -Xms2g -Xmx2g -XX:MetaspaceSize512m -XX:MaxMetaspaceSize512m -XX:UseG1GC -XX:MaxGCPauseMillis200 -XX:PrintGCDetails -XX:PrintGCDateStamps -Xloggc:/opt/tomcat/logs/gc.log -XX:UseGCLogFileRotation -XX:NumberOfGCLogFiles5 -XX:GCLogFileSize10M-Xms2g -Xmx2g堆内存固定大小避免 GC 时动态扩容缩容-XX:MetaspaceSize512mMetaspace 初始大小防止类加载过多触发 Full GC-XX:UseG1GCG1 垃圾收集器适合大堆内存且停顿可控-XX:MaxGCPauseMillis200G1 的目标停顿时间确保调度线程不被 GC 卡住。4. 实操全流程从 PostgreSQL 安装到 xxl-job-admin 启动成功的完整记录4.1 PostgreSQL 14.10 在 CentOS 7 上的安装与初始化步骤 1安装依赖并添加官方源# 安装基础工具 sudo yum install -y epel-release sudo yum install -y wget vim net-tools # 添加 PostgreSQL 官方 YUM 源 sudo yum install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-7-x86_64/pgdg-redhat-repo-latest.noarch.rpm # 禁用系统自带的 postgresql 模块CentOS 7 默认启用 sudo yum module disable postgresql # 安装 PostgreSQL 14 sudo yum install -y postgresql14-server postgresql14-contrib注意不要用yum install postgresql-server那是系统自带的 9.2 版本不兼容 xxl-job。步骤 2初始化数据库并启动服务# 初始化数据库集群 sudo /usr/pgsql-14/bin/postgresql-14-setup initdb # 启动服务并设开机自启 sudo systemctl start postgresql-14 sudo systemctl enable postgresql-14 # 检查状态 sudo systemctl status postgresql-14 # 输出应为 active (running)步骤 3修改 postgresql.conf 配置sudo vim /var/lib/pgsql/14/data/postgresql.conf关键修改项# 监听所有地址允许远程连接 listen_addresses localhost,127.0.0.1,192.168.1.100 # 允许外部连接 port 5432 # 连接数上限xxl-job 至少需要 100 连接 max_connections 200 # 共享内存必须 128MB shared_buffers 256MB # WAL 日志xxl-job 写入频繁需加大 wal_buffers 16MB # 检查点间隔避免频繁刷盘 checkpoint_completion_target 0.9 # 日志级别方便排查 log_statement all log_min_duration_statement 1000步骤 4修改 pg_hba.conf 允许 xxl-job 连接sudo vim /var/lib/pgsql/14/data/pg_hba.conf在文件末尾添加# TYPE DATABASE USER ADDRESS METHOD host xxl_job xxl_job 127.0.0.1/32 md5 host xxl_job xxl_job 192.168.1.0/24 md5然后重启 PostgreSQLsudo systemctl restart postgresql-144.2 创建 xxl-job 数据库与用户步骤 1切换到 postgres 用户执行 SQLsudo -u postgres psql步骤 2执行建库与授权-- 创建数据库 CREATE DATABASE xxl_job OWNER xxl_job ENCODING UTF8 LC_COLLATEen_US.UTF-8 LC_CTYPEen_US.UTF-8; -- 创建用户 CREATE USER xxl_job WITH PASSWORD XxlJob2024Secure!; -- 授权 \c xxl_job GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO xxl_job; GRANT USAGE ON SCHEMA public TO xxl_job; -- 设置默认隔离级别 ALTER ROLE xxl_job SET default_transaction_isolation repeatable read; -- 退出 \q4.3 执行 tables_postgres.sql 并验证步骤 1下载并修改 SQL 脚本从 xxl-job GitHub Release 页面下载xxl-job-3.1.1.sql提取tables_postgres.sql。用 vim 打开按前文 3.1 节的 5 处修改点逐一修正。步骤 2导入数据# 切换到脚本所在目录 psql -U xxl_job -d xxl_job -f tables_postgres.sql如果看到CREATE TABLE,INSERT 0 1等输出说明成功。步骤 3验证关键表结构psql -U xxl_job -d xxl_job -c \d xxl_job_info psql -U xxl_job -d xxl_job -c \d xxl_job_log检查update_time字段是否为timestamp without time zonetrigger_code是否为integeraddress_type是否为smallint。4.4 Tomcat 9.0.85 部署 xxl-job-admin步骤 1下载并解压 Tomcatcd /opt sudo wget https://dlcdn.apache.org/tomcat/tomcat-9/v9.0.85/bin/apache-tomcat-9.0.85.tar.gz sudo tar -xzf apache-tomcat-9.0.85.tar.gz sudo mv apache-tomcat-9.0.85 tomcat sudo chown -R tomcat:tomcat /opt/tomcat步骤 2配置 JVM 参数sudo vim /opt/tomcat/bin/setenv.sh粘贴前文 3.3 节的 JVM 参数。步骤 3部署 war 包# 下载 xxl-job-admin-3.1.1.jar官方 release 页面 wget https://github.com/xuxueli/xxl-job/releases/download/3.1.1/xxl-job-admin-3.1.1.jar # 转换为 warxxl-job-admin 是 jar 包需重命名为 war cp xxl-job-admin-3.1.1.jar /opt/tomcat/webapps/xxl-job-admin.war步骤 4配置 xxl-job-admin.propertiessudo mkdir -p /opt/tomcat/webapps/xxl-job-admin/WEB-INF/classes sudo vim /opt/tomcat/webapps/xxl-job-admin/WEB-INF/classes/xxl-job-admin.properties填入前文 3.2 节的 7 个关键参数特别注意spring.datasource.urljdbc:postgresql://127.0.0.1:5432/xxl_job?currentSchemapublicreWriteBatchedInsertstrueprepareThreshold5 spring.datasource.usernamexxl_job spring.datasource.passwordXxlJob2024Secure! xxl.job.admin.addresseshttp://127.0.0.1:8080/xxl-job-admin步骤 5启动 Tomcat 并验证sudo /opt/tomcat/bin/startup.sh tail -f /opt/tomcat/logs/catalina.out等待日志出现INFO [main] org.springframework.boot.web.embedded.tomcat.TomcatWebServer.start Tomcat started on port(s): 8080 (http) INFO [main] com.xxl.job.admin.XxlJobAdminApplication.main Started XxlJobAdminApplication in 25.342 seconds然后浏览器访问http://your-server-ip:8080/xxl-job-admin输入默认账号admin/123456能进入调度中心首页即成功。5. 常见问题与排查技巧实录那些官网不会告诉你的坑5.1 问题速查表症状、原因、解决方案症状可能原因解决方案调度中心页面空白F12 看 network 显示 404webapps/xxl-job-admin.war解压失败或context.xml里path配置错误检查/opt/tomcat/webapps/xxl-job-admin/目录是否存在确认server.xml中Host标签内无重复Context配置登录后提示“用户名或密码错误”但确定没输错xxl-job-admin.properties中xxl.job.login.username和xxl.job.login.password被注释或拼写错误检查 properties 文件确保xxl.job.login.usernameadmin和xxl.job.login.password123456两行未被#注释执行器注册成功但任务状态一直是“运行中”不变成“成功”PostgreSQL 的xxl_job_log表trigger_code字段类型错误或xxl_job_admin的XxlJobLogDao未正确映射执行SELECT data_type FROM information_schema.columns WHERE table_namexxl_job_log AND column_nametrigger_code;确认返回integer否则重建表任务能触发但执行器日志里报Connection refused执行器配置的xxl.job.admin.addresses填了内网 IP而执行器在另一台机器上无法访问把xxl.job.admin.addresses改成调度中心服务器的公网 IP 或 DNS 名称Tomcat 启动后访问 404但 catalina.out 无报错webapps/xxl-job-admin.war文件损坏或 SELinux 阻止了 Tomcat 访问 webapps 目录执行sudo setsebool -P tomcat_can_network_connect 1并重新上传 war 包5.2 独家避坑技巧3 个血泪教训技巧 1用ps -ef \| grep tomcat查进程时一定要看 PID 和启动命令很多人只看grep结果却忽略了 Tomcat 实际启动的 JVM 参数。正确做法ps -ef | grep tomcat # 输出类似 # root 1234 1 0 10:00 ? 00:00:12 /usr/lib/jvm/java-11-openjdk-amd64/bin/java -Djava.util.logging.config.file/opt/tomcat/conf/logging.properties -Djava.util.logging.managerorg.apache.juli.ClassLoaderLogManager -server -Xms2g -Xmx2g ...如果-Xms和-Xmx没显示说明setenv.sh没生效必须检查文件权限和路径。技巧 2排查慢 SQL 的终极命令当调度变慢时别急着看 xxl-job 日志先查 PostgreSQLsudo -u postgres psql -d xxl_job -c SELECT pid, now() - pg_stat_activity.backend_start AS duration, query FROM pg_stat_activity WHERE state active AND now() - pg_stat_activity.backend_start interval 1 minute ORDER BY duration DESC LIMIT 5;这条命令能直接揪出执行超 1 分钟的 SQL90% 的慢调度都源于xxl_job_log表没建索引或分区失效。技巧 3执行器注册失败时抓包看 HTTP 请求头用tcpdump抓执行器发给