☰
MySQL远程监控实践:mysql_exporter+Prometheus+Grafana+cpolar内网穿透
2026/10/22 13:32:31 网站建设 项目流程

MySQL 要远程盯着看,这事儿听起来常规,真正落地时全是细节。数据库不会只待在办公室旁边,它可能跑在公司内网、家里机房或者云上的隔离网段;你人也总有不坐在电脑前的时刻。到了外面想确认连接数是不是快满了、慢查询有没有突然暴涨、主从延迟还正不正常,总不能每次都用手机爬回内网再去查。我这次把整套链路从头到尾过了一遍:mysql_exporter 负责把 MySQL 的运行状态抽出来,Prometheus 存储、Grafana 出看板,最后用 cpolar 做内网穿透,让公网设备能直接打开监控面板。实测下来页面加载很顺,拖时间轴、刷图表基本不掉链子。这篇就把选型思路、部署步骤、隧道配置和踩坑记录完整写出来,适合正在做 MySQL 运维、又希望在外网随时掌握实例状态的人直接参考。

1. 这个需求是怎么冒出来的:远程盯 MySQL 到底难在哪

1.1 本地监控是常态,远程才是真痛点

先说说我为什么会被这个问题卡住。MySQL 实例平时待在机房里,你在办公室的局域网内想连就连,SSH 上去跑几条命令、开个本地监控面板,一点问题没有。但人一旦离开内网环境——出差、回家、去客户现场——事情就变了。最常见的状态是“等业务先报障,然后运维再上去查”。数据库响应变慢、连接数满了、主从延迟拉高,往往是前端先炸了,运营人员跑来反馈,你才打开监控看看发生了什么。这种模式说白了是被动救火,不是在监控。

所以真正靠谱的思路是主动监控:把连接数、QPS、慢查询、锁等待、主从复制延迟这类关键指标持续采集下来,画成曲线,再设定阈值。数据库还没出事,曲线就已经开始示警了。问题在于,大部分监控方案默认只在局域网内展示,内网里看板很正常,离开内网就两眼一抹黑。你可以高高兴兴地在办公室打开 Grafana,但出差在外连不上,那这套监控的“远程”价值就消失了。

远程监控的痛点本质上有两件事:一是要有稳定、低侵入的指标采集端,二是要有一条安全可靠的通路,让公网设备能访问到内网里的监控面板。前者我用 mysql_exporter 解决,后者用 cpolar 这类内网穿透工具解决。两个合起来,才算真正把远程监控打通。

1.2 方案选型对比:为什么是 mysql_exporter + cpolar 这条链路

在定下这套组合之前,我其实把市面上常见的几种远程访问方式都梳理了一遍,也实际踩过一些坑。这里直接列个对比表,省得大家再走弯路:

方案优点真正的痛点
公网直连 3306配置最简单,远程工具填 IP 就能连数据库直接暴露公网,暴力破解、漏洞扫描随时可能找上门,风险极高
SSH 隧道转发加密链路,安全性不错需要一台带公网 IP 的跳板机,多实例管理麻烦,非技术同事基本不会用
自建 frp 服务端完全自控,能力上限高要自己买公网服务器、维护服务端,成本稳定性都得自己兜着
cpolar 内网穿透不需要公网服务器,几分钟建好隧道,只暴露指定端口免费隧道地址不固定,需要自己补上访问鉴权

我最终选 mysql_exporter + Prometheus + Grafana + cpolar,核心原因是它的“暴露面”最小。mysql_exporter 只通过 MySQL 的监控协议去读取状态,数据库本身的 3306 端口完全不用暴露到公网;cpolar 只转发 Grafana 面板所在端口,公网用户能看到的只是一个登录页和图表。也就是说,潜在攻击者就算扫描到了隧道地址,他面对的也只是 Grafana 的登录框,连接不到数据库本身。

这套组合还有一个好处是分层清晰,每一层都能独立替换。采集端不合适可以换 exporter,存储太重可以换时序库,面板不顺手可以换可视化工具,内网穿透工具也不绑定死。对于个人项目和中小团队来说,这种松耦合结构是最省心的。

2. mysql_exporter 部署:先把数据库的“体检数据”抽出来

2.1 给 MySQL 建一个“只读体检账号”

