一般来说,监控 Substrate 框架开发的区块链节点,可以使用官方推荐的 Prometheus + Grafana 技术栈。在节点数量比较多的情况下,这套方案的优势比较容易体现出来,我给公司的官方节点也是这么配的。不过近期 Darwinia 主网上线,有不少同事想要跑自己的验证人(validator)节点。对于他们来说:

  • 搭建一套 Prometheus 还要自己调面板和规则,成本实在太高;
  • 只用 PM2、Supervisord、Systemd 之类的守护进程通常只能保证进程没挂,但节点是否正常出块是未知的(例如断网、0 Peer 的情况,节点进程还在,其实已经掉线了)。

为了解决以上这两个问题,我搞了一套非常简易的、基于日志的监控预警方法。

🚀 KUBE-VALI 是基于 Kubernetes 集群大规模部署的节点,稳定可靠,求大佬投票。

基本思路

基于 Darwinia 验证人产块,会有类似 🎁 Prepared block for proposing at ... 的日志输出,只要有个脚本不断检查节点日志,如果一段时间内没有类似的输出,说明节点可能已经出了问题,发送通知或重启节点均可。

最终效果

具体步骤

1) 实现检查日志

首先登录你的验证人节点,创建一个 Watchlog 脚本,例如 /usr/bin/darwinia-watchlog.sh

#!/usr/bin/env bash

RETRIVE_LOG_COMMAND="journalctl -u darwinia-node.service -o cat --since -30m"
# RETRIVE_LOG_COMMAND="docker logs darwinia-node --since 30m"

echo "[INFO] Checking Darwinia logs..."

DARWINIA_LOGS="$($RETRIVE_LOG_COMMAND | grep 'Prepared block')"

if [ $? -eq 0 ]; then

echo "[INFO] New blocks detected."

else

echo "[WARN] No blocks deteched!"

fi
  • RETRIVE_LOG_COMMAND 是用来获取近期节点日志的命令。我列出了两个例子,前者适用于 Systemd 启动的节点,后者适用于 Docker 启动的节点,你可以任意修改它。
  • 'Prepared block' 是在日志里查找的关键词,你也可以修改为 'Imported' 之类的值。

随后运行该脚本,会发现有 [INFO] New blocks detected. 或是 [WARN] No blocks deteched! 的输出,说明它已经能够正常检测节点日志了。

2) 持续检查节点日志

为了能够 持续 检查节点日志,我们使用 Cron job 每分钟 调用一次该脚本就可以了。执行以下脚本新增一个每分钟执行的 Cron job:

(crontab -l ; echo "* * * * * /usr/bin/darwinia-watchlog.sh | logger -t darwinia-watchlog") 2>&1 | grep -v "no crontab" | sort | uniq | crontab -

3) 预警通知和重启

自己写通知太麻烦,不如试试 https://healthchecks.io/ 吧。Healthchecks.io 是一款 开源的 定时任务监控、通知系统。它假设你的脚本在「某一时刻」运行,正常情况下,你的脚本运行成功并给它发送一个成功消息;如果你的脚本没有运行,或是执行出错,它能够按照指定的通知渠道,给你发送一条预警通知。

注册后首先在 Integrations 里添加通知渠道,例如我添加了我的 Telegram:

随后在 Checks 页面点击 Add Check 新增一个 Check,会跳到新创建的 Check 的信息页面:

Schedule 是肯定要改的,需要跟我们脚本的实际运行计划匹配,点击 Change Schedule...,把 Period 和 Grace Time 全部调成 1 minute

最后点击 Usage Examples...,找到 Bash 的例子,复制这行命令:

回到我们的节点机器上,修改 /usr/bin/darwinia-watchlog.sh 脚本,在 echo "[INFO] New blocks detected." 之后添加这行命令就可以了:

# ...

if [ $? -eq 0 ]; then

echo "[INFO] New blocks detected."
curl -m 10 --retry 5 https://hc-ping.com/9a9ea2f6-1b6e-43c3-ba5a-000130ad0fd3 # 在这里

# ...

这样我们的脚本在每分钟定时执行时,如果有检查到新块产生,就会输出 [INFO] New blocks detected.,并调用 healthchecks.io。如果没有检查到,就不会调用 healthchecks.io,进而 healthchecks.io 会默认执行失败,从而发起通知。

最终改进后的完整脚本

你可以直接复制以下脚本,我还做了一些其它的小优化,修改 !!! HEALTH CHECK ID !!! 即可使用。

#!/usr/bin/env bash

RETRIVE_LOG_COMMAND="journalctl -u darwinia-node.service -o cat --since -30m"
# RETRIVE_LOG_COMMAND="docker logs darwinia-node --since 30m"

HEALTHCHECK_IO_URL="https://hc-ping.com/!!! HEALTH CHECK ID !!!" # 别忘记填入 Healthchecks.io 的 URL

echo "[INFO] Checking Darwinia logs..."

DARWINIA_LOGS="$($RETRIVE_LOG_COMMAND | grep 'Prepared block')"

if [ $? -eq 0 ]; then

echo "[INFO] New blocks detected."
echo -n "[INFO] Notifying healthchecks.io... "
curl -fsS --max-time 10 --retry 3 --data-raw "$DARWINIA_LOGS" "$HEALTHCHECK_IO_URL"

else

echo "[WARN] No blocks deteched!"
echo -n "[INFO] Notifying healthchecks.io... "
curl -fsS --max-time 10 --retry 3 "$HEALTHCHECK_IO_URL/fail"

fi

你可以执行 journalctl SYSLOG_IDENTIFIER=darwinia-watchlog -f 观察脚本运行日志:

Sep 29 10:49:01 darwinia-watchlog[19493]: [INFO] Checking Darwinia logs...
Sep 29 10:49:01 darwinia-watchlog[19493]: [INFO] New blocks detected.
Sep 29 10:49:01 darwinia-watchlog[19493]: [INFO] Notifying healthchecks.io... OK
Sep 29 10:50:01 darwinia-watchlog[19503]: [INFO] Checking Darwinia logs...
Sep 29 10:50:01 darwinia-watchlog[19503]: [INFO] New blocks detected.
Sep 29 10:50:02 darwinia-watchlog[19503]: [INFO] Notifying healthchecks.io... OK
...

写在最后

  • 其实这个方案是受到 GCP Log-based metrics 启发而实现的,最早我的思路是用 ELK 分析日志,但某天突然灵光一现 — 根本不用这么麻烦,直接写个脚本 + CRON 定时执行 + 随便找个外部监控就好了。
  • 其实也可以不用 CRON,改用脚本死循环也可以。不过这样就增加了脚本本身的复杂度,另外还得处理常驻进程等问题。
  • 另外也可以不用 healthcheck.io,直接在脚本内发通知。但同样得考虑:万一脚本也崩了怎么办?如果验证人节点彻底断网,根本发不出来通知怎么办?单台机器无法解决,再开一台机器用作监控违背了这个方案的初心,而利用外部的、被动的(即使机器挂了发不出来通知也能被监控捕捉到)监控服务是我目前能想到成本最低廉的解决方案了。