Solana 交易机器人的监控

能在亏钱之前抓住机器人劣化的指标、为什么平均值会掩盖真正重要的失败,以及怎么告警才不会把自己训练成无视告警。

BoltTx Team··15 min read
solana监控告警交易机器人交易上链可观测性

崩掉的机器人好办。它停了,你发现了,重启就行。

★昂贵的失败是那种一边跑着一边越来越差的机器人。★ 它仍然在发交易、仍然在记录成功、仍然报告健康 —— 而它的成交率已经跌了一个星期。

存活时长不是那个指标

大多数团队搭的面板追踪的是"进程还活着吗"。它回答的是一个你很少会有的问题。

常见指标 它漏掉了什么
进程存活时长 一个跑着但每场都输的机器人
发出的交易数 ★有多少落了块★
错误计数 哪些错误重要
★平均延迟★ ★尾巴,亏损就住在那里★
钱包余额 它为什么在变

★"发送到落块"的 slot 距离,按分布看,是一个交易机器人能追踪的最有用的单个数字。★ 其它一切都是解读它的上下文。

配得上位置的那些指标

// ★每一次提交都记录,没有例外。★
metrics.record({
  submittedSlot,
  landedSlot,                                   // 从没落块则为 null
  outcome,                                      // success | reverted | expired
  errorCode: outcome.err ? classify(outcome.err) : null,
  priorityFeeLamports,
  strategy,                                     // ★按来源归因★
});

从这一条记录里,你能推导出所有重要的东西:

落块率。 落块数除以尝试数。不是返回的签名数 —— 签名只意味着 RPC 接收了字节,仅此而已。

slot 距离的分位数。 p50、p90、p99 分开追踪。★平均值是一种"不描述任何一笔真实交易"的算术。★

结果分布。 成功、revert、过期 —— 三种状态,三种不同的原因。把它们合并成"失败"会毁掉全部诊断价值。

按类别的错误。 滑点、insufficient fundsexceeded CUs meant to be usedBlockhashNotFound每一种都指向不同的子系统。

手续费开销对结果。 手续费上升而落块率不动,意味着你在为同样的结果付更多钱 —— 这本身就是一个信号。

如果你的监控显示问题在提交路径上,免费领个 BoltTx key 改一行就能拿来对比。

为什么要分位数而不是平均值

这值得单开一节,因为大多数面板正是栽在这里

机器人 A:每一笔都在 3 个 slot 内落块
机器人 B:90% 在 1 个 slot 内,10% 要 21 个 slot
★两者平均都是 3 个 slot。但它们不是同一种机器人。★

机器人 B 有一成的竞速直接输掉,而这些失败聚集在拥堵期 —— 也正是机会最大的时候平均值对此只字未提,而一个只显示平均值的面板会看起来很稳,同时你的最坏情况正在恶化

★按 p90 和 p99 告警,不要按均值。★ 出问题时,均值是最后才动的。

沉默是一种失败模式

悄悄杀死机器人的那种失败,是什么都没报错的那种。

accountSubscribe 的推送流不再送达。队列不再排空。策略不再触发。★没有异常抛出,没有错误日志,而对进程的健康检查返回一切正常。★

// ★存活检查必须独立于被监控的那条代码路径。★
let lastActivityAt = Date.now();

function onActivity() { lastActivityAt = Date.now(); }

setInterval(() => {
  const quietMs = Date.now() - lastActivityAt;
  if (quietMs > EXPECTED_MAX_QUIET_MS) {
    alert(`已经 ${Math.round(quietMs / 1000)} 秒没有任何活动`);
  }
}, 15_000);

★这个阈值必须来自策略本身的正常节奏。★ 一个安静了一分钟的做市商是坏了。一个安静了一分钟的套利机器人可能只是没找到机会。 要从实际观察到的沉默时长分布里取,不要取一个整数

不会把你训练成无视它的告警

一个对每次单独失败都触发的告警,会训练你去忽略告警。既然有些失败本来就是正常的,按单次告警就必然产生噪音

★按比率变化告警,不要按事件告警。★

// ★和这个机器人自己的近期基线比。★
if (landedRate < baseline.landedRate * 0.8) {
  alert("落块率相比 24 小时基线下降 20%");
}
if (p90SlotDistance > baseline.p90 * 1.5) {
  alert("p90 slot 距离上升 50%");
}

分级才能让信号保持有意义:

级别 例子 响应
★呼叫★ 机器人静默、余额在流失、落块率崩塌 立即
警告 p90 在劣化、手续费开销上升、revert 率上升 当天
记录 单次失败、输掉的竞速 汇总后再看

★输掉一场竞速不是事故。★ 记录它是对的;为它触发呼叫,则是一个团队开始不看呼叫的方式。

归因胜过发现

知道有问题只完成了一半。知道是哪一半有问题,才让你能在它再花掉一天之前修好。

// ★在记录的时候就把两半分开,不要等到调试时才分。★
log({
  detectLag: detectSlot - eventSlot,     // 数据源
  decideLag: submitSlot - detectSlot,    // 你的逻辑
  landLag: landSlot - submitSlot,        // ★提交路径★
});