mysql_exporter 本质上是替 Prometheus 定期询问 MySQL:“你现在状态怎么样?”为了让这个“询问者”不乱动任何业务数据,第一步就是建一个权限最小的只读账号。我习惯命名为 exporter,密码用独立强密码,绝不和业务账号混用,也不放进代码仓库。

在 MySQL 里执行:

CREATE USER 'exporter'@'localhost' IDENTIFIED BY '这里填强密码'; GRANT PROCESS, REPLICATION CLIENT, SELECT ON *.* TO 'exporter'@'localhost'; ALTER USER 'exporter'@'localhost' WITH MAX_USER_CONNECTIONS 3; FLUSH PRIVILEGES;

逐个解释这三个权限的用途:

  • SELECT:允许读取information_schema和performance_schema中的性能表,这是 exporter 取监控数据的主要来源。
  • PROCESS:允许查看线程状态,对应SHOW PROCESSLIST,有了它才能看到长事务和锁等待。
  • REPLICATION CLIENT:允许查询主从复制状态,比如SHOW SLAVE STATUS,主从延迟监控靠的就是这个权限。

WITH MAX_USER_CONNECTIONS 3是我强烈建议加的。监控账号理论上并发连接数很少,限制它最多同时建立 3 个连接,可以防止 exporter 异常重试时把 MySQL 的连接池占掉。身边真有人踩过这个坑:监控脚本没写超时时间,半夜重试上百次,直接把 MySQL 打挂了。

如果 MySQL 和 exporter 不在同一台机器,'localhost'要改成 exporter 所在机器的内网 IP,或者用'exporter'@'192.168.1.%'这种网段写法。不过安全起见,exporter 最好就部署在数据库同机或同内网,没必要为了“省一台机器”去跨网段访问。

2.2 安装并启动 mysqld_exporter

exporter 的二进制在官方仓库直接能拿到,按 Linux 架构选对应版本下载解压到/opt/mysqld_exporter就行。我这边的习惯是不用包管理器装,版本可控,升级方便。

连接信息不建议用DATA_SOURCE_NAME环境变量直接传,因为进程列表里一眼就能看到密码。更稳妥的做法是把连接信息写进配置文件,文件权限设置为仅 root 可读:

[client] user=exporter password=这里填强密码 host=127.0.0.1 port=3306

把文件放到/etc/mysql_exporter/.my.cnf,然后启动:

chmod 600 /etc/mysql_exporter/.my.cnf ./mysqld_exporter --config.my-cnf=/etc/mysql_exporter/.my.cnf --web.listen-address=0.0.0.0:9104

这里有个问题值得解释:exporter 监听地址为什么要用0.0.0.0:9104而不是127.0.0.1:9104?如果 Prometheus 和 exporter 在同一台机器上,用127.0.0.1更安全;但如果 Prometheus 部署在另一台机器,就必须监听在机器网卡能访问到的地址上。我通常把 Prometheus 也放在同一台服务器里,用0.0.0.0只是图方便,反正这台机器本身不对外暴露端口,没额外增加风险。

启动后先验证一下:

curl -s http://127.0.0.1:9104/metrics | grep mysql_global_status_threads_connected

能输出一行类似mysql_global_status_threads_connected 15的内容,说明采集通路已经打通。为了让重启不麻烦,我建议写成 systemd 服务,Restart=on-failure和KeepAlive都配上。监控端不该掉线,谁都不想因为 exporter 挂了而“盲监”。

2.3 哪些指标值得重点盯

exporter 输出的指标有成百上千个,但日常运维不需要全盯,盯多了反而眼花。我结合自己的使用习惯,整理了一份核心指标清单:

指标含义为什么值得关注
mysql_global_status_threads_connected当前连接数一旦接近max_connections,新连接就会被拒绝
mysql_global_status_queries累计查询数配合时间差可以算出 QPS
mysql_global_status_slow_queries慢查询累计次数曲线突然上跳,说明有 SQL 或锁在拖后腿
mysql_global_status_uptime实例运行秒数突然归零说明 MySQL 重启过,要追查原因
mysql_slave_status_seconds_behind_master主从延迟秒数从库落后面太大,读流量会读到过期数据

有个容易忽略的点:exporter 默认采集已经覆盖了这些核心指标,不用额外手动执行SHOW命令。后面 Prometheus 的抓取频率配置好就行,不需要在系统里再挂 crontab 去 curl 指标,那是重复劳动。

3. Prometheus + Grafana:让指标变成能看的看板

