最近帮一个团队交付一套完全隔离的数据库集群网络环境很严格除了 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 等sha256sumnode_exporter 二进制主机指标采集sha256sumAgent 可执行文件与默认配置本次部署的核心组件sha256sumJDK 或目标运行时如果 Agent 是 Java 系组件必须带离线 JDKsha256summysql 客户端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] nameLocal Repository baseurlhttp://repo-server/local-rpms enabled1 gpgcheck0这里要注意内网源必须以gpgcheck0或者准备好对应的签名密钥否则 yum 会因为公钥缺失拒绝使用。很多刚进内网环境的朋友在这里第一次踩坑进度直接卡住。2.3 Agent 访问 TiDB 各端口的关系核对表物料就绪之后别急着装。先拿出一张纸把“谁要访问谁”列清楚。我把 TiDB 生态中最常涉及的端口整理成一张表你可以直接抄作业端口对应组件说明4000TiDB ServerSQL 协议入口Agent 执行 SQL 验证时必用10080TiDB Server 状态端口提供 metrics 和 pprof 端点2379PD Client获取集群调度信息、读写路由信息2380PD PeerPD 集群内部通信Agent 一般不直接访问20160TiKV实际数据读写端口20180TiKV 状态端口暴露 TiKV 监控指标Prometheus 直接抓取9090Prometheus如果使用远程写入Agent 需要访问该端口9100node_exporter 默认端口监控抓取目标最容易犯的错就是只给 Agent 放通 4000 端口。你以为能连上数据库了实际数据请求会卡在 TiKV 那一步报错信息又非常隐蔽只会看到超时。我在 2.3 节里先把这个表抛出来是希望你在提交防火墙申请之前就按整条链路的端口一次性列全别让流程来回折腾。3. 配置文件逐项拆解让 Agent 在内网正确认到 TiDB3.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.log3.2 最容易写错的核心字段listen、endpoints、intervallisten为什么要写成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 agent10.20.% IDENTIFIED BY 你的密码; GRANT PROCESS, SELECT ON *.* TO agent10.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] DescriptionTiDB Agent Service Afternetwork-online.target Wantsnetwork-online.target [Service] Typesimple Usertidb Grouptidb EnvironmentFile/etc/tidb-agent/agent.env ExecStart/opt/tidb-agent/bin/agent --config /etc/tidb-agent/agent.yaml WorkingDirectory/opt/tidb-agent Restartalways RestartSec10 LimitNOFILE1048576 LimitNPROC65536 NoNewPrivilegestrue PrivateTmptrue [Install] WantedBymulti-user.target这个文件里的几个字段每一个都不是随手加的。Usertidb意味着 Agent 以非 root 身份运行。数据库相关组件如果以 root 跑一旦进程被利用就直接拿到系统管理员权限内网环境里这是绝对不能接受的。提前用useradd -r -s /sbin/nologin tidb建一个专用系统账号然后把 Agent 的目录属主改成它。Restartalways配合RestartSec10是内网无人值守场景的核心。Agent 进程崩溃后10 秒内自动拉起。没有这行凌晨三点 Agent 挂了第二天上班监控数据一整夜都是空的。LimitNOFILE1048576是针对 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直接看文件最好用 journaldjournalctl -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两边一对接中文字段就乱码了。排查时先看连接串里是否带了characterEncodingutf8mb4没有就加上。这个问题在内网里容易被人忽略因为开发环境大家用的是图形化客户端通常自动帮你处理了字符集协商Agent 这种无人值守进程反而容易暴露。7. 经验收尾关于内网 Agent 长期稳定运行的几件小事部署完成、验证通过只是开始。Agent 真正考验人的地方是它要没日没夜地跑在内网环境里承担监控和连接通道的职责。我长期运维下来有几件小事非常想分享。第一配置文件必须纳入版本管理。内网环境普遍有变更审批流程改一次配置成本不低。如果把 agent.yaml、systemd unit、agent.env 的模板都纳入 Git 管理出问题时可以快速 diff看清楚上次能正常运行时的配置到底改了什么。这个习惯帮我省掉了太多次半夜救火的痛苦。第二日志轮转一定要配置。很多 Agent 默认输出到一个日志文件不轮转的话运行一个月就可能把磁盘写满。用 logrotate 或者 systemd 自带的机制都可以。关键是提前配好别等磁盘告警再补救。第三给 Agent 加一个独立的健康检查。最简单的做法是在内网调度机或监控机上写一个脚本定期抓取 Agent 的指标端点连续失败三次就告警。这样 Agent 本身的故障不会等到用户反馈才发现。第四升级 TiDB 集群前先查一遍 Agent 兼容矩阵。不要在集群升级后才发现 Agent 版本不配合导致监控数据断流这种问题在内网环境下特别难快速解决因为离线包准备和审批流程都很耗时。同批升级风险最可控。我在内网环境部署过太多次 TiDB 周边组件最大的感受是内网配置本身没有特别深的技术难点真正的难点在于做任何操作之前把依赖、端口、权限、时间、DNS 这些细节点全部想到前头。只要能提前把网络放行单列全、把物料备齐、把配置文件逐项理解透内网里的 Agent 完全可以做到一次部署、长期稳定运行。希望这篇基于实际踩坑经验写下的内容能让你少走几趟弯路。
