
1. 项目概述从国赛题目看区块链运维的实战需求看到“区块链系统监控脚本”这个标题很多刚接触区块链运维的同学可能会觉得这无非就是写个脚本看看服务器CPU、内存。但如果你真这么想那可能就错过了国赛题目设计的深意也低估了生产环境中区块链节点运维的复杂性。这个题目源自全国职业院校技能大赛的国赛它考核的绝不仅仅是写几行Shell命令而是对区块链系统特别是联盟链或公链节点其特有运行状态、健康指标和故障模式的深度理解与监控能力。区块链节点无论是Fabric、FISCO BCOS还是以太坊都不是一个普通的Web服务。它的核心价值在于共识、同步、出块。因此监控的重点必须从“资源是否够用”上升到“链是否在健康地工作”。CPU飙高可能是在正常打包交易内存占用大可能是因为状态数据库缓存磁盘IO高可能是区块在同步。一个只会报警“资源使用率高”的监控脚本在区块链场景下就是“噪音制造机”甚至会误导运维人员做出错误决策。这个国赛题目的核心就是要求我们设计一个能真正“听懂”区块链语言的监控脚本。它需要像一位经验丰富的链上医生不仅能测体温系统资源更要会听心跳区块高度、把脉搏交易池状态、看气色节点连接数。我们需要用Shell脚本这把“手术刀”精准地剖开节点的运行日志、RPC接口和系统状态提取出那些真正关乎链生死的关键指标。下面我就结合常见的开源联盟链框架和公节点部署实践拆解一下如何构建这样一个有深度的监控脚本。2. 监控体系设计不止于资源聚焦于链上健康在动手写脚本之前我们必须先想清楚到底要监控什么一个完整的区块链节点监控体系应该分为三个层次基础设施层、节点服务层和链上业务层。国赛题目通常要求覆盖前两层并对第三层有初步涉及。2.1 基础设施层监控确保土壤肥沃这是监控的基石任何上层应用的问题最终都可能体现在这一层。但我们的监控逻辑需要更智能。CPU与负载监控不仅要看整体使用率更要区分是用户态us还是系统态sy。区块链节点如Geth、Besu的共识和交易执行主要在用户态。如果sy异常高可能意味着磁盘IO等待严重或是系统调用频繁需要检查磁盘或网络。# 获取详细的CPU统计信息重点关注us和sy cpu_info$(top -bn1 | grep \%Cpu(s)\) us$(echo $cpu_info | awk \{print $2}\) sy$(echo $cpu_info | awk \{print $4}\)内存监控Linux系统的内存管理机制使得“剩余内存少”不一定是问题。关键看可用内存available和Swap使用率。区块链节点尤其是全节点会利用大量内存缓存状态数据这是正常行为。Swap如果被频繁使用则是严重警告。# 查看内存与Swap信息 mem_info$(free -m | grep Mem) available_mem$(echo $mem_info | awk \{print $7}\) swap_info$(free -m | grep Swap) swap_used$(echo $swap_info | awk \{print $3}\)磁盘监控重点监控节点数据目录所在分区。除了使用率Inode使用率和磁盘IO等待await同样关键。区块数据是由大量小文件状态、区块组成的Inode耗尽会导致无法写入新数据即使磁盘空间还有剩余。高await值意味着磁盘响应慢会拖慢区块同步。# 查看指定挂载点的磁盘使用率和Inode使用率 df -h /data/blockchain | tail -1 df -i /data/blockchain | tail -1 # 使用iostat查看磁盘await需安装sysstat iostat -dx 1 2 | grep \sda\ | tail -1网络监控监控节点的监听端口如Fabric的7051Geth的8545是否存活是基本操作。更进一步需要监控节点的对等连接数peer count。连接数过少可能导致节点被孤立无法同步最新区块。2.2 节点服务层监控洞察链本身的生命体征这是区块链监控区别于普通应用监控的核心。进程存活监控检查geth、besu、fabric-peer等核心进程是否存在。区块高度监控这是最核心的指标。通过节点的RPC/API接口如Geth的eth_blockNumber获取当前区块高度。监控脚本需要定期记录并计算区块高度增长是否停滞。连续多个周期高度不变意味着节点可能已停止出块或同步。# 使用curl调用Geth节点的RPC接口获取最新区块号十六进制 block_number_hex$(curl -s -X POST --data \{\jsonrpc\:\2.0\,\method\:\eth_blockNumber\,\params\:[],\id\:1}\ http://localhost:8545 | jq -r \.result\) # 将十六进制转换为十进制 block_number$(printf \%d\ $block_number_hex)交易池状态监控监控待处理交易数pending transactions。如果交易池持续为空可能意味着没有交易产生或网络有问题如果交易池堆积过高可能意味着网络拥堵或gas费设置不合理。同步状态监控对于同步节点需要监控它是否正在同步以及同步的进度。例如通过eth_syncing接口可以获取当前同步的起始块和最高块。共识状态监控针对共识节点对于PoA或PoS等共识机制的节点需要监控其是否在出块者列表中最近是否成功出块。这通常需要查询特定的管理接口或分析日志。2.3 链上业务层监控进阶国赛题目可能涉及基础但实际生产环境必须考虑。例如监控智能合约中关键变量的状态、特定类型交易的数量、Gas费用的波动等。这需要更复杂的脚本结合事件监听和链上查询。实操心得在设计监控指标时一定要先明确节点的类型共识节点、同步节点、轻节点和链的类型公链、联盟链。不同类型的节点监控侧重点完全不同。例如对共识节点出块间隔和出块成功率是生命线对同步节点区块高度差和同步速度是关键。3. 脚本核心模块拆解与Shell编程要点一个健壮的监控脚本其结构应该是模块化、可配置、易扩展的。下面我们按功能模块来拆解Shell脚本的实现。3.1 配置与初始化模块脚本不应该把监控项、阈值、节点RPC地址等硬编码在逻辑里。一个好的做法是使用一个独立的配置文件如monitor.conf或者至少在脚本开头用变量声明。#!/bin/bash # 监控脚本主入口 # 加载配置文件 CONFIG_FILE\/path/to/monitor.conf\ if [ -f \$CONFIG_FILE\ ]; then source \$CONFIG_FILE\ else echo \配置文件 $CONFIG_FILE 不存在\ 2 exit 1 fi # 或者在脚本头部定义关键变量 NODE_RPC\http://127.0.0.1:8545\ CHAIN_DATA_DIR\/data/blockchain/geth/chaindata\ ALERT_THRESHOLD_CPU90 ALERT_THRESHOLD_BLOCK_DELAY10 # 允许的区块高度延迟块数 LOG_FILE\/var/log/blockchain_monitor.log\注意事项使用source命令加载配置时要确保配置文件的权限安全如chmod 600 monitor.conf避免敏感信息泄露。另外所有路径尽量使用绝对路径避免因脚本执行目录不同而导致的错误。3.2 指标采集模块这是脚本的“传感器”部分。每个采集函数应专注于获取一类数据并做好错误处理。# 函数获取系统CPU使用率 get_cpu_usage() { local cpu_usage # 使用vmstat取1秒内的平均CPU空闲时间然后计算使用率 cpu_idle$(vmstat 1 2 | tail -1 | awk \{print $15}\) cpu_usage$((100 - cpu_idle)) echo $cpu_usage # 更精确的做法可以使用/proc/stat计算但vmstat更简洁 } # 函数获取节点最新区块高度 get_block_height() { local rpc_url\$1\ local height_hex height # 调用RPC使用jq解析JSON响应 height_hex$(curl -s -X POST --max-time 5 --connect-timeout 3 \\ -H \Content-Type: application/json\ \\ --data \{\jsonrpc\:\2.0\,\method\:\eth_blockNumber\,\params\:[],\id\:1}\ \\ \$rpc_url\ 2/dev/null | jq -r \.result\) # 错误处理如果curl或jq失败height_hex可能为空或不是十六进制 if [[ -z \$height_hex\ || \$height_hex\ \null\ ]]; then echo \ERROR\ # 返回错误标识 return 1 fi # 将十六进制0x开头转换为十进制 height$(printf \%d\ \$height_hex\ 2/dev/null) if [ $? -ne 0 ]; then echo \ERROR\ return 1 fi echo $height } # 函数检查进程是否存在 check_process() { local process_name\$1\ # pgrep更精确避免grep匹配到自身或其它包含关键字的进程 if pgrep -x \$process_name\ /dev/null; then echo \RUNNING\ else echo \STOPPED\ fi }3.3 告警判断与触发模块采集到数据后需要与阈值比较决定是否告警。告警逻辑要避免“抖动”即指标在阈值附近波动时频繁告警。常见的做法是引入连续触发机制。# 全局变量记录连续异常次数 BLOCK_DELAY_COUNT0 CPU_HIGH_COUNT0 # 连续异常N次后才真正告警 ALERT_CONSECUTIVE2 # 函数判断区块高度是否异常 judge_block_height() { local current_height$1 local last_height$2 # 需要有一个机制记录上一次的高度比如写入文件 if [[ \$current_height\ \ERROR\ ]]; then echo \RPC接口调用失败\ return 2 fi if [ -z \$last_height\ ]; then # 第一次运行无法判断只记录 echo \INIT\ return 0 fi if [ \$current_height\ -eq \$last_height\ ]; then BLOCK_DELAY_COUNT$((BLOCK_DELAY_COUNT 1)) if [ $BLOCK_DELAY_COUNT -ge $ALERT_CONSECUTIVE ]; then echo \BLOCK_STALLED\ # 区块停滞 return 1 else echo \BLOCK_DELAYING\ # 区块延迟中未达到告警次数 return 0 fi else # 高度增长重置计数器 BLOCK_DELAY_COUNT0 echo \HEALTHY\ return 0 fi } # 函数判断CPU使用率 judge_cpu_usage() { local cpu_usage$1 if [ \$cpu_usage\ -ge \$ALERT_THRESHOLD_CPU\ ]; then CPU_HIGH_COUNT$((CPU_HIGH_COUNT 1)) if [ $CPU_HIGH_COUNT -ge $ALERT_CONSECUTIVE ]; then echo \CPU_CRITICAL\ return 1 else echo \CPU_HIGH\ return 0 fi else CPU_HIGH_COUNT0 echo \CPU_NORMAL\ return 0 fi }3.4 日志记录与告警输出模块告警信息不能只打印在终端需要持久化到日志文件并可能通过外部渠道如邮件、钉钉、企业微信机器人通知。LOG_FILE\/var/log/blockchain_monitor.log\ # 函数统一日志记录 log_message() { local level\$1\ # INFO, WARNING, ERROR, ALERT local message\$2\ local timestamp$(date \%Y-%m-%d %H:%M:%S\) echo \[$timestamp] [$level] $message\ | tee -a \$LOG_FILE\ } # 函数触发告警动作 trigger_alert() { local alert_subject\$1\ local alert_body\$2\ # 1. 记录到日志 log_message \ALERT\ \$alert_subject - $alert_body\ # 2. 发送邮件需要配置mailx或sendmail # echo \$alert_body\ | mail -s \区块链节点告警: $alert_subject\ adminexample.com # 3. 发送到钉钉机器人更常用 # DINGDING_WEBHOOK\https://oapi.dingtalk.com/robot/send?access_tokenYOUR_TOKEN\“ # curl -s \$DINGDING_WEBHOOK\ -H \Content-Type: application/json\ -d \{\\\msgtype\\\: \\\text\\\, \\\text\\\: {\\\content\\\: \\\告警: $alert_subject\\n详情: $alert_body\\\}}\ # 4. 或者简单地在严重情况下尝试重启服务慎用 # if [[ \$alert_subject\ *\区块停滞\* ]]; then # systemctl restart geth.service # log_message \WARNING\ \已尝试重启geth服务\ # fi }3.5 主控循环与调度模块最后我们需要一个主循环或通过crontab定时调度将上述模块串联起来。# 主监控函数 main_monitor() { log_message \INFO\ \开始执行区块链节点监控检查...\ # 1. 检查进程 process_status$(check_process \geth\) if [ \$process_status\ \STOPPED\ ]; then trigger_alert \节点进程异常\ \geth进程不存在节点可能已停止运行。\ fi # 2. 检查CPU cpu_usage$(get_cpu_usage) cpu_judge_result$(judge_cpu_usage \$cpu_usage\) if [[ \$cpu_judge_result\ \CPU_CRITICAL\ ]]; then trigger_alert \CPU使用率持续过高\ \当前CPU使用率: ${cpu_usage}% 阈值: ${ALERT_THRESHOLD_CPU}%。\ fi # 3. 检查区块高度 current_height$(get_block_height \$NODE_RPC\) # 读取上一次记录的高度 last_height_file\/tmp/last_block_height.txt\ last_height$(cat \$last_height_file\ 2/dev/null || echo \\) height_judge_result$(judge_block_height \$current_height\ \$last_height\) case $height_judge_result in \RPC接口调用失败\) trigger_alert \节点RPC接口不可用\ \无法通过$NODE_RPC获取区块高度请检查节点服务与网络。\ ;; \BLOCK_STALLED\) trigger_alert \区块高度停滞\ \当前区块高度: $current_height, 已连续${ALERT_CONSECUTIVE}次检查未增长。\ ;; \HEALTHY\) # 高度正常增长更新记录文件 echo \$current_height\ \$last_height_file\ log_message \INFO\ \区块高度正常增长至: $current_height\ ;; esac log_message \INFO\ \本次监控检查完成。\ } # 如果是通过脚本直接运行则执行一次 # main_monitor # 更常见的做法是将脚本设置为每分钟通过crontab执行一次 # */1 * * * * /path/to/blockchain_monitor.sh /var/log/monitor_cron.log 214. 高级监控技巧与生产环境考量一个能在国赛拿高分的脚本或者能在生产环境稳定运行的脚本必须考虑更多边界情况和优化点。4.1 性能数据的历史记录与趋势分析简单的阈值告警是滞后的。更高级的做法是将每次采集的性能数据CPU、内存、区块高度、交易数以时间序列的形式记录下来例如写入csv文件或推送到类似InfluxDB的时序数据库中。这样我们可以绘制趋势图直观看到资源使用的变化判断是周期性高峰还是持续恶化。计算基线告警根据历史数据动态计算“正常范围”而不是固定阈值。例如CPU使用率在工作日白天通常为40%-60%如果突然持续低于20%或高于80%都可能是异常。关联分析分析区块同步速度变慢时是否伴随着磁盘IO等待时间的升高。在Shell中可以简单地将数据追加到文件echo \$(date %s),$cpu_usage,$block_height,$(get_pending_tx_count)\ /var/metrics/blockchain_metrics.csv4.2 监控脚本自身的健壮性监控脚本不能成为系统的不稳定因素。超时控制所有网络调用如curl访问RPC必须设置超时--max-time,--connect-timeout避免因节点无响应导致脚本挂起。资源限制脚本本身不应消耗过多CPU或内存。避免在循环中使用高开销命令。避免重复告警实现一个简单的“告警冷却”机制。例如发送一条“区块停滞”告警后在接下来的1小时内即使问题持续也不再发送相同告警直到状态恢复为正常后再发生异常。依赖检查脚本开始时应检查所需命令jq,curl,bc等是否存在并检查配置文件、日志目录的权限。4.3 对接外部监控与可视化平台在真实的企业运维中我们很少只用独立的Shell脚本。通常会将Shell脚本作为数据采集器Agent将采集到的指标输出为标准格式如JSON、Prometheus Exposition格式然后由node_exporter的textfile收集器抓取或者直接推送到监控中心。例如将输出改为Prometheus格式# 输出Prometheus格式的指标 echo \# HELP node_block_height Current block height of the node\ echo \# TYPE node_block_height gauge\ echo \node_block_height{chain\\\mainnet\\\, instance\\\$HOSTNAME\\\} $current_height\ echo \# HELP node_cpu_usage_percent CPU usage percentage\ echo \# TYPE node_cpu_usage_percent gauge\ echo \node_cpu_usage_percent{instance\\\$HOSTNAME\\\} $cpu_usage\然后将这个输出重定向到/var/lib/node_exporter/textfile_collector/blockchain.promPrometheus通过node_exporter就能自动收集这些自定义指标并在Grafana中制作精美的仪表盘。4.4 针对不同区块链框架的适配国赛题目可能指定或隐含了特定的链框架。我们需要调整采集方法Hyperledger Fabric监控Peer和Orderer节点。除了进程和资源关键指标包括ledger_height账本高度、gossip状态、endorser处理交易的成功率。这些信息通常需要通过调用其metrics端点默认端口9443或查询运维API获取。FISCO BCOS作为国产联盟链其提供了丰富的getConsensusStatus,getSyncStatus,getGroupPeers等RPC接口非常适合用于监控脚本采集。以太坊Geth/Besu如前所述使用标准JSON-RPC接口eth_,net_,admin_前缀的方法是主要方式。admin_peers可以查看对等节点详情。5. 常见问题排查与脚本调试实录即使脚本写好了在实际运行中也会遇到各种问题。这里记录几个我踩过的坑和解决方法。5.1 问题一jq命令解析JSON失败报错“parse error”现象curl能拿到返回但jq处理时失败。排查首先直接运行curl命令看看返回的是什么。很可能节点返回的不是标准JSON而是一个HTML错误页面比如Nginx 502错误或者连接被拒绝。使用curl -v查看详细的请求和响应头。在脚本中将curl的原始输出先保存到临时文件或者用echo打印出来检查。解决在curl命令后增加2/dev/null只捕获标准输出并在管道处理前检查返回码和内容。response$(curl -s -w \%{http_code}\ -o /tmp/response.json \$RPC_URL\) http_code${response: -3} # 获取最后三位状态码 if [ \$http_code\ -ne 200 ]; then log_message \ERROR\ \RPC请求失败HTTP状态码: $http_code\ # 可以查看/tmp/response.json的内容辅助诊断 exit 1 fi # 再用jq处理/tmp/response.json5.2 问题二脚本在crontab中运行异常但手动执行正常现象这是最经典的问题。排查环境变量crontab的执行环境与用户登录Shell环境不同PATH变量通常非常精简。你的jq、curl命令可能不在crontab的PATH中。相对路径crontab的执行当前目录通常是用户的家目录脚本中使用的相对路径如./config.conf会失效。输出重定向crontab中的任务如果没有正确重定向输出错误信息会以邮件形式发送给用户如果邮件未配置你就看不到错误。解决在脚本开头显式设置PATHPATH/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin脚本中所有路径都使用绝对路径。在crontab条目中将标准输出和错误输出重定向到日志文件* * * * * /absolute/path/to/script.sh /var/log/script_cron.log 215.3 问题三监控发现区块高度不增长但节点日志显示正常现象脚本告警区块停滞但登录服务器查看geth日志发现节点在正常同步或出块。排查RPC端口问题检查脚本中配置的RPC端口是否正确。Geth默认的HTTP-RPC端口是8545但可能被禁用或修改。RPC模块启用问题Geth需要通过--http和--http.api参数启用特定模块的RPC。确保eth模块被启用--http.api eth,net,web3。防火墙或安全组检查服务器防火墙和云服务商安全组是否允许从监控脚本所在主机访问节点的RPC端口。时钟不同步如果监控脚本和节点服务器时间不同步可能会导致判断逻辑混乱。确保所有服务器使用NTP同步时间。解决在脚本中增加对RPC接口可用性的基础检查。例如在获取区块高度前先调用一个更简单的方法如web3_clientVersion确认RPC通道是通的。5.4 问题四磁盘空间充足但节点报“no space left on device”现象df -h显示磁盘使用率不到80%但节点无法写入。排查这几乎可以肯定是Inode用尽了。使用df -i命令查看。解决区块链节点尤其是以太坊的geth在chaindata目录下会创建海量的小文件状态树节点。需要定期归档或迁移历史数据或者一开始就使用Inode数量更多的文件系统如XFS通常比ext4有更多的Inode。写一个能用的监控脚本不难但写一个能在生产环境稳定、准确、高效运行的监控脚本需要充分考虑上述所有的细节。国赛题目考察的正是这种从“功能实现”到“生产就绪”的跨越性思维。希望这份详细的拆解能帮你不仅完成比赛更能掌握区块链运维监控的实战精髓。