3.1 Prometheus 拉取配置

Prometheus 在这里扮演的角色是“定时问 exporter 要数据,然后把数据存成时间序列”。核心配置在prometheus.yml,加一个 job:

scrape_configs: - job_name: 'mysql' scrape_interval: 15s static_configs: - targets: - '127.0.0.1:9104' labels: instance: 'db-server-01'

如果有多台 MySQL,就把 targets 列出多个,再用instance标签区分实例。关于scrape_interval,我实测下来 15 秒已经足够捕捉绝大多数问题。没必要图省事改成 5 秒甚至 1 秒,因为每次抓取都会让 exporter 查一堆状态表,频率太密对数据库有额外开销,而数据库的监控指标也没有那么多秒级瞬变需要盯着。要知道,监控看的是趋势和异常拐点,不是每秒钟的精确值。

Prometheus 启动后,在http://127.0.0.1:9090/targets页面能看到这个 job 的状态。状态为UP且scrape duration稳定,说明指标采集链路已经通了。

3.2 Grafana 看板导入与常用面板

Grafana 的价值是把机器可读的指标变成一眼能看懂的图。装好之后先加数据源:地址填http://127.0.0.1:9090,类型选 Prometheus。这一步没什么坑,只要保证网络能通。

然后导入现成的 MySQL 看板模板。社区有不少高质量的 MySQL Overview 模板,基本都是基于 mysqld_exporter 的指标命名规则写的,导入之后几乎不用改。我在 Grafana 模板库里搜 “MySQL Overview”,挑了一个下载量高的导入。导入步骤很简单:登录 Grafana,进 Dashboards -> Import,输入模板 ID,Load 之后选好数据源,确认导入就行。

不过我的建议是不要贪多。模板里通常会有连接数、QPS、慢查询、缓冲池命中率、主从复制状态等一堆面板。远程访问场景下,面板越多加载越慢,反而干扰判断。我通常只保留三块核心区域:连接与线程、查询性能、复制状态。面板越精简,远程打开越快,也越容易一眼发现异常。

3.3 远程场景下看板怎么读

到了远程场景,看板的价值才真正体现出来。在外网打开 Grafana 之后,我一般是按这个顺序扫:

  • 先看连接数曲线:长期在高位,比如超过max_connections的 70%,说明连接池要满了,要考虑调大参数或优化应用连接释放。
  • 再看 QPS 曲线:突然翻倍,要么是业务高峰,要么是有人在跑大查询或者全表扫描。
  • 然后看慢查询:如果慢查询数和 QPS 同步上升,基本可以判定是 SQL 性能问题,需要抓慢日志分析。
  • 最后看一眼主从延迟:数值持续增大而不是归零,需要检查从库磁盘状态或复制线程是否中断。

这里我特别想强调告警的作用。Prometheus 的 Alertmanager 或 Grafana 内置告警都行,把连接数超过阈值、延迟超过 30 秒之类的事件推到钉钉或企业微信。配置不复杂,但收益非常直接:数据库开始“不舒服”的瞬间,你手机上就能收到提醒,而不是等业务喊你时才去打开面板。监控的真正价值,恰恰是给你留出这段提前量。

4. cpolar 内网穿透接入:把内网看板“带到”公网

4.1 cpolar 的工作原理

先讲清楚 cpolar 这类内网穿透工具到底干了什么。正常情况下,公网设备无法直接访问内网地址,因为内网 IP 不在公网路由表里。cpolar 的做法是让本机运行一个客户端,客户端主动向外部的云端节点发起一条长连接,云端节点拿到连接后分配一个公网地址。公网用户访问这个地址时,请求会被云端节点通过长连接隧道转发到本地指定端口。

这个方向很重要:因为是客户端主动连出去,所以它不要求你家里或公司宽带具备公网 IP。你不需要去运营商那里要公网地址,也不需要折腾路由器端口映射。打个比方,内网里的 Grafana 就像一栋没有临街入口的屋子里的人,cpolar 客户端是他在窗口摆的一部对讲机,云端节点是楼下的前台。外来的访客按下前台对应的频道,前台通过对讲机喊话,屋里的人应答并回应,整个过程不需要这栋楼真的开一扇临街大门。

这个设计对监控场景特别友好:3306 完全不用碰,公网隧道只指向 3000 端口。数据库本身对外不可见,你在公网能访问到的仅仅是一个经过登录认证的 Grafana 页面,威胁面一下小了很多。

