↓
全链路可观测平台落地实录:20 个问题、16 个文件改动,和一台慢了 29 分钟的服务器
  1. Posts/

全链路可观测平台落地实录:20 个问题、16 个文件改动,和一台慢了 29 分钟的服务器

写在前面
#

这篇是上一篇 政务系统可观测平台搭建实战:SigNoz + OpenTelemetry 探针 的续集。

上一篇写的是"把平台和探针装起来"——SigNoz、ClickHouse、OTel Collector,给 5 台服务器 9 个应用挂探针。那一篇写完的时候,平台能跑、图表能出,我以为活儿干完了。

事实证明只干了一半。

平台"能跑",和平台"能说清数据、能看借口",完全是两件事。 这次的任务是把一套已经装好的可观测平台,从"装完什么样就是什么样"变成"乌兰察布这套系统该有的样子"。中间动的东西比我想的多:

  • 前端页面里全是历史环境的地址——IP、仪表板 UUID、工单接口、SDK 上报地址,一个都不能直接用
  • CMDB 里 1000 多条全是示例数据,主机名叫 SRV-202401001,接口路径里带 guizhou,一眼就知道不是我们这套
  • 给应用挂探针,重启一个系统直接起不来,日志只有一行提示,什么都没说
  • 接口监控页面录了 138 个接口,调用次数全是 0
  • 最后查出来的原因是:可观测平台那台服务器的系统时钟慢了 29 分钟

这些坑有个共同点:报错信息不会告诉你在哪。 只能一层一层往下挖。

排查过程中我大量用了 AI 帮忙:反编译 class 文件看逻辑、写批量查 ClickHouse 的脚本、比对两份配置的差异、生成验证命令。说句实话,没有 AI 我大概要多花三四倍时间,特别是反编译和写查询脚本这两块,它比我手快得多。

但 AI 也有明显的短板:它不知道现场。 有一次它判断某个应用起不来是"外网授权服务不可达",让我去查网络。我回了一句"网络一点没动,就是重启了一下",它才转向去查 jar 包,最后在反编译出来的字节码里找到了一个硬编码的日期。类似的情况还有几次,所以每个结论我都得自己再验一遍。

这篇会写:

  1. 20 个问题的现象、怎么查出来的、最后怎么解决的
  2. 改了哪些文件、每处改动到底是干什么的
  3. 踩过的坑,以及下次怎么少踩

脱敏说明:本文所有 IP、账号、密码、域名都换成了占位符(APP-HOST、SIG-HOST、<密码> 这类),路径和参数保留原样。换成你自己的环境就能用。


环境说明
#

先交代一下本文用到的代号,后面对应的都是这些:

代号角色说明
APP-HOST应用服务器Nginx、网关、两个微服务、4 个 Tomcat 都在这台
APP-HOST-B上面的 B 区网卡地址双网卡主机,A/B 区各一个地址
DB-HOST数据库服务器MySQL 5.7(平台库)+ Oracle(业务库)
DB-HOST-B上面的 B 区网卡地址同上
SIG-HOST可观测平台服务器SigNoz、ClickHouse、OTel Collector
SIG-HOST-B上面的 B 区网卡地址同上
BIZ-HOST-1/2/3其他业务服务器云表单、链条审批、审管互动
OLD-HOST-*平台初始配置里的历史地址全部需要替换
EXT-HOST-*外部环境的地址与本环境不通

为什么要强调 A 区 / B 区:这套环境是双网卡,A 区给用户访问,B 区给服务器之间互通。前端(浏览器)必须用 A 区地址,后端(服务器)必须用 B 区地址,填反了页面就空,或者数据上报不进来。这个坑后面会专门说。

部署形态:

组件说明
4 个微服务资源服务(8087)、业务服务(8089)、网关(30901)、BSPPLUS(9099)
Nginx80 端口,统一入口:/obs/ 前端、/gate/ 网关、/ucenter/ 登录
前端打包产物解压到 Nginx 的 html 目录,访问路径 /obs
SigNoz8086 前端、8123 ClickHouse HTTP、4317/4318 OTLP 上报
Tomcat4 个实例,分别承载通用审批、并联审批、综合受理、网办后台

第一部分 部署过程中遇到的问题与解决
#

1.1 问题总览
#

#问题影响面状态
1网关全部接口返回「缺少Authorization」所有业务接口 401已解决
2服务启动即退出(license.dat 缺失)BSPPLUS / 网关起不来已解决
3.dbmd 建库脚本报排序规则不支持数据库无法初始化已解决
4数据迁移时字段超长 / 权限不足 / 无法跳过建表147 张表数据迁移已解决
5bat 脚本乱码、吞换行服务无法启动已解决
6执行 startup.bat 后命令行永久挂住运维操作受阻已解决
7加探针后 Tomcat 报「‘xxx’ 不是内部或外部命令」服务启动失败已解决
8网办后台(iWebSite)启动 10 秒后自动退出生产系统不可用已解决
9换最新 license.dat 仍无法启动排查方向错误已纠正
10告警「查看工单」点击后长时间无响应功能不可用已解决
11修改前端配置后浏览器仍用旧值配置不生效已解决
12接口监控页面完全空白功能不可用已解决
13接口监控「调用总次数」始终为 0功能不可用已解决
14接口调用总览 P50/P95/P99 面板报错面板不可用已解决
15告警详情都是公司的实例地址原为不可达地址已解决
16CMDB 初始数据需替换为公司实际环境数据失真已解决
17接口表唯一键冲突数据无法入库已解决
18nacos\bin\logs 占用 17.4 GB磁盘浪费已清理
19SigNoz 服务器时钟偏差 29 分钟所有时间窗查询偏移已解决
20性能问题(部署期间顺带发现)待优化已记录

1.2 问题详述
#

问题 1:网关全部接口返回「缺少Authorization」
#

现象

GET /gate/bspplus/user/login  →  {"code":0,"msg":"缺少Authorization","status":400}

所有经过网关的请求都被拦下,包括本该免登录的登录接口。

根因

网关的鉴权链路由两个过滤器组成:

  • GlobalApiAuthFilter:负责 anon-white-list(匿名白名单)和 session.loginuris
  • GlobalAuthorizationFilter:负责 tokenWhiteList(Token 白名单)

网关配置里 api-auth-check-enable: false 关闭了 GlobalApiAuthFilter,导致 anon-white-list 里的配置完全不生效。最终只有 GlobalAuthorizationFilter 在跑,而它只认 tokenWhiteList。

判断逻辑(反编译确认):

private boolean isWhite(String path) {
    return securityCustomConfig.getTokenWhiteList().stream()
            .anyMatch(p -> pathMatcher.match(p, path));
}

处理

在 Nacos 的 dgov-cloud-gateway 配置里,往 tokenWhiteList 追加 6 条:

tokenWhiteList:
  - /gate/bspplus/utils/**
  - /gate/bspplus/user/login
  - /gate/bspplus/user/signOn/login
  - /gate/bspplus/oauth/**
  - /gate/bspplus/sso/**
  - /gate/bspplus/user/logout

验证

GET /gate/bspplus/utils/uuid  →  HTTP 200,返回 uuid

教训

网关有两套白名单机制,只改其中一套没用。排查时应当先确认哪个过滤器在生效(看 api-auth-check-enable 开关),再决定改哪个配置项。


问题 2:服务启动即退出(license.dat 缺失)
#

现象

java.io.FileNotFoundException: class path resource [license.dat] cannot be opened

BSPPLUS 和网关日志打印 Started 之后立刻退出。

根因

SystemApp.checkLicence() 在启动时校验 License:

goto("utf-8") → ClassPathResource / FileUrlResource("license.dat")
→ Base64 + DES 解密 → 校验 JSON 里 code == "1"

license.dat 文件名在 com.inspur.dgov.core.a.c.class() 中硬编码(ldc #20 'license.dat')。

处理

从已经正常运行的通用审批(XZSP)目录复用 license.dat:

D:\server\apache-tomcat-9.0.87-XZSP\...\license.dat
  → D:\server\inspur-digital-bspplus\license.dat
  → D:\server\dgov-cloud-gateway\license.dat

该 License 有效期至 2031-03-03。

教训

同一产品线的 License 通常可以复用。建议把可用的 license.dat 统一留存一份到 D:\server\_license\,后续服务重装直接拷贝。


问题 3:.dbmd 建库脚本报排序规则不支持
#

现象

导入 .dbmd 时提示 Unknown collation: 'utf8mb4_0900_ai_ci'。

根因

utf8mb4_0900_ai_ci 是 MySQL 8.0 引入的排序规则,本环境是 MySQL 5.7.17,不支持。

处理

替换脚本内所有 utf8mb4_0900_ai_ci → utf8mb4_general_ci,重建后 147 张表创建成功。


问题 4:数据迁移的三个问题
#

4.1 字段超长

ERROR 1406: Data too long for column 'USER_CODE'

表定义 VARCHAR(36),源库实际数据 56 字符。

解决:ALTER TABLE PUB_USER_ROLE MODIFY USER_CODE VARCHAR(100);

4.2 权限不足

ERROR 1044 (42000): Access denied for user 'dgov_bsp'@'%' to database 'dgov_bsp_tmp'

解决:用 root 执行 GRANT ALL PRIVILEGES ON dgov_bsp_tmp.* TO 'dgov_bsp'@'%';

4.3 数据传输工具无法跳过建表

目标库已有表结构,工具仍强制建表导致冲突。

解决:建临时库 dgov_bsp_tmp 先导入,再用 SQL 从临时库搬到正式库:

INSERT IGNORE INTO dgov_bsp.PUB_ROLE SELECT * FROM dgov_bsp_tmp.PUB_ROLE;

迁移结果

表源库行数目标库行数
PUB_ROLE7571
PUB_RESOURCE27082541
PUB_ROLE_RESOURCE43181511
PUB_USER_ROLE125814125814(INSERT IGNORE)

问题 5:bat 脚本乱码、吞换行
#

现象

执行 startup.bat 时输出:

'+' 不是内部或外部命令,也不是可运行的程序
'笈低?' 不是内部或外部命令
'MX' 不是内部或外部命令
'上报地址:' 不是内部或外部命令

根因(两个叠加)

  1. 文件用 LF 换行写出,而 cmd.exe 要求 CRLF
  2. 文件内含 GBK 中文注释(rem 应用: xxx),cmd 逐行解析时把 rem 和中文拆开,中文碎片被当作命令执行

处理

.bat 文件统一规范:

$lines = @('@echo off', 'set "JAVA_OPTS=..."', ...)
$text  = ($lines -join "`r`n") + "`r`n"          # 强制 CRLF
[System.IO.File]::WriteAllText($f, $text, (New-Object System.Text.ASCIIEncoding))  # 纯 ASCII

规范(后续所有 bat 都遵守)

  • 换行必须 CRLF
  • 内容必须纯 ASCII,注释也用英文
  • 不使用 heredoc 直接写文件(容易带入 LF)

问题 6:执行 startup.bat 后命令行永久挂住
#

现象

& cmd /c "startup.bat" 2>&1 | Out-String | Write-Host    # ← 卡死,不再返回

根因

startup.bat 内部调用 catalina.bat start,会 start 一个新窗口运行 java。Java 进程继承了父进程的 stdout 管道句柄,只要 java 活着,管道就不关闭,PowerShell 就一直等待。

处理

改用 Start-Process,不接管输出:

Start-Process -FilePath "cmd.exe" `
    -ArgumentList "/c","startup.bat" `
    -WorkingDirectory "$base\bin" `
    -WindowStyle Hidden

教训

凡是会驻留后台的进程(Tomcat、java、nginx),都不要用管道接收它的输出,否则管道永不关闭。


问题 7:加探针后 Tomcat 报「‘xxx’ 不是内部或外部命令」
#

现象(同问题 5,但发生在探针配置里)

'+' 不是内部或外部命令
'MX' 不是内部或外部命令
'上报地址:' 不是内部或外部命令

根因

写 setenv.bat 时用了 GBK 编码 + 中文注释 + LF 换行。

处理

重写为纯 ASCII + CRLF,注释全改英文。三个文件校验结果:

ACCEPT:   字节=858  非ASCII=0  CRLF=11  LF-only=0   [通过]
Parallel: 字节=858  非ASCII=0  CRLF=11  LF-only=0   [通过]
WebSite:  字节=864  非ASCII=0  CRLF=11  LF-only=0   [通过]

问题 8:网办后台(iWebSite)启动 10 秒后自动退出
#

现象

Tomcat 正常启动,Spring 容器初始化完成,然后静默退出,无异常栈:

14:41:12  Root WebApplicationContext: initialization completed in 9651 ms
14:41:12  com.inspur.app.utils.DateUtils.compareDate(DateUtils.java:43)
          - Application is not initialize...
          ↓ 等 10 秒
14:41:22  Closing Root WebApplicationContext
14:41:22  {dataSource-2} closed / {dataSource-1} closed

排查过程

  1. 首先怀疑外网授权服务 EXT-HOST-4:8081 不可达 → 测了一下确实不通。但我回了一句"网络一点没动,就是重启了一下",才意识到方向找错了
  2. 用 javap 反编译 jcore-1.0.jar 里的 com.inspur.app.utils.DateUtils

反编译结果

private static final String expireDate = "2025-10-01 00:00:00";   // ← 到期日硬编码
public  static final String RUN_MODE    = "release";              // ← 本方法未使用,无旁路

public static JSONObject compareDate() {
    c1.setTime(df.parse("2025-10-01 00:00:00"));   // 到期日
    c2.setTime(new Date());                        // 当前时间
    int r = c1.compareTo(c2);

    if (r == 0)      { code="1"; log("Application is initialize..."); }
    else if (r < 0)  {                              // ★ 已过期
        code = "0";
        log("Application is not initialize...");
        Thread.sleep(10000);
        System.exit(0);                             // ★★★ 主动结束 JVM
    }
    else             { code="1"; log("Application is initialize..."); }
}

根因

jcore-1.0.jar 把到期日写死成 2025-10-01,当前日期(2026-10-27)超过后 System.exit(0)。

为什么之前能跑:旧进程是在 2025-10-01 之前启动的,运行时不重查。本次为接探针重启,才触发检查。

对比扫描:其他产品都是新版 jar

Tomcatwebappjar到期日状态
ACCEPTInspur.Dzzw.CloudAcceptjcore-3.5.jar2118-10-01正常
ParallelInspur.Dzzw.WebParalleljcore-3.5.jar2118-10-01正常
XZSPInspur.Dzzw.WebApprovaljcore-3.5.jar2118-10-01正常
WebSiteiWebSitejcore-1.0.jar2025-10-01已过期

处理

用公司已发布的 jcore-3.5.jar 替换:

Copy-Item "...\XZSP\...\lib\jcore-3.5.jar"  $lib\jcore-3.5.jar
Move-Item  $lib\jcore-1.0.jar  $lib\jcore-1.0.jar.disabled-<时间戳>

结果

8030 LISTENING  PID 10252   ← 网办后台恢复
9996 LISTENING  PID 10252   ← JMX 探针同时生效

教训(重要)

  1. jcore-1.x → jcore-3.5 跨大版本替换兼容(API 无破坏性变更),已验证
  2. 每个老应用重启前都要确认 jar 版本与到期日,否则一重启就炸
  3. 我把这个结论反馈给了公司,让他们排查其他服务器上是否有同样的漏升级

问题 9:换最新 license.dat 仍无法启动
#

现象

更换最新的 license.dat 后,重启仍然 10 秒退出。

我的判断

DateUtils.compareDate() 根本不读 license.dat:

  • expireDate 是 static final 编译期常量,已内联进字节码
  • 方法内唯一用到 License 的地方是 com.iop.util.License.getLicenseName(),只取一个名字打日志

所以换 license.dat 对这个问题完全无效。

记录这一点的意义:后续再遇到"启动即退出"且日志有 DateUtils.compareDate,直接查 jar 版本,不要再从 license 或网络方向排查。


问题 10:告警「查看工单」点击后长时间无响应
#

现象

点击告警的「查看工单」:

  • 先等约 30 秒
  • 浏览器 DevTools 报 Failed to load response data
  • 页面无任何提示

根因

前端 dmsApi.js 直连公司外网工单系统:

DMS_API_ROOT: "https://dms.example.com"
DMS_ORDER_INFO_PATH: "/local/dsm-plugin-oms/api/order/getInfo"
DMS_HTTP_TIMEOUT: 30000          // 30 秒

dms.example.com 在本环境不可达 → 请求挂 30 秒后才超时。

关键:前端逻辑分支

const o = await post(DMS_API_ROOT + DMS_ORDER_INFO_PATH, { busiId });
if (o.state !== 1) {
    if (o.message.includes("TkOrder not found")) {
        err.code = "TK_ORDER_NOT_FOUND";   // → 前端弹「尚未生成工单,是否创建?」
    }
    reject(...);
}

解决(不改前端代码,用 Nginx 造响应)

在 nginx.conf 加两条 location:

# ① 模拟「未找到工单」,让前端走友好分支
location = /dms/local/dsm-plugin-oms/api/order/getInfo {
    default_type 'application/json; charset=utf-8';
    add_header Cache-Control 'no-store';
    return 200 '{"state":0,"message":"TkOrder not found: DMS not connected"}';
}

# ② 工单占位页
location ^~ /dms/ {
    alias  D:/server/nginx/html/dms/;
    index  index.html;
    try_files $uri $uri/ /dms/index.html;
}

前端配置改为同源相对路径:

DMS_API_ROOT: '/dms',
DMS_DETAIL_PAGE_URL: '/dms',
DMS_CREATE_PAGE_URL: '/dms',
DMS_HTTP_TIMEOUT: 5000,     // 30s → 5s

结果

阶段行为耗时
修复前直接跳转外网 API 地址 / 等 30 秒报错30 秒
修复后5 秒内弹「是否创建工单」→ 点创建打开占位页≤5 秒

问题 11:修改前端配置后浏览器仍用旧值
#

现象

config.dms.js 已改成 DMS_HTTP_TIMEOUT: 5000,但浏览器仍按 30 秒超时。

根因

index.html 给配置文件带了固定版本号:

<script src="./config.dms.js?id=1792120301403"></script>

浏览器认为 URL 没变,一直用缓存。

处理

  1. 换版本号:?id=1792120301403 → ?id=202610271345
  2. Nginx 对 config.*.js 禁缓存:
location ~ ^/obs/config\.[a-z0-9]+\.js$ {
    root   D:/server/nginx/html;
    add_header Cache-Control "no-cache, no-store, must-revalidate";
    add_header Pragma "no-cache";
    expires -1;
}

教训

前端配置类文件(config*.js)必须禁缓存,否则改配置永远要手工强刷。


问题 12:接口监控页面完全空白
#

现象

「接口调用详情」表格一行都没有。

根因(两个独立问题叠加)

13.1 默认筛选是「高危」,而导入的接口全是「非高危」

const D = 1;                    // 默认值 = 1(高危)
const g = r(D);
const P = async () => {
    const a = await pe({ isHighRisk: g.value });   // ← 只查 is_high_risk=1
    m.value = Array.isArray(a) ? a : (a?.data) || [];
};

13.2 导入的接口路径是「span 名」,不是「HTTP 路由」

之前从 ClickHouse 导入的 709 条是 span 的 name,包含 SQL / Dubbo 调用:

SELECT orcl.APPROVE_EXPORTALREQ          ← SQL span
UPDATE orcl.ENTERPRISE_RESOURCE_SHARE    ← SQL span
com.inspur.service.PowerManagerService/getItemInfoByItemCode   ← RPC span

而接口监控只统计 HTTP 路由,后端 SQL 按 http.route / http.target 匹配,SQL 名永远匹配不上。

处理

重建 cmdb_app_interface,只保留真实 HTTP 路由:

应用接口数
浪潮政务服务通用审批平台(XZSP)60
链条审批(QYSL)55
乌兰察布综合受理平台(ZHSL)8
电子政务公共服务平台 BSP7
浪潮政务云盘(DISK)2
网办后台(WEBSITE)2
并联审批系统(BLSP)2
浪潮电子政务任务调度系统1
浪潮行政权力事项管理系统1
合计138

高危接口标注规则:平均耗时 ≥ 500ms 或 调用量 ≥ 90 次 → 共 19 条。

建表时遇到的问题:cmdb_app_interface 没有 app_name 列,首次插入 138 条全部报 ERROR 1054 Unknown column。实际列为:

id, app_id, service_id, api_name, api_path, method,
type, remark, create_time, update_time, create_by, update_by,
del_flag, is_high_risk

按实际列名重插后成功。


问题 13:接口监控「调用总次数」始终为 0
#

现象

138 行接口全部显示 调用总次数 = 0、接口状态 = 无流量。

根因

前端 signozService 里的 SQL 用 http.target 做精确匹配:

AND attributes_string['http.target'] IN $http.route
GROUP BY attributes_string['http.route'] AS `接口地址`

而实际数据:

项值
前端传的 api_path/Inspur.Dzzw.WebApproval/approval/workextend
ClickHouse http.target/Inspur.Dzzw.WebApproval/approval/workextend?method=queryCount ← 带查询参数
ClickHouse http.route/Inspur.Dzzw.WebApproval/approval/workextend ← 不带参数

IN 是精确匹配,http.target 带 ?method=queryCount → 匹配失败。

验证(直连 ClickHouse)

-- 用 http.target 精确匹配
SELECT ... WHERE attributes_string['http.target'] IN ('/Inspur.Dzzw.WebApproval/approval/workextend')
-- → 0 条

-- 用 http.route 精确匹配
SELECT ... WHERE attributes_string['http.route'] IN ('/Inspur.Dzzw.WebApproval/approval/workextend')
-- → 764 条

解决(前端补丁)

signozService-Cg3RwBMu.js:

-- 改前
AND attributes_string['http.target'] IN $http.route
-- 改后
AND attributes_string['http.route'] IN $http.route

第二层:网关 SQL 注入过滤器拦截

改为 http.route 后,接口返回:

{"code":0,"msg":"非法参数","status":400}

响应使用 msg 字段(网关格式),业务服务使用 message 字段,据此定位到网关。查网关配置:

security:
  sql-injection-regex: ...|UNION.+?SELECT.+?FROM|INSERT\s+INTO.+?VALUES|(SELECT|DELETE).+?FROM|...

查询体里含 SELECT ... FROM signoz_traces...,命中 (SELECT|DELETE).+?FROM。

网关 Nacos 配置追加参数白名单:

param-white-list[1]: /gate/obs/business/signoz/proxy/**

重启网关后,请求通过参数校验,卡在鉴权层(返回「缺少Authorization」),说明 SQL 过滤器已放行。

第三层:SigNoz 服务器时钟偏差

放行后数字能出来,但调 60 次只显示 3 次。经逐查询对比,定位为 SigNoz 服务器系统时钟慢 29 分钟,导致 BETWEEN ... AND now() 的时间窗上界偏移。详见「问题 19」。

最终处理

层处理
第一层signozService-Cg3RwBMu.js 中 http.target 改为 http.route
第二层网关 Nacos 配置追加 param-white-list[1],重启网关
第三层SigNoz 服务器执行 hwclock --hctosys

验证

校时后,同一接口 timestamp > now()-30m 与 BETWEEN now()-30m AND now() 结果一致(14 = 14);Postman 调 10 次后刷新页面,调用总次数随之增长。


问题 14:接口调用总览 P50/P95/P99 面板报错
#

现象

总览页 P50/P95/P99 延迟面板显示红色报错图标,Console 输出:

error: Executable file ./histogramQuantile is not executable
inside user scripts folder /var/lib/clickhouse/user_scripts/
while executing 'FUNCTION histogramQuantile(...)'

根因

SigNoz 的 ClickHouse 镜像里,histogramQuantile UDF 脚本没有执行权限:

-rw-r--r-- 1 root root 1446040 Jun 29 01:29 histogramQuantile
     ↑↑↑ 没有 x

解决(在 SigNoz 服务器 SIG-HOST 上)

# 注意:docker exec 不做 shell 通配符展开,要用完整文件名
docker exec -u root signoz-clickhouse chmod +x /var/lib/clickhouse/user_scripts/histogramQuantile

# 确认
docker exec -u root signoz-clickhouse ls -l /var/lib/clickhouse/user_scripts/
# -rwxr-xr-x ... histogramQuantile

# 验证
docker exec signoz-clickhouse clickhouse-client --query \
  "SELECT histogramQuantile([1.0,2.0,5.0,10.0], [10.0,20.0,30.0,40.0], 0.99) AS p99"
# 返回 nan(能执行即成功,nan 是因为测试数据是假的)

结果

报错类型从 not executable → TYPE_MISMATCH → 正常返回,说明 UDF 已修复。


问题 15:告警详情都是公司的实例地址
#

现象

SigNoz 告警通知里「查看详情」链接指向 http://OLD-HOST-1:8086/...,不是本环境的实例地址,浏览器打不开。

根因

告警规则的 annotations.description / annotations.summary 里写死了非本环境地址的 HTML:

<a href="http://OLD-HOST-1:8086/metrics-explorer/explorer?compositeQuery=...">查看详情</a>

处理

通过 SigNoz API 批量更新 24 条规则:

PUT /api/v2/rules/{id}  →  204

将 OLD-HOST-1:8086 全部替换为 SIG-HOST:8086,即公司在本环境的 SigNoz 实例地址(A 区,浏览器可达)。

验证:残留 0 处。


问题 16:CMDB 初始数据需替换为公司实际环境
#

现象

服务器 / 数据库 / 中间件 / 应用 / 接口均为初始化示例数据,不是乌兰察布实际环境。

识别特征(后续导入数据时用于判断是否为示例数据)

特征值
create_by88888888888888888888888888888888
接口路径含guizhou
IP 段10.108.x.x(历史环境网段)
服务名INSPUR-DZZW-CJSXGC-V6、TraceDemo-service
主机名SRV-202401001 ~ SRV-202401004

处理

全部替换为乌兰察布真实数据:

资源类型数量来源
服务器9 台BIZ-HOST-1/.113/.114/.115/.116/.127、BIZ-HOST-3/.238/.241
数据库3 个MySQL 116:3306 / Oracle 116:1521 / ClickHouse 248.238:8123
中间件5 个Nacos 115:8848 / Redis 115:6379 / Nginx 115:80 / Tomcat 115:8080 / OTel 248.238:4317
业务应用16 个Oracle BSP.PUB_APPS
接口138 个ClickHouse 真实 HTTP 路由

备份表(可回滚)

cmdb_compute_resource_bak20261027
cmdb_db_resource_bak20261027
cmdb_comp_resource_bak20261027
cmdb_application_bak20261027
cmdb_app_service_bak20261027b
cmdb_app_interface_bak20261027b   (709 行,span 名)
cmdb_app_interface_bak20261027c   (709 行)

问题 17:接口表唯一键冲突
#

现象

Duplicate entry 'xxx-/Inspur.DZZW.XZSP.APPROVE_EXPORTALREQ-POST-0' for key 'uk_app_interface'

根因

唯一键 uk_app_interface (app_id, api_path, method, del_flag) 在 MySQL 默认排序规则下大小写不敏感, Oracle 表名的大小写变体(APPROVE_EXPORTALREQ / approve_exportalreq)会被判定为重复。

处理

按 (app_id, LOWER(api_path), method) 去重,727 → 709,再用 INSERT IGNORE 入库。


问题 18:nacos\bin\logs 占用 17.4 GB
#

现象

D:\server\nacos  = 17,551 MB
  ├── bin      17,411 MB   ← ★
  ├── target       77 MB
  └── logs         59 MB

根因

nacos\bin\logs\ 里全是 2021 年 的 Tomcat access log,每天一个 89.9 MB:

access_log.2021-12-08.log   89.9 MB
access_log.2021-11-19.log   89.9 MB
...

属于上一套系统在这台机器上运行遗留的垃圾(2021 年 8–12 月)。

处理

删除 2024 年以前的文件(保留近期以防有用):

Get-ChildItem "D:\server\nacos\bin\logs" -File |
    Where-Object { $_.LastWriteTime -lt (Get-Date "2024-01-01") } |
    Remove-Item -Force

结果:D 盘已用从 151.6 GB → 140.16 GB,释放约 11.4 GB。


问题 19:SigNoz 服务器时钟偏差 29 分钟
#

现象

接口监控「最近 30 分钟」的数字不随新调用变化:调 60 次仍只显示 3 次。链路监控、指标监控、日志监控选择「最近 5 分钟」同样查不到最新数据。

根因

SigNoz 服务器 SIG-HOST 的系统时钟比实际慢 29 分钟,硬件时钟(RTC)正常:

Local time:     Tue 2026-10-27 17:08:43 CST      ← 系统时钟,慢 29 分钟
Universal time: Tue 2026-10-27 09:08:43 UTC
RTC time:       Tue 2026-10-27 09:37:37          ← 硬件时钟,正确
NTP enabled:    no
NTP synchronized: no

页面 SQL 为 WHERE timestamp BETWEEN (now()-30m) AND now(),其中 now() 取自 SigNoz 系统时钟。时间窗上界因此落在实际时间 29 分钟之前,窗口内只剩 29~59 分钟前的历史数据。

验证方法

同一接口两种写法对比,结果相差 3 倍:

写法结果
timestamp > now() - 30m(不设上界)15 条
timestamp BETWEEN now()-30m AND now()(页面写法)5 条

三方时间对比(UTC):

来源时间说明
应用服务器(写入 span)09:37:29正常
运维终端09:37:19正常
SigNoz 服务器09:08:22慢 29 分钟

处理

# 1) 确认硬件时钟正常
timedatectl status

# 2) 从硬件时钟同步系统时钟(该服务器无外网,无需安装 NTP 软件)
hwclock --hctosys

# 3) 确认
date

验证

ClickHouse now() : 09:40:29
终端 UTC          : 09:40:32
偏差              : 0.1 分钟

两种查法结果一致(14 = 14),最近 5 分钟数据实时可见,页面刷新后调用总次数正常增长。

影响范围

该偏差使所有基于时间窗的功能整体偏移:

功能表现
接口监控调用总次数显示 29~59 分钟前的数据
接口调用总览图表时间轴与实际不符
链路 / 指标 / 日志监控「最近 N 分钟」查不到最新数据
告警计算窗口告警延迟约 29 分钟
按天分区边界边界错位

预防

该服务器未启用 NTP(NTP enabled: no),时钟会持续漂移,29 分钟量级说明已漂移数周。建议:

  1. 配置内网 NTP 源,启用 chrony 自动同步:
    yum install -y chrony
    vi /etc/chrony.conf      # server <内网NTP地址> iburst
    systemctl enable --now chronyd
    chronyc makestep
    
  2. 若暂无 NTP 源,用计划任务定期从 RTC 对齐:
    0 3 * * * /sbin/hwclock --hctosys
    
  3. 将「服务器时钟偏差」列入日常巡检项,与 ClickHouse 写入量一并检查。

问题 20:性能问题(部署期间顺带发现)
#

接口 / 组件数据问题
QYSL/enterprise/business/mainpage8 次,平均 33,099 ms(33 秒)严重慢,需查 span 明细
QYSL/enterprise/business/havedone/query1 次,2,969 ms慢
XZSP/approval/workextend1,671 次,平均 1,551 ms高频慢接口
XZSP/approval/worktodolist/businessOpinion1 次,964 ms慢
QYSL/web/enterprise/updateBizState26 次,870 ms慢
SELECT orcl.WEBFINAL_APP_CONFIG48,044 次 / 6 小时(133 次/分)配置表无缓存,建议加 Caffeine,TTL 30s
HTTP 状态码 null7,389 / 7,534OTel agent 未采集到大部分 http.status_code,导致错误率统计偏低

第二部分 修改了哪些文件、思路与代码解释
#

2.1 修改文件总览
#

#文件类型改动要点
1D:\server\dgov-obs-business-service\application-dev.yaml配置换库地址、关 Kafka、删多余数据源
2D:\server\dgov-obs-resource-service\application-dev.yaml配置同上
3D:\server\apache-tomcat-9.0.87-*\bin\setenv.bat × 3新增加 OTel + JMX 探针
4D:\server\nginx\conf\nginx.conf配置加 /dms/、/posthog/、禁缓存
5D:\server\nginx\html\dms\index.html新增工单占位页
6D:\server\nginx\html\posthog\index.html新增行为分析占位页
7D:\server\nginx\html\obs\index.html配置改配置版本号
8D:\server\nginx\html\obs\config.signoz.js配置覆盖初始地址
9D:\server\nginx\html\obs\config.dms.js配置工单地址改本地
10D:\server\nginx\html\obs\js\index-B14RlMeI.js前端服务名改真实值
11D:\server\nginx\html\obs\js\signozService-Cg3RwBMu.js前端SQL http.target → http.route
12D:\server\apache-tomcat-9.0.87-WebSite\...\lib\jcore-1.0.jar替换用 jcore-3.5.jar 替换
13Nacos dgov-cloud-gateway配置tokenWhiteList 加 6 条
14SigNoz 告警规则(24 条)数据替换初始地址
15ClickHouse UDF 权限系统chmod +x histogramQuantile
16cmdb_* 各类资源表数据换真实数据

2.2 application-dev.yaml(业务服务,8089)
#

原始配置
#

server:
  port: 8089
  servlet:
    context-path: /obs/business

spring:
  cloud:
    dubbo:
      enabled: false
    stream:                       # Kafka 启用
      defaultBinder: kafka
      kafka:
        binder:
          brokers: OLD-HOST-KAFKA:9092
      bindings:
        signozAlertProducer-out-0:
          destination: dsm.oms.sync
  datasource:
    dynamic:
      primary: primary
      public-key: MFwwDQYJKoZIhvcNAQEB...     # 用于解密 ENC() 密码
      datasource:
        primary:                              # MySQL(青岛环境)
          url: jdbc:mysql://EXT-HOST-1:3306/dgov-obs-behavior
          username: qingdao
          password: ENC(aa1VORxQvP/8jx33k9dgPUOs88DMVh5ihPYkwWq7ashZFl6mULgM/8JUMps6A3IhIdvQ6tfZA5MZku8kGg0M5w==)
        teledb:                               # TiDB
          url: jdbc:mysql://EXT-HOST-2:3307/dgov-obs-behavior
          username: dgov_admin
        highgo:                               # 瀚高数据库
          url: jdbc:highgo://EXT-HOST-3:5866/dgov_obs_behavior
          username: sysdba
        clickhouse:
          url: jdbc:ch://OLD-HOST-2:8123/default

signoz:
  server: http://OLD-HOST-1:8086
  queryUri: /api/v5/query_range

messageCenter:
  url: http://localhost:8192/messagecenter/sendSMSMsg
  template: "【系统告警】收到 Signoz 告警: {alerts}"
  phone: "13800138000"

现网配置(当前)
#

server:
  port: 8089
  servlet:
    context-path: /obs/business

spring:
  cloud:
    dubbo:
      enabled: false                              # 原本就是 false,未改动
    # Kafka disabled (no Kafka in this site).
    # stream:                                     # ← 整块注释
    #   ... brokers: 127.0.0.1:9092
  datasource:
    dynamic:
      primary: primary
      datasource:
        primary:
          url: jdbc:mysql://DB-HOST-B:3306/dgov-obs-behavior?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai
          username: dgov_obs
          password: '<dgov_obs-密码>'
          driver-class-name: com.mysql.cj.jdbc.Driver
        clickhouse:
          url: jdbc:ch://SIG-HOST-B:8123/default?compress=true&async=1
          username: default
          driver-class-name: com.clickhouse.jdbc.ClickHouseDriver
          hikari:
            max-pool-size: 10
            connection-timeout: 30000
            idle-timeout: 600000

signoz:
  user: your-email@example.com
  password: '<SigNoz-密码>'
  server: http://SIG-HOST-B:8086
  tokenUri: /api/v2/sessions/email_password
  orgUri: /api/v2/sessions/context
  loginUri: /login
  queryUri: /api/v5/query_range

messageCenter:
  url: http://127.0.0.1:8192/messagecenter/sendSMSMsg
  template: "Signoz Alert: {alerts}"
  phone: "13800138000"
  smsChannelId: "signoz"

逐项改动与理由
#

#配置项原值现在理由
1spring.cloud.stream 整块启用注释本环境无 Kafka。启用会不停重连 OLD-HOST-KAFKA:9092,刷错误日志
2datasource.primary.urlEXT-HOST-1:3306DB-HOST-B:3306换成本地 MySQL(B 区地址,115 可达)
3datasource.primary.usernameqingdaodgov_obs本地库账号
4datasource.primary.passwordENC(...) 密文明文密文需 public-key 解密,换库后直接用明文更简单
5datasource.public-key有删除不再用 ENC(),公钥无用
6datasource.teledb有(TiDB)删除本环境无 TiDB
7datasource.highgo有(瀚高)删除本环境无瀚高
8datasource.clickhouse.urlOLD-HOST-2:8123SIG-HOST-B:8123SigNoz 的 ClickHouse
9signoz.serverOLD-HOST-1:8086SIG-HOST-B:8086真实 SigNoz 地址(服务端走 B 区)
10messageCenter.urllocalhost:8192127.0.0.1:8192等价
11messageCenter.template中文模板英文模板避免编码问题

配置含义解释
#

server

port: 8089                    # 服务监听端口(对应 java 进程 PID 12316)
context-path: /obs/business   # URL 前缀 → 所有接口是 /obs/business/xxx

spring.cloud.dubbo.enabled: false

本服务不用 Dubbo(只访问 MySQL + ClickHouse + SigNoz HTTP API)。 若改 true,启动时会去找 Dubbo 注册中心(ZooKeeper/Nacos),找不到就报错。

spring.cloud.stream(Kafka)

原设计链路:

SigNoz 告警 → Webhook → OBS 业务服务 → Kafka topic: dsm.oms.sync → DMS 工单系统 → 自动建工单

本环境无 Kafka,该链路断开。告警→工单目前只能靠 HTTP webhook 直连。

datasource.dynamic(多数据源)

使用 dynamic-datasource 组件,primary: primary 表示 @DS 不指定时默认用 primary。 原设计兼容 4 种数据库(MySQL / TiDB / 瀚高 / ClickHouse),本环境只用 MySQL + ClickHouse。

datasource.clickhouse

url: jdbc:ch://.../default        # default 库是空的,代码里 SQL 都写了全名 signoz_traces.xxx 才能用
compress=true                     # LZ4 压缩
async=1                           # 异步插入
hikari.max-pool-size: 10          # 连接池上限

signoz

键含义
user / passwordSigNoz 登录账号,用于换 token
serverSigNoz 后端地址
tokenUri登录接口 /api/v2/sessions/email_password
orgUri组织信息接口(SigNoz 部分 API 需要 orgID)
loginUri网页登录页
queryUri查询接口 /api/v5/query_range:SignozProxyController 转发时用

messageCenter

url: http://127.0.0.1:8192/messagecenter/sendSMSMsg   # 短信网关
template: "Signoz Alert: {alerts}"                     # 短信内容,{alerts} 被替换为告警 JSON
phone: "13800138000"                                   # 收件手机号(占位假号)
smsChannelId: "signoz"                                 # 短信通道 ID

遗留风险(4 项)
#

  1. teledb / highgo 删除后:若代码中有 @DS("teledb") / @DS("highgo"),运行时会抛异常。需确认代码是否引用。
  2. messageCenter 指向的 127.0.0.1:8192 服务不存在:短信告警必然失败。
  3. 密码明文存储:原设计用 ENC() + public-key 加密,现为明文。安全测评会被提。
  4. clickhouse 连 default 空库:任何不带库名前缀的查询都会 404。建议改为 signoz_traces。

2.3 setenv.bat(探针配置,新增 3 个)
#

文件位置
#

D:\server\apache-tomcat-9.0.87-ACCEPT\bin\setenv.bat     (综合受理,8010)
D:\server\apache-tomcat-9.0.87-Parallel\bin\setenv.bat   (并联审批,8068)
D:\server\apache-tomcat-9.0.87-WebSite\bin\setenv.bat    (网办后台,8030)

XZSP(8090)原本已有,作为模板。

内容(以 Parallel 为例)
#

@echo off
set "JAVA_OPTS=%JAVA_OPTS% -javaagent:D:\app\jmx_prometheus\jmx_prometheus_javaagent-0.15.0.jar=9997:D:\app\jmx_prometheus\config.yaml"
set "JAVA_OPTS=%JAVA_OPTS% -javaagent:D:\app\opentelemetry-javaagent\opentelemetry-javaagent.jar"
set "JAVA_OPTS=%JAVA_OPTS% -Dotel.service.name=INSPUR-DZZW-BLSP"
set "JAVA_OPTS=%JAVA_OPTS% -Dotel.exporter.otlp.endpoint=http://SIG-HOST-B:4318"
set "JAVA_OPTS=%JAVA_OPTS% -Dotel.exporter.otlp.protocol=http/protobuf"
set "JAVA_OPTS=%JAVA_OPTS% -Dotel.traces.exporter=otlp"
set "JAVA_OPTS=%JAVA_OPTS% -Dotel.resource.attributes=app.code=INSPUR-DZZW-BLSP,deployment.environment=production,environment=production"
set "JAVA_OPTS=%JAVA_OPTS% -Dotel.traces.sampler=parentbased_traceidratio"
set "JAVA_OPTS=%JAVA_OPTS% -Dotel.traces.sampler.arg=1.0"
set "JAVA_OPTS=%JAVA_OPTS% -Dotel.logs.exporter=none"

逐行解释
#

行含义
@echo off关闭命令回显
-javaagent:jmx_prometheus_javaagent-0.15.0.jar=9997:config.yamlJMX 探针,在 9997 端口暴露 JVM 指标(堆内存/GC/线程/连接池)
-javaagent:opentelemetry-javaagent.jarOTel 探针,自动给 Spring/JDBC/Dubbo/HTTP 调用打埋点,生成 Trace
-Dotel.service.name=INSPUR-DZZW-BLSP服务名,SigNoz 里按这个分组
-Dotel.exporter.otlp.endpoint=http://SIG-HOST-B:4318上报地址(B 区 OTel Collector,走 HTTP/4318)
-Dotel.exporter.otlp.protocol=http/protobuf传输协议
-Dotel.traces.exporter=otlp只导出 Trace(不导 metrics/logs)
-Dotel.resource.attributes=app.code=...,deployment.environment=production资源属性,便于筛选
-Dotel.traces.sampler=parentbased_traceidratio采样策略:按 traceID 比例
-Dotel.traces.sampler.arg=1.0采样率 100%(低流量系统全采才有意义)
-Dotel.logs.exporter=none不采集日志(避免重复采集、避免量太大)

关键点:JMX 端口必须唯一
#

Tomcat端口JMX
XZSP80909999(原有)
Parallel80689997
ACCEPT80109998
WebSite80309996

端口冲突会导致第二个 Tomcat 起不来。

编码规范(曾经遇到)
#

  • 必须 CRLF 换行
  • 必须纯 ASCII(中文注释会导致 'xxx' 不是内部或外部命令)

2.4 nginx.conf
#

完整结构
#

worker_processes  1;
error_log  logs/error.log  warn;
pid        logs/nginx.pid;

events {
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    client_max_body_size 100m;

    server {
        listen       80;
        server_name  _;

        # ① 前端静态文件
        location /obs/ {
            alias  D:/server/nginx/html/obs/;
            index  index.html;
            try_files $uri $uri/ /obs/index.html;
        }

        # ② 网关
        location /gate/ {
            proxy_pass http://127.0.0.1:30901/gate/;
            proxy_http_version 1.1;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-Proto $scheme;
            proxy_connect_timeout 30s;
            proxy_read_timeout 300s;
            proxy_send_timeout 300s;
        }

        # ③ BSPPLUS
        location /ucenter/ {
            proxy_pass http://127.0.0.1:9099/;
            proxy_http_version 1.1;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_read_timeout 300s;
        }

        # ④ 行为分析占位页
        location /posthog/ {
            alias  D:/server/nginx/html/posthog/;
            index  index.html;
            try_files $uri $uri/ /posthog/index.html;
        }

        # ⑤ 工单系统:模拟「未找到工单」
        location = /dms/local/dsm-plugin-oms/api/order/getInfo {
            default_type 'application/json; charset=utf-8';
            add_header Cache-Control 'no-store';
            return 200 '{"state":0,"message":"TkOrder not found: DMS not connected"}';
        }

        # ⑥ 工单占位页
        location ^~ /dms/ {
            alias  D:/server/nginx/html/dms/;
            index  index.html;
            try_files $uri $uri/ /dms/index.html;
        }

        # ⑦ 前端配置文件禁缓存
        location ~ ^/obs/config\.[a-z0-9]+\.js$ {
            root   D:/server/nginx/html;
            add_header Cache-Control "no-cache, no-store, must-revalidate";
            add_header Pragma "no-cache";
            expires -1;
        }

        # ⑧ 根路径
        location = / { return 302 /obs/; }

        location / {
            root   D:/server/nginx/html;
            index  index.html;
        }
    }
}

各 location 解释
#

#location作用关键点
①/obs/前端静态文件alias 而不是 root;try_files 兜底到 index.html(Vue history 路由需要)
②/gate/转发到网关 30901proxy_pass 带 /gate/ 路径,网关侧再做 StripPrefix
③/ucenter/转发到 BSPPLUS 9099登录、菜单、SSO
④/posthog/行为分析占位页PostHog 未部署
⑤= /dms/…/getInfo精确匹配,直接返回 JSON= 优先级最高;返回 TkOrder not found 让前端走友好分支
⑥^~ /dms/工单占位页^~ 表示前缀匹配后不再检查正则
⑦~ ^/obs/config\.…js$配置文件禁缓存正则匹配,比前缀匹配优先级高(除 ^~ 和 =)
⑧= /根路径重定向到 /obs/—

location 匹配优先级(Nginx 规则)
#

1. = /exact          精确匹配,最高优先级
2. ^~ /prefix        前缀匹配,命中后不再检查正则
3. ~  regex          正则匹配(按配置文件中的顺序,第一个命中的生效)
4. /prefix           普通前缀匹配,选最长匹配

曾经遇到的问题
#

第一次插入 /posthog/ 时放错了大括号层级(放到了 server{} 外面), 导致 nginx -t 报错、nginx -s reload 静默失败、页面一直 404。

做法:每次改完必须 nginx -t 验证,再 -s reload。


2.5 前端 Js 补丁(3 个文件)
#

2.5.1 index-B14RlMeI.js — 服务名
#

改前

serviceName: "INSPUR-DZZW-CJSXGC-V6"     // 公司「一件事一次办 V6」,本环境不存在

改后

serviceName: "INSPUR-DZZW-XZSP"          // 通用审批(真实在跑,流量最大)

思路

service.name 是 SigNoz 的服务过滤条件,代码里写死了示例服务名 → 查询 0 条。 换成本环境真实服务名。

遗留问题:这个文件里 serviceName 出现 2 次(查询 + 详情路由跳转),都已替换。


2.5.2 signozService-Cg3RwBMu.js — SQL 修正
#

改前

  AND attributes_string['http.target'] IN $http.route

改后

  AND attributes_string['http.route'] IN $http.route

完整 SQL(改后)

SELECT
    attributes_string['http.route'] AS `接口地址`,
    toFloat64(count()) AS `调用总次数`,
    toFloat64(countIf(toFloat64OrNull(response_status_code) >= 400)) AS `错误次数`,
    if(
        toFloat64(count()) > 0,
        (toFloat64(countIf(toFloat64OrNull(response_status_code) >= 400)) / toFloat64(count()) * 100),
        0
    ) AS `错误率(%)`,
    if(
        toFloat64(count()) > 0,
        if(
            (toFloat64(countIf(toFloat64OrNull(response_status_code) >= 400)) / toFloat64(count()) * 100) > 10,
            '异常', '正常'
        ),
        '无流量'
    ) AS `接口状态`
FROM signoz_traces.distributed_signoz_index_v3
WHERE timestamp BETWEEN {{.start_datetime}} AND {{.end_datetime}}
  AND attributes_string['http.scheme'] = 'http'
  AND attributes_string['http.target'] NOT LIKE '%/static/%'
  AND attributes_string['http.target'] NOT LIKE '%.css'
  AND attributes_string['http.target'] NOT LIKE '%.js'
  AND attributes_string['http.target'] NOT LIKE '%.png'
  AND attributes_string['http.target'] NOT LIKE '%.ico'
  AND attributes_string['http.route'] IN $http.route
GROUP BY `接口地址`
ORDER BY `调用总次数` DESC

思路

http.target = 完整请求路径(含 query string);http.route = 路由模板(不含参数)。 前端传的是路由模板(/xxx/yyy),必须用 http.route 匹配才命中。

这个 SQL 是通过 POST /obs/business/signoz/proxy/api/v5/query_range 转发的, body 里带 type: "clickhouse_sql"。当前网关返回 非法参数,此功能仍未生效:见问题 14。


2.6 config.dms.js(工单地址本地化)
#

改前

DMS_APP_KEY: "",
DMS_APP_TOKEN: "",
DMS_API_ROOT: "https://dms.example.com",
DMS_DETAIL_PAGE_URL: "https://dms.example.com/dsm/ticket/work/detail",
DMS_CREATE_PAGE_URL: "https://dms.example.com/dsm/ticket/work/addProblem?code=CATA20260707115553259&backPath=%252Fwork%252Fsubmit",
DMS_ORDER_INFO_PATH: "/local/dsm-plugin-oms/api/order/getInfo",
DMS_HTTP_TIMEOUT: 30000

改后

DMS_API_ROOT: '/dms',
DMS_DETAIL_PAGE_URL: '/dms',
DMS_CREATE_PAGE_URL: '/dms',
DMS_HTTP_TIMEOUT: 5000

思路

  1. 改同源相对路径 → 消灭 DNS 解析和外网等待
  2. 超时 30s → 5s → 快速失败
  3. 配合 Nginx 返回 TkOrder not found → 前端走「尚未生成工单 → 创建工单」的友好分支

前端逻辑链

POST {DMS_API_ROOT}{DMS_ORDER_INFO_PATH}
  ↓ state !== 1 且 message 含 "TkOrder not found"
  → err.code = "TK_ORDER_NOT_FOUND"
  ↓
confirm("该告警尚未生成工单,是否前往创建工单?")
  ↓ 点确定
window.open(DMS_CREATE_PAGE_URL)     // → 打开 /dms 占位页

2.7 config.signoz.js(覆盖历史地址)
#

思路

前端 env-xH10ADq8.js 里烘焙了历史环境地址:

VITE_SIGNOZ_BASE_URL: "http://OLD-HOST-1:3301"
VITE_SIGNOZ_API_URL:  "http://OLD-HOST-1:8086"
VITE_APP_API_URL:     "http://OLD-HOST-3:31225/gate"
VITE_APP_OAUTH2_SERVER_URL: "http://OLD-HOST-3:32520/ucenter"

配置解析优先级:

window.posthogConfig → window.publicConfig → window.signozConfig → 烘焙默认值 I[key]

因此在 config.signoz.js 里设置 window.signozConfig 即可覆盖烘焙值,无需改打包产物。

关键设计:双网卡地址不能填错

调用方用哪个地址原因
浏览器(前端)SIG-HOST:8086(A 区)我的电脑在 A 区
服务端(后端/探针)SIG-HOST-B:4318/8086(B 区)115 与 B 区互通,且 OTel 上报已验证可用

填反了会导致:前端打不开 SigNoz 页面,或后端上报不到数据。


2.8 index.html(配置版本号)
#

改前

<script src="./config.js?id=1792120301403"></script>
<script src="./config.signoz.js?id=1792120301403"></script>
<script src="./config.posthog.js?id=1792120301403"></script>
<script src="./config.dms.js?id=1792120301403"></script>

改后

<script src="./config.js?id=202610271345"></script>
...(4 个文件全部更换 id)

思路

?id= 是打包工具生成的固定版本号,浏览器据此判断缓存是否有效。 不换 id,改了 config.*.js 也不会生效。

根治办法:Nginx 对 config.*.js 加 no-store(见 2.4 第 ⑦ 条),以后改配置不用再换 id。


2.9 jcore-1.0.jar → jcore-3.5.jar(网办后台)
#

操作

$lib = "D:\server\apache-tomcat-9.0.87-WebSite\webapps\iWebSite\WEB-INF\lib"

# 备份
Copy-Item "$lib\jcore-1.0.jar" "$lib\jcore-1.0.jar.bak-<时间戳>"

# 从 XZSP 取新版
Copy-Item "...\XZSP\webapps\Inspur.Dzzw.WebApproval\WEB-INF\lib\jcore-3.5.jar" "$lib\jcore-3.5.jar"

# 旧版改名禁用(不是删除,可回滚)
Move-Item "$lib\jcore-1.0.jar" "$lib\jcore-1.0.jar.disabled-<时间戳>"

# 重启

回滚

Move-Item "$lib\jcore-1.0.jar.disabled-*" "$lib\jcore-1.0.jar"
Move-Item "$lib\jcore-3.5.jar" "$lib\jcore-3.5.jar.unused"

思路

这不是"破解授权",而是把漏升级的组件升到公司当前版本(其他 3 个产品都在用 jcore-3.5)。 风险在 API 兼容性,不在合规性。已验证 jcore-1.0 → jcore-3.5 兼容。

待办:仍需公司(成哥)确认此替换是被支持的,并排查其他服务器上的应用是否有同样问题。


2.10 Nacos 网关配置(dgov-cloud-gateway)
#

改前

security:
  custom:
    tokenWhiteList:
      - /gate/bspplus/utils/uuid
      # ...(原有条目)

改后(追加 6 条)

security:
  custom:
    tokenWhiteList:
      - /gate/bspplus/utils/uuid
      - /gate/bspplus/utils/**        # 工具类(uuid、滑块验证码等)
      - /gate/bspplus/user/login      # 登录
      - /gate/bspplus/user/signOn/login  # 单点登录
      - /gate/bspplus/oauth/**        # OAuth
      - /gate/bspplus/sso/**          # SSO
      - /gate/bspplus/user/logout     # 退出

思路

GlobalAuthorizationFilter 用 AntPathMatcher 匹配,支持 ** 通配。 白名单只放登录/工具/SSO 这类必需免登录的路径,不放业务接口。

注意:anon-white-list 在本环境不生效(因为 api-auth-check-enable: false 关掉了对应过滤器),不要再往那里加。


2.11 数据库改动
#

2.11.1 CMDB 资源表(换真实数据)
#

表现网行数备份表
cmdb_compute_resource(服务器)9_bak20261027
cmdb_db_resource(数据库)3_bak20261027
cmdb_comp_resource(中间件)5_bak20261027
cmdb_application(应用)16_bak20261027
cmdb_app_service(应用服务)9_bak20261027b
cmdb_app_interface(接口)138_bak20261027b(709) / _bak20261027c(709)

回滚方式(以接口表为例)

DELETE FROM `dgov-obs-behavior`.cmdb_app_interface;
INSERT INTO `dgov-obs-behavior`.cmdb_app_interface
SELECT * FROM `dgov-obs-behavior`.cmdb_app_interface_bak20261027c;

2.11.2 cmdb_app_interface 实际表结构
#

id              varchar(64)   NOT NULL
app_id          varchar(64)   NOT NULL
service_id      varchar(64)   NULL
api_name        varchar(255)  NOT NULL
api_path        varchar(500)  NOT NULL
method          varchar(20)   NULL
type            int(11)       NOT NULL      -- 1 = HTTP 接口
remark          varchar(500)  NULL
create_time     datetime      NULL
update_time     datetime      NULL
create_by       varchar(64)   NULL
update_by       varchar(64)   NULL
del_flag        int(11)       NULL          -- 0 = 有效
is_high_risk    int(11)       NOT NULL      -- 1 = 高危(默认筛选项)

注意:没有 app_name 列(曾经遇到:按 app_name 插入会报 ERROR 1054)。应用名通过 app_id 关联 cmdb_application 查。

2.12 SigNoz 侧改动
#

2.12.1 告警规则(24 条)
#

  • 改动内容:annotations.description / annotations.summary 里的 HTML 链接
  • 改前:http://OLD-HOST-1:8086/...
  • 改后:http://SIG-HOST:8086/...
  • API:PUT /api/v2/rules/{id} → 204
  • 验证:残留 0 处

2.12.2 ClickHouse UDF 权限
#

docker exec -u root signoz-clickhouse chmod +x /var/lib/clickhouse/user_scripts/histogramQuantile

说明:docker exec 不做 shell 通配符展开,用 chmod +x /path/* 会报 cannot access '/path/*': No such file or directory。必须写完整文件名,或加 bash -c。


写在最后
#

这 20 个问题里,只有 3 个是"配置写错了一个参数"。剩下的要么是信息藏在二进制里(jar 里的硬编码日期),要么是跨越了多个组件(网关拦了、前端 SQL 不对、服务器时钟还偏),要么是报错信息完全误导(应用启动失败但日志只说 not initialize)。

几点体会:

1. 报错信息不可信的时候,去看底层。

“启动即退出"看起来像配置问题、像网络问题、像授权问题,实际是 jar 里一个硬编码的日期字符串。这种信息,配置文件里永远找不到,只能反编译 class 看常量池。

2. 现象和根因之间可能隔着好几层。

“调用次数是 0"这一个现象,背后是三个独立的问题:SQL 匹配字段不对、网关的安全策略拦了查询请求、服务器时钟偏移把时间窗切掉了。修完前两个数字能出来了,但只出来一部分——第三个问题才让数字完全对上。

3. 时间基准是所有监控的地基。

可观测平台的所有查询都是"某段时间内的数据”。如果服务器时钟偏了 29 分钟,那所有"最近 N 分钟"的视图都在看历史数据,所有告警都会延迟。这个问题很难从界面上看出来,因为界面上的数字"看起来是正常的”,只是永远不更新。

4. 文档里不会写的,才是真正花时间的地方。

公司部署手册写的都是"配置这一项、启动服务、访问地址"。真实环境里的问题,是 License 过期、jar 版本不一致、bat 文件编码、双网卡地址填反这一类。这些只能靠现场踩。

如果这篇能让你少踩两个坑,那就值了。


本文所有 IP、账号、密码、域名均已脱敏,仅保留技术细节。

附录 A 环境信息速查
#

主机与地址
#

用途A 区B 区
应用服务器APP-HOSTAPP-HOST-B
可观测平台服务器SIG-HOSTSIG-HOST-B
MySQLDB-HOST:3306DB-HOST-B:3306
OracleDB-HOST:1521—

服务端口
#

服务端口进程
Nginx80—
网关30901java
BSPPLUS9099java
obs-resource-service8087java
obs-business-service8089java
Nacos8848java
Tomcat XZSP8090java
Tomcat ACCEPT8010java
Tomcat Parallel8068java
Tomcat WebSite8030java
JMX 探针9996/9997/9998/9999—

关键凭据
#

项值
平台登录admin / <平台管理员密码>
MySQL root<MySQL-root-密码>
MySQL dgov_obs<dgov_obs-密码>
MySQL dgov_bsp<dgov_bsp-密码>
SigNozyour-email@example.com / <SigNoz-密码>
SigNoz orgID<org-id>

访问地址
#

用途地址
平台前端http://APP-HOST/obs/#/login
SigNoz(浏览器)http://SIG-HOST:8086
ClickHouse HTTPhttp://SIG-HOST:8123

附录 B 经验总结
#

B.1 Windows 脚本类
#

问题现象正确做法
.bat 用 LF 换行'xxx' 不是内部或外部命令、中文碎片被执行必须 CRLF
.bat 含中文cmd 解析乱码纯 ASCII,注释也用英文
管道接驻留进程命令行永久挂住Start-Process -WindowStyle Hidden,不接管输出
docker exec 用通配符cannot access '/path/*'写完整路径,或 bash -c 'cmd *'

B.2 前端补丁类
#

问题正确做法
改了 config.*.js 不生效换 ?id= 版本号 + Nginx 对 config 禁缓存
报错被 try/catch 吞掉我排查时先看 Console 报错,不要只看界面

B.3 排查方法类
#

场景方法
不知道某接口/某功能怎么实现的反编译 jar(javap -p -c),优先采用
不知道前端调的什么接口F12 → Network,看 URL + Payload + Response
不知道请求被谁拒绝看响应字段名:message = 业务服务,msg = 网关
不知道数据为什么查不到直连底层数据源验证(ClickHouse / MySQL),再逐层往上看
大文件 / 大目录占用按目录逐层统计(一级目录 → 子目录 → 单个文件)
服务重启后起不来先看 jar 里有没有硬编码的日期/授权检查(javap -p -constants)
数据「看起来没有采集」先核对各服务器时钟:date -u 逐台对比;时钟偏差会使 BETWEEN now()-N AND now() 的时间窗整体偏移

B.4 判断是否为本次改动引入的问题
#

现象判断依据
重启后起不来,日志有 DateUtils.compareDate不是配置问题,是 jar 里硬编码到期日
换配置后还是不生效先确认文件真的被加载了(浏览器缓存 / 服务是否重启)
功能一直返回空先直连数据源验证数据存在,再排除中间层

文档结束


Weidong's Blog 伟东
Weidong’s Blog 伟东
欢迎访问我的技术博客,记录工具、踩坑、系统运维经验。