做矿场运维这行,时间越久越觉得,真正让人头疼的往往不是矿机本身,而是管理矿机的那套工具。商业面板按月付费、按卡收费,功能看似齐全,可真要接入自己写的告警、自己想做的自动恢复策略,就会发现处处都是墙。所以我用了大概三周时间,用开源组件从零搭了一套完全攥在自己手里的矿机管理系统,代号就叫 openrig。这篇文章会把整体设计、技术选型、核心功能实现和部署细节都摊开讲,适合小中型矿场、多机架玩家,也适合想摆脱商业面板锁定的运维团队参考。
1. OpenRig 是什么:从需求倒推出来的设计
1.1 商业矿池面板的四个痛点
先说说我为什么放着现成的商业面板不用,非要自己折腾。
第一是费用和规模的矛盾。商业面板大多按矿机数量或者显卡数量阶梯计价,机子少的时候看着不贵,机架一多,每个月就是一笔固定开销。更难受的是,有些功能比如自定义策略、开放 API,都被放在更高的付费档位里,等于你想省事反而要被多收钱。
第二是数据不透明。面板上显示的温度、算力、拒绝率,很多是经过厂商处理的,你看不到原始采样数据。一旦想针对某张卡做精细分析,比如显存温度震荡、功耗曲线异常,商业面板往往不给原始数据导出,逼着你另外写采集脚本。
第三是策略被锁死。自动重启、温度预警、算法切换,这些功能都依赖厂商预设的模板。想加一条“显存温度连续十分钟超过 96 度就先降频再重启”的规则?可以,要么加钱,要么等版本更新。最要命的是,有些面板的自动逻辑是黑盒,你不知道它什么时候重启了矿机,也不知道为什么。
第四是闭源风险。面板本身不开源,一旦厂商调整协议、关闭服务,或者现场环境需要离线运行,整个机架的管理就会立刻失效。
1.2 OpenRig 的定位与设计目标
我想要的系统其实很简单:自托管、全开源、可离线运行,并且在协议层完全开放。它不是一个大而全的商业产品,更像是一个“矿机管理框架”,我把底下所有模块都做成了可以独立替换的组件。
初始设计目标定得很明确:新矿机接入不超过 5 分钟,断网后矿机端仍然能按最后策略运行,故障后可以在 30 秒内自动重启挖矿进程,并且所有采集指标全部落到自己的数据库里。这几条听起来不复杂,但真正实现起来,每一步都有不少细节要抠。
2. 系统架构与关键技术选型
2.1 整体架构:采集、汇聚、控制三层
OpenRig 在架构上分成三个清晰的层次:采集层、汇聚层、控制层。
采集层跑在每一台矿机上,是一个轻量级 Agent 进程。它的职责是轮询本机挖矿内核暴露的 API 接口,把温度、功耗、算力、拒绝率等指标读出来,然后标准化成统一格式上报。Agent 同时负责接收控制指令,比如重启内核、切换算法、调整风扇转速。
汇聚层是服务端集群,由消息中间件、后端 API、数据库和前端面板组成。消息中间件负责接收海量的指标数据,后端 API 做指令下发和业务逻辑处理,数据库存时序指标和配置,前端面板负责展示和操作。
控制层实际上就是后端 API 加规则引擎。它根据采集上来的指标,结合你预设的阈值和策略,决定是否下发控制指令。这个分层的好处是:哪怕后端 API 挂了,矿机端的 Agent 依然能按照本地缓存策略继续跑,不会因为服务端故障导致算力中断。
在实际部署里,我用这几样组件来承载对应职责:
- EMQX 作为 MQTT Broker,负责采集数据的接入和指令下发。
- Go 写的后端服务,负责 API、规则引擎、任务调度。
- TimescaleDB 存储时序指标,PostgreSQL 的生态也可以直接用。
- Redis 做短时的状态缓存和分布式锁。
- React 加 TypeScript 写前端控制台。
- 矿机端 Agent 用 Python 写成,方便快速迭代,后续也可以换成编译型语言。
2.2 为什么要用 MQTT 来传监控数据
很多朋友问我,监控数据用 HTTP 轮询不就行了?确实可以,但矿场这个场景有其特殊性:单机几十张卡,指标每 5 秒采集一次,一次上报的数据量非常小,但数量很大。如果每台矿机都用 HTTP 不停地打接口,连接建立的额外开销和负载就上来了。
MQTT 的优势在于它本身就是为大量低频消息设计的。矿机 Agent 与 Broker 保持长连接,上报数据就是一个很小的 PUBLISH 消息,没有 HTTP 头这些冗余。而且 MQTT 的 Last Will 机制特别适合矿场监控:矿机异常断电时,Broker 能立刻感知连接断开,推送离线事件,比“因为没数据所以判断离线”要快太多。
最重要的是,MQTT 天然支持一个 Topic 树结构。我可以把每台矿机的数据按rigs/{rig_id}/metrics这样的路径组织,控制指令走另一个rigs/{rig_id}/control方向,前端订阅特定 Topic 就能实时看到数据变化,不需要后端额外做长连接推送。
2.3 数据模型:一台矿机一张“体检表”
设计数据模型时,我没有把矿机指标单纯看成一串数字,而是当成一张动态更新的“体检表”。
每台矿机有一份静态配置表,记录矿机 ID、Agent 版本、所在机架、控制端口、对应的挖矿模板。动态指标单独存时序表,包括采集时间、GPU 索引、核心温度、显存温度、核心频率、显存频率、功耗、算力、效率等字段。这样静态配置和动态数据分离,查询历史趋势时只需要扫时序表,效率高很多。
设备状态我划分为三种:在线、关联路径缺失、离线。在线是指 Agent 持续上报心跳;关联路径缺失是指 Agent 在线但挖矿内核 API 无响应,常见于内核崩溃;离线就是 MQTT 连接断开。这个划分很重要,因为很多故障其实发生在矿机没宕机、只是挖矿进程挂了的场景。
2.4 安全边界设计
自托管系统最容易被忽视的就是安全。OpenRig 的安全边界我做了三层。
第一层是网络隔离。服务端只暴露必要端口,后端 API 在用反向代理前加上 HTTPS,矿机 Agent 和 Broker 之间通过网络策略限制,禁止矿机直接访问数据库。
第二层是认证。Agent 连接 Broker 时使用独立账号密码,后端签发短期 Token 给控制台登录使用。所有控制指令都要求携带 Agent 端的随机挑战码,防止中间人伪造重启指令。
第三层是操作审计。每一次重启、切换算法、改配置的操作都会追加到审计日志表里,我可以在面板上随时查到是谁在什么时间对哪台矿机做了什么操作。
3. 核心功能拆解与实现细节
3.1 矿机接入与自动注册
矿机接入流程的目标是“零手工运维”。我给每台新矿机准备了一个一次性注册码,在服务器后台生成一个码,贴到矿机配置里。Agent 启动后先带着这个码去请求注册接口,服务端验证通过后,给这台矿机分配正式 ID 和 Token。
注册完成之后,Agent 立刻从服务端拉取该矿机对应的挖矿模板。模板里包含挖矿内核路径、矿池地址、钱包地址、超频参数这些信息。也就是说,矿机本身不需要预装任何挖矿配置,重装系统之后只要装上 Agent、填上注册码,一切环境都由服务端下推。
这一步省掉了很多重复劳动。以前每台机器我都要手动编辑配置文件、核对矿池地址,还经常出现钱包地址填错导致算力白跑的情况。现在注册即配好,错了也能在面板上一键修正。
3.2 指标采集:算力、温度、功耗、拒绝率
指标采集是 OpenRig 最重要的基础能力。不同型号的挖矿内核 API 返回格式不一样,所以 Agent 里做了解析器层,每种内核对应一个解析器,统一输出标准化字段。
以常见的矿机程序为例,它的本地 API 端口返回 JSON 格式,包括每张卡的当前算力、核心温度、功耗。Agent 轮询的频率我设成 5 秒一次,这个频率足够捕捉温度陡升,又不会给内核 API 造成太大压力。
采集到数据后,Agent 会先做一层轻量处理:过滤掉明显异常的值,比如 -1 度这样的占位符;计算最近一分钟的平均算力;再把这些处理后的数据打包成一条消息,通过 MQTT 上报。这样做的好处是,服务端拿到的数据已经是相对平滑的指标,画出来的趋势图不会到处是毛刺。
功耗这一项很多新手会忽略。对家用电源来说,整机功耗和单卡功耗的换算经常让人对不上账。OpenRig 里我记录的是内核程序报的单卡功耗,同时 Agent 也通过读取系统功耗传感器记录整机功耗,两套数据分开存,这样哪张卡异常耗电一眼就能从面板上看出来。
3.3 告警、熔断与自动恢复机制
告警和自恢复是我最看重的一部分,也是和商业面板差距最大的地方。
在 OpenRig 里,规则引擎支持这样几条典型的故障规则:
- 核心温度超过 95 度,持续 2 分钟,触发高温告警。
- 显存温度超过 100 度,持续 3 分钟,触发降频指令。
- 算力低于理论值的 80%,持续 5 分钟,触发挖矿进程重启。
- MQTT 连接断开,5 秒内触发离线通知。
- 内核 API 无响应,30 秒内触发全机断电重启。
这些规则都配置在服务端,Agent 本地也会缓存一份简化版本。即使服务端不可用,Agent 也能根据本地缓存的阈值做基本的自我保护,比如温度过高时直接重启内核,不需要等服务端下发指令。
自动重启策略我做成了分级处理:先尝试通过内核 API 软重启,比如发送重启指令;软重启失败就由 Agent 直接结束挖矿进程再拉起;还不行就重启整台机器。这个分级策略避免了“一有小问题就把机器重启一遍”的粗暴做法,毕竟频繁冷重启对硬件寿命是有影响的。
3.4 算法切换与利润调度
OpenRig 的算法切换逻辑,本质上是“按外部收益指标变化,选择当前最优挖矿算法”。这个功能和商业面板里的自动切换类似,但我做成了完全可控的调度器。
调度器定时去读取第三方利润热度接口,拿到不同算法当前的单位算力收益排名。然后结合矿机显卡型号和当前功耗,算出一个预估的每瓦收益。如果新算法比当前算法的预估收益高出一定比例,并且持续了一段时间,才触发切换。
为了安全,切换前系统会先拉取新模板,检查模板可用性,然后把新旧算法跑一个短时间的并发对比。对比结束后根据实际收益决定是否切换。这个机制能有效避免因为接口数据抖动导致矿机频繁切换,超频参数也因此在每个模板里独立管理。
4. 实操:从零部署一套 OpenRig
4.1 服务端快速部署
服务端我用 Docker Compose 编排,所有组件打包成容器,部署时只需要在服务器上执行几条命令。
git clone https://your-git-host/openrig/deploy.git cd deploy cp .env.example .env # 编辑 .env,配置数据库密码、JWT 密钥等 docker compose up -d如果你没有现成的 Git 仓库,也可以把整份部署目录直接拷到服务器上。服务端首次启动后需要初始化数据库:
docker compose exec api openrig-admin init-db docker compose exec api openrig-admin create-admin --username admin --password 你的密码这样一个最小可用的服务端就跑起来了。对于机柜数量不超过 30 台的小型矿场,单台 4 核 8G 的服务器已经完全够用。指标数据默认保留 30 天,可以根据磁盘空间调整保留周期。
4.2 Agent 端安装与注册
Agent 端安装我写成了一个脚本,系统里只需有 Python 3.9 以上版本即可。
curl -fsSL http://your-server/static/install_agent.sh | bash脚本会完成这几个动作:下载 Agent 程序、创建系统服务、生成配置文件框架。接下来只需要编辑配置文件:
[server] endpoint = your-server:8883 company_code = your_company [rig] register_code = xxxx-xxxx-xxxx network_timeout = 30保存后启动服务,再看服务端面板,这台矿机就会出现在“待审批”列表里。审批通过后,Agent 会从那台服务器拉取挖矿模板,整个过程不需要 SSH 上去手改挖矿配置。
4.3 接入主流挖矿内核
OpenRig 的模板机制设计成“内核类型 + 参数”的组合。新增一种内核时,只需在面板上创建一个模板:选择内核类型、填矿池地址、钱包地址、内核启动参数、单卡配置和超频参数。
以常见的 GPU 内核为例,模板配置大致长这样:
{ "kernel_type": "teamredminer", "pool_address": "stratum+tcp://example-pool:3333", "wallet": "your_wallet_address", "parameters": ["--fan_control=50"], "oc_settings": { "core_clock": 1400, "memory_clock": 2100, "power_limit": 120 } }模板创建后,可以批量应用到一组矿机,比如按机架分组应用。Agent 收到新模板后会先校验配置合法性,再重启挖矿进程。这样做的好处是调参不用再挨台机器敲命令,改完模板统一下发,一分钟内全部生效。
4.4 仪表盘与告警通知配置
仪表盘是平时看得最多的界面。我用 React 写了一个简洁的概览页,包含整体算力趋势、在线矿机数、平均温度、最近告警列表。每台矿机的详情页可以查看单卡温度、功耗、算力、内核运行时长,并直接执行重启、切换模板、追加控制指令这些操作。
告警通知我接入了通用 Webhook 模式。不管是钉钉群、企业微信还是其他支持 Webhook 的平台,把地址填到配置里就能收到消息。通知格式是一条纯文本加一个跳转链接,点击直接跳到对应的矿机详情页。
配置项里我还加了一个静默时段。比如凌晨三点的温度高告警,不想被连续打扰,可以把静默时段设为三点到七点,只记录告警不推送通知。这个功能看似不起眼,实际用起来非常舒服。
5. 真实踩坑记录与排障速查表
5.1 我踩过的五个坑
第一个坑是时间同步。矿机上如果系统时间不准,Agent 上报的时间戳就会出现偏差,时序数据画出来的趋势图全是错位的。我后来在 Agent 启动时强制做一次时间同步,并周期性检查时间偏移,超过 60 秒就告警。
第二个坑是 MQTT 半连接。矿机异常断电再恢复后,经常出现网络层已经恢复、但 MQTT 连接还挂在半开状态的问题。Agent 进程还在,实际上已经断开,服务端却以为在线。解决方式是在 Agent 里加了一个心跳自检,如果连续 3 次心跳发送失败就主动重连 Broker。
第三个坑是挖矿内核占用控制端口。有些内核默认占用了 Agent 也需要用的端口,尤其是重启内核后端口释放不及时,导致 Agent 误判为内核崩溃。我给 Agent 的端口探测加上了重试机制,并且把端口占用检测放到矿池模板下发之前。
第四个坑是数据库写入放大。指标每 5 秒一次,30 台矿机各自 8 张卡,数据量积攒起来非常可观。如果不做批量写入,数据库负载会非常高。后来我把写入改成缓存批量提交,每五秒合并一次上报数据,再用单条批量 SQL 插入,负载瞬间降了下来。
第五个坑是挖矿进程重启后拿到的是脏环境。内核用的是同一批超频参数,但偶尔重启后参数没生效,算力跑不满。最后我在 Agent 的重启流程里加入了“等待内核就绪—检查算力—未达标则再次重启”的闭环。
5.2 常见问题速查表
| 症状 | 可能原因 | 排查与解决 |
|---|---|---|
| 矿机显示离线但本机系统正常 | MQTT 半连接或防火墙阻断 | 检查 8883 端口连通性,重启 Agent 服务 |
| 面板有上报数据但无温度曲线 | 采集字段模板与矿机型号不匹配 | 在面板上更新该矿机的内核解析器版本 |
| 自动重启无效 | 模板配置里内核路径错误 | 查看 Agent 日志,核对模板下发内容 |
| 告警一直触发 | 阈值设太低或静默时段未配置 | 调高阈值,或设置静默时段 |
| 算力切换过于频繁 | 利润热度接口数据抖动 | 提高切换判定持续时长,增加新旧算法对比期 |
5.3 几个调优心得
时间序列数据的存储保留,可以按时间做降采样。原始 5 秒级数据保留 3 天,分钟级聚合数据保留 30 天,更早的只留小时级聚合。这样查询历史趋势仍然能看到整体走向,磁盘占用却少了非常多。
采集频率不是越高越好。对普通矿场来说,10 秒一次已经足够,5 秒是一次冗余的激进值。如果矿机数量很大,可以考虑把采集频率调成 10 秒,再对告警类指标用 Agent 侧秒级检测,这样兼顾精细度和负载。
自动恢复逻辑里,每一级操作之间要加入延迟等待。比如先软重启,等 90 秒让内核重新初始化并报告算力,算力恢复后才算成功。时间给太短,容易误判成失败,触发更高级别的重启动作,反而把正常的流程打断。
我个人在实际操作中的体会是,自建这套系统的最大价值不是省钱,而是把“矿场怎么跑”的决策权完全拿回到了自己手上。从采集指标的第一行代码,到控制指令下发的每一条链路,每一个环节都能被审查、被改动、被优化。这套体系用久了以后,你会对自己机架上的每一张卡的状态、每一次异常的前因后果,都有非常清晰的判断,不再依赖厂商给的“平均数据”和“自动处理”。如果你也打算搭一套类似的系统,我的建议是从最小闭环开始,先只做指标采集和展示,把链路跑通后再逐步加入自动恢复和算法切换,这样每一步都有清晰验证,翻车的概率会低很多。