4.2 安装与创建隧道

安装 cpolar 客户端后,先在官网注册账号,拿到认证令牌并绑定到客户端。绑定完成后创建隧道就只是几分钟的事。我常用的方式是用命令行:

cpolar authtoken 你的认证令牌 cpolar http 3000

http 3000的意思是建一条 HTTP 隧道,把公网流量转发到本机 3000 端口,也就是 Grafana 的默认监听端口。命令行跑起来之后会返回一个公网地址,类似https://xxxx.cpolar.top,在浏览器打开就是 Grafana 登录页。

如果你更习惯图形界面,cpolar 的管理后台也可以建隧道:名称随意,协议选 http,本地地址填127.0.0.1,端口填3000,保存后会自动生成公网地址。

这里有一个建议:如果希望访问地址固定下来,最好在 cpolar 后台开通固定二级域名并绑定到这条隧道。监控场景下这是刚需。免费随机地址每次重启都会变,你总不能每次想看数据库状态都先翻一遍客户端日志找新地址。固定域名绑定后,隧道基本是稳定的,日常用起来和访问一个普通网站没有区别。

4.3 为什么这样搭不容易卡

很多朋友一听到内网穿透,第一反应是“外面访问肯定卡”。实测下来,在监控面板这个场景里,影响远没有想象中那么大。原因是 Grafana 拉取的数据本身就很轻量:面板页面、若干 JSON、一些小图标,单次图表查询通常只有几十到几百 KB,不是视频流也不是大文件下载,对带宽要求很低。

再加上 Grafana 对 Prometheus 的查询结果有缓存,时间范围不变时重复查询会直接命中缓存;图表加载是异步的,首屏出现之后其他面板慢慢补,观感就是“随点随开”。真正让面板变慢的,往往是手机信号本身差,或者首次加载时把所有不常用的面板全部拉了一遍。后面第 5 章会专门说怎么把这些多余请求压掉。

5. 安全加固与调优:远程监控不能只看“通不通”

5.1 三层防护:数据库、监控链路、公网入口

远程监控最忌讳的心态就是“能通就行”。我把这条链路拆成了三层,每一层都做了限制,缺一层我都觉得不踏实。

第一层,MySQL 账号层。exporter 账号只有 SELECT、PROCESS、REPLICATION CLIENT 三个权限,还限制了最大连接数。它无法修改任何数据,无法执行 DDL,更不可能删除任何表。就算攻击者拿到这个账号的密码,他能看到的也只有性能相关的视图,破坏力极其有限。

第二层,网络路径层。3306 端口只监听内网,公网无法直连数据库。exporter 的 9104 端口也只在内网被 Prometheus 抓取。公网唯一能触达的是 cpolar 隧道指向的 3000 端口,也就是 Grafana。

第三层,应用与隧道层。Grafana 有登录认证,不能保持默认的 admin/admin;cpolar 隧道也建议开启访问鉴权,在入口再挡一道账号密码。就算公网地址被人扫到,对方面对的也只是一个登录页,没有凭证什么都做不了。

三层各管一段,任何一层被突破,攻击者都拿不到完整的数据库权限。这就是纵深防御的朴素形态。

5.2 防爆破与访问控制

公网地址一旦公布出去,被扫描只是时间问题。Grafana 默认页面有清晰的登录框,恶意请求一定回来试弱口令。在正式环境里,我会做这几件事:

  • 把 Grafana 的 admin 账号改名,或至少把密码换成足够长的随机串;
  • 创建独立的只读账号供日常查看面板使用;
  • 在 cpolar 后台开启 Basic Auth ,让隧道入口再挡一层;
  • 关闭 Grafana 的匿名访问,绝对不开启“匿名只看图”模式。

有人可能觉得“一个监控面板,谁会来搞我”。但你想想:攻击者一旦进了 Grafana,不仅能看你的连接数、QPS、主从状态,还能看到数据源配置,知道自己下一步可以探测哪些内网地址。信息暴露本身就是风险。多设一层认证成本很低,不要把数据库的暴露风险寄托在“没人发现我”上面。

5.3 开销控制与性能调优

监控链路本身的开销其实很小。exporter 每次抓取相当于跑几次SHOW STATUS和查几张performance_schema表,对 MySQL 的影响基本可以忽略。Prometheus 存时间序列占的是磁盘和内存,实例少时完全不是负担。