没有这个拆分,一个在劣化的成交率在"数据源慢""逻辑慢""提交慢"之间含混不清 —— 而团队经常去买一个更快的数据源,来修一个提交侧的问题。

也要按策略打标。 一个策略在劣化而其它稳住了,那是策略问题;所有策略一起劣化,那是基础设施问题。

对着链上核对

你的日志记录的是你的机器人相信发生了什么。★链上记录的是实际发生了什么。★

// ★定期对账能抓到日志抓不到的东西。★
const onChain = await connection.getSignaturesForAddress(wallet, { limit: 1000 });
const logged = await getLoggedSignatures(since);

const unlogged = onChain.filter((s) => !logged.has(s.signature));
if (unlogged.length) {
  alert(`有 ${unlogged.length} 笔链上交易不在日志里`);
}

★"链上有、而你的日志不知道"是令人警觉的那个方向。★ 它意味着要么有一条重复的提交路径,要么某次重试在你放弃之后才落块,要么有你没打算发出的东西正在用你的密钥提交这三种都值得当天查清。

上链应该是什么水平

我们投递节点上的真实交易:中位确认 336 毫秒 —— 不到一个 slot。

★你自己的面板不该只显示一个中位数★ —— 还要看质量集中在哪里、尾巴拖多长。中位数告诉你典型情况,分位数才告诉你会不会赔钱。

BoltTx 在这里的位置

我们负责提交。不管你的监控栈,不管你的策略。

提交走我们自建的四区域投递节点,带 SWQoS 路由,不暴露公共 mempool。对监控来说重要的属性是一致性 —— 一个稳定的分布,才让偏差可以归因到你自己的改动上,而不是网络波动上。

你在本地签名。我们不托管资金、不代签、不修改交易内容。tip 带在交易里、从你自己的钱包链上支付,交易失败时跟着一起 revert —— 这是 Solana 原子交易的机制决定的。只有到达链上的交易才计费。

免费领 API key,没有月费:

const connection = new Connection("https://la.bolttx.io/?api-key=YOUR_KEY");

常见问题

Solana 交易机器人该监控什么? 按分布看的"发送到落块" slot 距离、落块率、成功/revert/过期的分布、按类别的错误,以及手续费开销对结果。存活时长回答的是一个你很少会有的问题。

为什么平均延迟指标有误导性? 因为两个平均值完全一样的机器人,尾部行为可能天差地别,而亏损集中在尾部。要分开追踪 p50、p90、p99,并按高分位告警。

怎么发现一个已经悄悄不工作的机器人? 用一个独立的存活计时器,当"超过策略合理沉默时长"还没有任何活动记录时触发。进程健康检查会通过,而策略已经不再触发了。

什么该触发紧急告警? 超出策略正常节奏的静默、落块率崩塌、意料之外的余额变动,以及日志不知道的链上交易。单次失败属于日志。

怎么避免告警疲劳? 按相对滚动基线的比率变化告警,而不是按单个事件。有些失败本来就正常,所以按单次告警必然产生噪音,并把人训练成无视它。

怎么判断是数据源慢还是提交路径慢? 在每一笔交易上分别记录检测、决策、落块三段延迟。没有这个拆分,劣化的成交率就是含混的 —— 团队经常买更快的数据源来修提交问题。

Solana 机器人的落块率多少算好? 取决于策略和行情,所以要和你自己的近期基线比,而不是和一个外部数字比。相对基线的下降才是信号,绝对值是多少并不重要。

revert 和过期该分开统计吗? 永远该。revert 意味着你的指令在链上撞到了某个条件,过期意味着它从没执行过。 把两者合并成"失败",就抹掉了你修任何一个所需要的信息。

怎么监控手续费效率? 在同一个窗口里追踪手续费开销对落块率。手续费上升而落块率不动,意味着你在为同样的结果付更多钱 —— 值得在它累积之前查清。

链上有、日志里没有的交易意味着什么? 要么有一条重复的提交路径,要么某次重试在你不再追踪之后才落块,要么有你没打算发出的东西正在用你的密钥提交。三种都该当天查。

多久该对账一次? 频繁到能在几小时而不是几天内发现差异。最要紧的方向是:链上有活动而你的日志里没有。

输掉的竞速该告警吗? 记录,但不要为它呼叫。竞争性策略输掉竞速是预期之内的,而输掉比例上升属于警告级的趋势,不是事故。

存活检查的沉默阈值怎么设?那个特定策略实际观察到的沉默时长分布里取。做市商和套利机器人的正常沉默差别极大,一个全局阈值至少对其中一个是错的

slot 距离该按什么粒度记录? 按每一笔交易记,并打上策略和网络状况的标签。过早聚合会让你失去"把变化归因到某个策略或某段拥堵"的能力。

不改机器人代码能监控它吗? 能一部分,只靠链上数据 —— 落块率和 slot 距离可以从签名推导出来。从外部拿不回来的是:这笔交易为什么被发出,以及决策是什么时候做的

如果我什么都没有,第一个该加的指标是什么? 从提交到落块的 slot 距离,按每笔交易连同结果一起记录。几乎其它每一个有用的信号,要么是从它推导出来的,要么要对着它来解读。

延伸阅读

返回博客列表