最近帮一个团队交付一套完全隔离的数据库集群,网络环境很严格,除了 SSH 端口,其余端口都要走流程申请放行,服务器不能访问外部软件源,也不能随便装包。TiDB 集群本身倒是装得顺利,官方离线包一次搞定,真正卡住我大半天的是给这套集群配齐各种 Agent。监控采集的要装,状态上报的要配,数据同步的也要跑起来。平时在公网环境,yum install一下、改两行配置、systemctl start就能跑完的事,一进内网就变成另一回事:依赖要先备齐、端口要提前核对、主机名解析不正确、时间不同步,每一步都可能踩坑。这篇文章就从零开始,讲讲内网这种受限环境里,TiDB 周边 Agent 到底怎么配,才能既装得上、跑得动,又能长期稳定不闹脾气。
为了避免概念漂移,我先说明:本文里的“Agent”,指的是部署在 TiDB 集群周边、以独立进程运行的常驻组件,用来采集监控指标、上报集群状态、或者承担访问通道。这类组件的配置思路高度一致,你只要理解了一条主线,不管是官方组件还是自研脚本,都能套用。
1. 先说清楚:内网里的 TiDB Agent 到底在解决什么问题
1.1 三类常见 Agent 角色
很多人一听到“TiDB Agent”会下意识以为是一个固定软件,其实不是。它更像一个角色分类,我按实际项目里最常见的用途,把它分成三类:
- 监控采集类 Agent:这是最普遍的一类。TiDB 集群装好后,Prometheus 需要从各个节点拉取指标,node_exporter 暴露主机资源指标,TiDB 组件自带的 metrics 端点也需要被周期访问。这类 Agent 的本质是一个补充采集器,把监控体系够不到的数据补齐。
- 数据通道类 Agent:比如 TiCDC、syncer 这类的同步组件,它们把 TiDB 的变更数据实时同步到下游 Kafka、MySQL 或数仓。严格说它们也是 Agent,负责一条数据管道的搬运和服务。
- 访问代理类 Agent:统一承接应用侧请求,做连接池、审计、透明转发。这类组件在网络分区里可以屏蔽后端 TiDB 的拓扑变化。
由于没有限定具体是哪一种,本文以“监控采集 Agent”为主线展开,这是绝大多数内网环境最先要解决的问题。数据通道和访问代理的配置方法,在连接参数、权限控制、网络放通这几个维度上完全一致。
1.2 内网环境的三个约束条件
公网环境下部署 Agent 真的很轻松:拉包、装依赖、配域名、起服务,出问题还能一搜一大把解决方案。可一旦进入内网,我总结下来有三个约束会一直卡着你:
第一,没有外网依赖源。很多 Agent 运行时依赖的库,在内网机器上装不了,必须在办公网提前准备离线包。而离线包这东西有个麻烦,版本差一个 Patch 都可能行为不同,必须先考试再上场。
第二,端口放行是刚性的。Agent 不是只要连上 TiDB 的 4000 端口就完事了。TiDB 是计算存储分离的架构,SQL 语句进了 4000 端口之后,还要通过 PD 获取路由信息,再访问 TiKV 拿实际数据。整个链路涉及的端口,任何一个没放通,Agent 看起来能连、实际取不到数。
第三,基础设施的隐性依赖。内网环境往往没有成熟的 DNS 体系,主机名解析时灵时不灵;没有 NTP 服务的话,每台服务器的时间各走各的,Agent 上报的数据点时间戳和 TiDB 集群不一致,告警和监控完全没法看。
认识这三条约束以后,后面的每一步准备工作就都有了针对性。接下来我从实操角度把整条链路拆开讲。
2. 内网环境下的事前准备:离线物料与全网段规划
2.1 物料清单要在办公网一次备齐
进入内网之前,先在一台有外网的机器上把所有依赖一次下载好,做成一个物料包,然后一起拷过去。这个物料包具体要什么,我按最小集列一下:
| 组件 | 用途 | 校验方式 |
|---|---|---|
| TiDB 官方离线安装包 | 集群自身以及配套 prometheus、grafana 等 | sha256sum |
| node_exporter 二进制 | 主机指标采集 | sha256sum |
| Agent 可执行文件与默认配置 | 本次部署的核心组件 | sha256sum |
| JDK 或目标运行时 | 如果 Agent 是 Java 系组件,必须带离线 JDK | sha256sum |
| mysql 客户端 | Agent 联调时验证数据库连通性 | 可直接用二进制包 |
| sysstat、jq、telnet 等排障工具 | 后续排查几乎一定会用到 | rpm 包或 deb 包 |
物料包的下载策略有讲究。不要看到最新版本就下,要先确认 Agent 版本与 TiDB 集群版本的兼容范围。好多人在公网环境不太在意版本匹配,但内网环境一旦把包带进去发现不兼容,再返回去下载的沟通和审批成本非常高。正确做法是:先在文档站确认兼容矩阵,再按矩阵下载大版本内最稳定的那一个,最后用 sha256 校验每个包的完整性,避免内网传输中磁盘坏道导致文件损坏。
2.2 文件分发与本地软件源的搭建
如果只有三五台机器,用scp或rsync分发即可。但如果 Agent 需要部署在十几个节点上,我建议在管理网段搭一个临时文件源。最简单的做法是在一台装有 Python 或 Nginx 的机器上,把物料目录通过 HTTP 共享出来:
cd /data/tidb-agent-packages python3 -m http.server 8080 --bind 0.0.0.0然后各节点用wget http://repo-server:8080/xxx.tar.gz拉取。这样比逐个 scp 高效得多,而且不容易漏文件。对于用 yum/apt 管理的系统,还可以把 RPM 包配置成一个内网源:
# /etc/yum.repos.d/local.repo [local] name=Local Repository baseurl=http://repo-server/local-rpms enabled=1 gpgcheck=0这里要注意,内网源必须以gpgcheck=0或者准备好对应的签名密钥,否则 yum 会因为公钥缺失拒绝使用。很多刚进内网环境的朋友在这里第一次踩坑,进度直接卡住。
2.3 Agent 访问 TiDB 各端口的关系核对表
物料就绪之后,别急着装。先拿出一张纸,把“谁要访问谁”列清楚。我把 TiDB 生态中最常涉及的端口整理成一张表,你可以直接抄作业:
| 端口 | 对应组件 | 说明 |
|---|---|---|
| 4000 | TiDB Server | SQL 协议入口,Agent 执行 SQL 验证时必用 |
| 10080 | TiDB Server 状态端口 | 提供 metrics 和 pprof 端点 |
| 2379 | PD Client | 获取集群调度信息、读写路由信息 |
| 2380 | PD Peer | PD 集群内部通信,Agent 一般不直接访问 |
| 20160 | TiKV | 实际数据读写端口 |
| 20180 | TiKV 状态端口 | 暴露 TiKV 监控指标,Prometheus 直接抓取 |
| 9090 | Prometheus | 如果使用远程写入,Agent 需要访问该端口 |
| 9100 | node_exporter 默认端口 | 监控抓取目标 |
最容易犯的错就是只给 Agent 放通 4000 端口。你以为能连上数据库了,实际数据请求会卡在 TiKV 那一步,报错信息又非常隐蔽,只会看到超时。我在 2.3 节里先把这个表抛出来,是希望你在提交防火墙申请之前就按整条链路的端口一次性列全,别让流程来回折腾。
3. 配置文件逐项拆解:让 Agent 在内网正确认到 TiDB
3.1 一份兜底的 Agent 配置模板
不同 Agent 的配置文件名不同,但核心字段高度类似。我以一个典型的采集 Agent 为例,给出一个覆盖了绝大多数需求的配置模板:
global: listen: "0.0.0.0:9100" collect_interval: 15s namespace: "tidb-prod" tidb: endpoints: - "tidb-01.local:4000" - "tidb-02.local:4000" status_endpoints: - "tidb-01.local:10080" - "tidb-02.local:10080" user: "agent" password: "${AGENT_PASSWORD}" tls_enabled: true ca_cert: "/etc/tidb-agent/certs/ca.pem" cert: "/etc/tidb-agent/certs/agent.pem" key: "/etc/tidb-agent/certs/agent-key.pem" log: level: "info" output: "/var/log/tidb-agent/agent.log"3.2 最容易写错的核心字段:listen、endpoints、interval
listen为什么要写成0.0.0.0:9100而不是127.0.0.1:9100?因为 Agent 的指标通常要被 Prometheus 或监控平台从其他机器抓取,只监听回环地址会导致抓取方连接不上。如果你在安全意识比较强的内网里,可以只绑到业务网卡的 IP 上,比如10.20.3.15:9100,这样只有能访问该 IP 的机器能连到,这是更稳的一个方案。
endpoints一定要写多个 TiDB Server 地址。TiDB 天生是多实例架构,你只写一个地址,相当于把 Agent 的可用性和单一节点的健康绑定在一起。写多个地址以后,Agent 故障转移和负载均衡就有了基础。
collect_interval默认 15 秒比较稳妥。有些团队为了看更细的曲线,把采集间隔硬压到 3 秒或 5 秒,这在公网环境可能无所谓,但内网监控抓取也会产生连接和查询消耗。TiDB 的 metrics 端点在高频拉取下会带来额外的 CPU 开销,对生产集群不友好。我的建议是普通集群 15 秒足够,特殊情况再调到 10 秒以下。
3.3 认证与权限:最小权限的落地写法
Agent 的数据库账号一定要按最小权限原则来给,不要图省事直接用root。TiDB 的授权语法兼容 MySQL,可以直接这样建:
CREATE USER 'agent'@'10.20.%' IDENTIFIED BY '你的密码'; GRANT PROCESS, SELECT ON *.* TO 'agent'@'10.20.%';PROCESS权限用于查看会话信息,SELECT权限用于查询状态表和集群信息。这两样对绝大多数采集场景已经足够。重点说一下 host 部分,不要图省事写成'agent'@'%',而要用网段限制。内网不代表零风险,一旦有主机被攻破,@'%'账号就是整个数据库的常开大门。写成10.20.%后,Agent 所在网段以外的主机即使拿到了账号密码,也连不上 4000 端口,安全水位会明显提高。
3.4 内网到底要不要开 TLS
这个问题几乎每次都会被问到。有人觉得内网是隔离网络,传输不加密问题不大。我强烈建议不要这么做。内网的隔离边界往往没有你想象的清晰,交换机镜像、防火墙日志、内部扫描都可能存在,数据库账号密码和查询内容如果明文流经这些节点,等于把敏感数据直接暴露。所有的 Agent 配置都应该支持 TLS,证书可以由自建 CA 签发。TiDB 官方和客户端都兼容 MySQL 风格的 SSL 配置,启动tls_enabled即可。要注意的是,客户端连接串里要同时加上tls参数,否则就算服务端开了 TLS,客户端默认也可能走明文。
4. 用 systemd 托管 Agent:内网环境的标准启动方式
4.1 一份值得长期使用的 unit 文件
内网环境原则上没有人工值守,Agent 进程必须交给系统级守护进程来托管。Linux 下标准做法就是 systemd。我给一个经过多次生产环境验证的 unit 文件:
[Unit] Description=TiDB Agent Service After=network-online.target Wants=network-online.target [Service] Type=simple User=tidb Group=tidb EnvironmentFile=/etc/tidb-agent/agent.env ExecStart=/opt/tidb-agent/bin/agent --config /etc/tidb-agent/agent.yaml WorkingDirectory=/opt/tidb-agent Restart=always RestartSec=10 LimitNOFILE=1048576 LimitNPROC=65536 NoNewPrivileges=true PrivateTmp=true [Install] WantedBy=multi-user.target这个文件里的几个字段,每一个都不是随手加的。
User=tidb意味着 Agent 以非 root 身份运行。数据库相关组件如果以 root 跑,一旦进程被利用就直接拿到系统管理员权限,内网环境里这是绝对不能接受的。提前用useradd -r -s /sbin/nologin tidb建一个专用系统账号,然后把 Agent 的目录属主改成它。
Restart=always配合RestartSec=10,是内网无人值守场景的核心。Agent 进程崩溃后,10 秒内自动拉起。没有这行,凌晨三点 Agent 挂了,第二天上班监控数据一整夜都是空的。
LimitNOFILE=1048576是针对 TiDB 周边组件的特殊调整。Agent 运行时会持有大量连接和文件句柄,系统默认的 1024 或 65535 数值很容易不够用,导致进程明明活着,却无法建立新连接,报错“too many open files”。直接调高到百万级,一劳永逸。
EnvironmentFile=/etc/tidb-agent/agent.env把密码这类敏感信息分离出来,不直接写进 YAML 配置。agent.env 的内容类似:
AGENT_PASSWORD=你的密码这个文件的权限必须设成600,属主为tidb。这样即使配置文件被读取,也不会暴露数据库密码。
4.2 启动与自启的完整命令序列
配置写好后,按下面的顺序操作:
sudo systemctl daemon-reload sudo systemctl enable --now tidb-agent systemctl status tidb-agentdaemon-reload必须在新增或修改 unit 文件后执行,否则 systemd 会沿用旧配置。“enable”和“--now”连用,同时完成开机自启和立即启动。内网机房经常会有计划内断电重启,服务器起来后如果 Agent 不自启,监控就有空窗期,这是运维事故级别的低级问题。
启动后,检查日志不要用tail -f直接看文件,最好用 journald:
journalctl -u tidb-agent -fjournald 会自动记录标准输出和标准错误,还用彩色标注级别,排查起来直观很多。如果 Agent 本身没有写独立日志,合理配置 Systemd 的StandardOutput和StandardError字段,也能把输出重定向到指定的日志目录。
5. 验证联调:从端口探测到真实业务流量
5.1 最小连通性验证清单
配置文件和 systemd 都就绪后,真正重要的事情才开始:验证 Agent 到底能不能干活。我习惯按下面这个清单从底向上逐层确认,哪一步失败就立刻知道该去哪里查:
- 本机监听检查:
ss -lntp | grep 9100,确认端口已被 Agent 占用; - 本机指标抓取:
curl http://127.0.0.1:9100/metrics | head,确认进程能正常返回指标数据; - 远端抓取测试:从监控机执行
curl http://agent-ip:9100/metrics | head,确认防火墙没有拦截; - 数据库连通性:
mysql -h tidb-01.local -P4000 -uagent -p -e "select version();",确认账号权限和网络路径正常; - 集群拓扑查询:
mysql -h tidb-01.local -P4000 -uagent -p -e "SELECT * FROM information_schema.cluster_info;",这一步能验证 Agent 是否拿到了完整的集群路由信息。
5.2 一个反直觉但高频出现的验证失败场景
很多人做完第 4 步,看到版本号返回正常,就觉得 Agent 配置万无一失。但实际上,第 5 步才是最容易被忽略的杀手。cluster_info查询会向 PD 请求完整拓扑,然后返回 TiKV、TiDB 等各实例的地址信息。如果内网只放通了 4000 端口,没有放通 PD 的 2379 端口,这个查询会直接超时,报错信息通常像“TiKV server timeout”或者“PD server timeout”。
这个验证步骤的重要意义在于:Agent 要做的不只是连上一个数据库节点,它还要能感知整个集群的拓扑变化。如果拓扑通道被防火墙切断,Agent 表面看起来是活的,监控页面上却会持续报错或者完全拉不到数据。
5.3 验证 Agent 是否真的完成了一次采集
命令行验证通过后,还需要确认 Agent 自身确实执行过采集动作。最直接的方式是看 Agent 日志,查找最近一次采集的完成记录或错误记录。也可以在 Prometheus 的 targets 页面上,看 Agent 暴露的抓取端点是不是UP状态。
如果你用的是 Grafana 监控方案,还可以把时间范围调到最近 15 分钟,在 TiDB 相关面板上随便找一个指标看是否有点。这个动作看着简单,却能一次性确认 Prometheus 抓取链路、Agent 暴露端点、数据库采集权限三个环节同时正常。很多团队验证到这个环节才发现,Agent 的数据是空白的,因为 Prometheus 的抓取配置里 IP 写错了,或者抓取路径写错了。
6. 内网环境独有的坑与排查链路
6.1 坑一:内网 DNS 解析飘忽导致的连接不稳
现象非常隐蔽:Agent 刚启动时运行正常,过一段时间后日志里开始出现lookup tidb-01.local on 10.0.0.53:53: no such host或者connection refused,但重启 Agent 后又恢复正常。
排查链路是这样的:
- 在 Agent 所在机器上执行
getent hosts tidb-01.local,看是不是解析结果时有时无; - 执行
cat /etc/resolv.conf,确认 nameserver 是不是一个不可靠的 DNS; - 执行
cat /etc/hosts,看有没有写死记录。
内网 DNS 非常典型的问题是记录没做好或者 TTL 太短,经常出现间歇性解析失败。修复方案很简单:在/etc/hosts里把 TiDB 组件的关键主机名和 IP 对应关系写死,比如:
10.20.1.11 tidb-01.local 10.20.1.12 tidb-02.local 10.20.2.11 pd-01.local写完后重启 Agent,这个问题会立刻消失。治本方案是找内网基础设施团队把 DNS 记录做规范,但在系统层面写hosts是最快最稳的止血措施。
6.2 坑二:时钟不同步导致的数据时间戳错乱
内网如果缺少 NTP,集群节点和 Agent 之间的时间偏差会逐渐累积。现象是监控图上出现诡异的尖刺,或者数据永远滞后几分钟,更严重的情况下 SQL 里基于时间的查询都可能出错。
排查链路:
- 在 Agent 所在机器执行
timedatectl,看 System clock 与 NTP 状态; - 在 TiDB 节点执行
SELECT NOW();,对比两边时间差异; - 如果差异超过 1 分钟,基本可以确定是时钟同步问题。
修复方案是在所有相关节点配置 NTP 客户端,指向内网的 NTP 服务器:
# /etc/chrony.conf server 10.20.0.1 iburst然后重启 chronyd,观察时间差是否收敛:
systemctl restart chronyd chronyc sources -v如果内网确实没有 NTP 服务器,把 TiDB 其中的一台稳定机器临时当作时间源也是可行的临时方案。但最实际的建议是尽快建立基础设施级的 NTP,这不只是为 Agent 服务,整个集群和数据库都需要它。
6.3 坑三:防火墙只放通固定端口,导致 TiKV 数据链路中断
这是前面在端口核对表里埋过的伏笔。现象更加隐蔽:Agent 进程 running,连接测试也成功,监控抓取显示 UP,但实际指标数据稀疏,或者特定指标一直为零。
排查链路:
- 在 Agent 所在机器执行
telnet 10.20.3.11 20160,看看能不能通; - 如果超时,大概率是防火墙没放通 TiKV 的数据端口;
- 打开防火墙规则管理端,确认 20160 是否在放行列表里。
内网安全团队常以“最小放行”为原则,只开放了 SQL 端口和 SSH,像 20160 这种端口往往没在列表中。但 TiDB 架构决定了 SQL 层拿到路由信息后必须直连 TiKV 取数,这个端口不通,所有读请求都会超时。需要提交防火墙申请时,把 2379、20160、20180 这些端口和用途写明,说明它们是数据库集群内部通信的必需端口,而不是额外的开放面。
6.4 坑四:字符集参数不一致导致数据“假乱码”
数据库连接串里如果没有显式指定字符集,Agent 在连接 TiDB 时可能使用默认字符集,而 TiDB 端表的字符集又是 utf8mb4,两边一对接,中文字段就乱码了。排查时先看连接串里是否带了characterEncoding=utf8mb4,没有就加上。这个问题在内网里容易被人忽略,因为开发环境大家用的是图形化客户端,通常自动帮你处理了字符集协商,Agent 这种无人值守进程反而容易暴露。
7. 经验收尾:关于内网 Agent 长期稳定运行的几件小事
部署完成、验证通过只是开始。Agent 真正考验人的地方,是它要没日没夜地跑在内网环境里,承担监控和连接通道的职责。我长期运维下来,有几件小事非常想分享。
第一,配置文件必须纳入版本管理。内网环境普遍有变更审批流程,改一次配置成本不低。如果把 agent.yaml、systemd unit、agent.env 的模板都纳入 Git 管理,出问题时可以快速 diff,看清楚上次能正常运行时的配置到底改了什么。这个习惯帮我省掉了太多次半夜救火的痛苦。
第二,日志轮转一定要配置。很多 Agent 默认输出到一个日志文件,不轮转的话,运行一个月就可能把磁盘写满。用 logrotate 或者 systemd 自带的机制都可以。关键是提前配好,别等磁盘告警再补救。
第三,给 Agent 加一个独立的健康检查。最简单的做法是在内网调度机或监控机上写一个脚本,定期抓取 Agent 的指标端点,连续失败三次就告警。这样 Agent 本身的故障不会等到用户反馈才发现。
第四,升级 TiDB 集群前,先查一遍 Agent 兼容矩阵。不要在集群升级后才发现 Agent 版本不配合,导致监控数据断流,这种问题在内网环境下特别难快速解决,因为离线包准备和审批流程都很耗时。同批升级,风险最可控。
我在内网环境部署过太多次 TiDB 周边组件,最大的感受是:内网配置本身没有特别深的技术难点,真正的难点在于做任何操作之前把依赖、端口、权限、时间、DNS 这些细节点全部想到前头。只要能提前把网络放行单列全、把物料备齐、把配置文件逐项理解透,内网里的 Agent 完全可以做到一次部署、长期稳定运行。希望这篇基于实际踩坑经验写下的内容,能让你少走几趟弯路。