真正需要调优的是远程加载 Grafana 的体验。我实测有效的几个手段:

  • 面板默认刷新间隔从“自动”改成 1 分钟或手动刷新,避免多人同时挂着自动刷新页面,白白占用查询资源。
  • 在 Grafana 里关掉不重要的大面板,只保留核心几个。
  • 手机访问时直接打开具体 dashboard,不要停在首页导航,首页加载的小组件最多。
  • cpolar 隧道尽可能选支持 HTTPS 的节点,避免监控数据明文传输。
  • 多人同时使用,合理分配查看权限,不要所有人共用同一个管理员账号。

这些操作做完后,远程看板的体验基本就是“打开就出图、拖动时间范围稍微等一下而已”。配合第 4 章说的缓存机制,“不卡壳”不是一句口号。

6. 踩坑日志:这些问题我替你先踩了

6.1 问题一:exporter 起来了,指标却全是 0

症状:9104端口有响应,mysql_up是 1,但mysql_global_status_threads_connected这类指标全是 0。我第一反应是查 exporter 日志,发现它在执行权限相关查询时反复报错。

根源基本就是权限没给全。很多教程只让你给 SELECT,忽略了 PROCESS 和 REPLICATION CLIENT,结果 exporter 需要查线程状态和复制状态的时候权限不够,查询失败后只能静默返回空值。处理方式很简单:把 2.1 那三个权限完整授予一遍,FLUSH PRIVILEGES,重启 exporter。如果还不行,用命令行手工验证账号能否正常执行SHOW GLOBAL STATUS和SHOW SLAVE STATUS。这一步原地排查,很快就能定位。

6.2 问题二:隧道 online,公网却 502

cpolar 显示隧道在线,公网打开却 502。这个问题的排查顺序很固定:先本地确认服务是否活着,再确认端口映射对不对。

我在容器环境里踩过一次:Grafana 跑在容器里,端口映射成127.0.0.1:3000:3000,cpolar 隧道指向本机 3000 端口,看起来没问题。但问题在于 cpolar 客户端跑在另一个容器里,它访问的127.0.0.1是它自己所在的容器,并不是 Grafana 所在容器,自然就 502 了。把端口映射改成0.0.0.0:3000:3000,或者让 cpolar 客户端和 Grafana 跑在同一个容器网络里,问题迎刃而解。

6.3 问题三:换了访问地址,Grafana 图表全断

远程面板能打开,但图表区域一大片connection refused。查了一下,是 Grafana 数据源里 Prometheus 地址写成了127.0.0.1:9090。这个地址在 Grafana 所在机器内访问没问题,但图表请求是由浏览器直接发出的。浏览器在你的电脑上,它拿到127.0.0.1自然找不到任何 Prometheus。

解决办法是把数据源地址改成 Prometheus 所在机器的内网 IP,比如http://192.168.1.10:9090,或者在 Grafana 配置里用相对路径。改完之后重载一下页面,图表就恢复了。这个坑很典型,几乎每套远程化方案里都会遇到一次。

6.4 问题四:手机流量下看面板时快时慢

同一块面板,在 WiFi 下很流畅,换成 4G/5G 就偶尔打不开。我观察下来,问题通常不在隧道链路本身,而在 Grafana 首次加载时拉取大量静态资源:JS、CSS、字体文件。手机网络抖动时这些资源加载就会变慢。

我的处理方式是给面板“减负”:核心 dashboard 只保留少数图表;调长 Grafana 的静态资源缓存;在 cpolar 后台确认开启数据压缩。另外,手机访问时尽量直接打开具体 dashboard,不要每次都从首页导航进去。做了这些之后,即便在信号一般的环境,打开面板的耗时也在可接受范围内。

最后再分享一点自己的体会。这套 mysql_exporter + cpolar 的远程监控组合,真正的价值不只是“在外面能看到面板”,而是让你从被动救火变成主动发现。数据库指标曲线出现异常和业务真正报障之间,通常隔着一段时间窗口,这正是监控能给你的操作空间。安全底线一定别省:最小权限账号、Grafana 强制登录、隧道访问认证,三层防护缺一不可。跑一段时间之后你会发现,你需要做的不是天天盯着面板发呆,而是把告警配好,然后该干嘛干嘛去。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询