1. 项目概述与核心价值最近几年区块链技术从金融领域的“神坛”逐渐走向产业应用特别是在职业教育和技能竞赛中它已经成为一个检验学生综合能力的重要赛道。全国职业院校技能大赛的“区块链技术与应用”赛项就是这样一个风向标。它考察的远不止是概念理解更是实打实的工程化能力比如如何部署、运维和监控一个真实的区块链网络。我注意到很多参赛队伍在完成了链的搭建和智能合约部署后往往在“系统监控”这个环节卡壳。监控脚本写得好不好直接关系到在比赛高压环境下能否快速定位问题、保障系统稳定运行这往往是拉开分数差距的关键。这次我们要拆解的正是第六套赛题中的“区块链系统监控脚本”。这个标题看似简单背后却涵盖了从Linux系统管理、Shell脚本编程到区块链节点状态解析的复合型技能。它要求参赛者不仅能写出脚本更要理解区块链节点如FISCO BCOS、Fabric或企业以太坊的运行机制知道哪些指标是生命线以及如何高效、准确地采集和呈现这些指标。对于一名即将踏入运维开发或区块链应用开发岗位的学生来说掌握这套监控脚本的编写思路其价值远超比赛本身它是你构建可观测性系统的第一块扎实的基石。简单来说这个项目就是要求你编写一个Shell脚本这个脚本能自动化地检查区块链系统中各个核心组件的健康状态并以清晰、易读的方式输出报告。它要解决的痛点非常明确在国赛有限的调试时间内评委或运维人员不可能手动登录每台服务器去敲一堆命令你需要一个工具能一键告诉你“网络是否连通”、“节点是否在出块”、“磁盘空间是否告急”、“内存使用是否异常”。这本质上是一个将运维经验产品化的过程。2. 监控脚本的整体设计与核心思路接到“编写监控脚本”这个任务新手最容易犯的错误就是立刻开始写代码。我的经验是先花70%的时间做设计剩下的30%写代码会顺畅得多。这个设计的核心就是回答三个问题监控谁监控什么怎么呈现2.1 监控对象与架构分析国赛的区块链环境通常是多节点的可能包含排序节点Orderer、Peer节点、CA节点甚至前端管理界面。以常见的联盟链平台为例我们需要明确脚本的运行环境。通常监控脚本会部署在一台“监控机”上或者就在其中某个节点上运行通过SSH或直接本地命令去采集其他节点的信息。关键设计决策集中式 vs 分布式采集集中式采集脚本在单一机器上运行通过ssh命令需要提前配置好密钥免密登录连接到其他节点执行命令收集数据后统一处理。这种方式逻辑简单适合节点数量不多比如小于10个的赛题环境。缺点是强依赖于网络连通性和SSH配置一旦监控机故障整个监控就瘫痪了。分布式采集在每个节点上部署一个轻量级的采集脚本或Agent定期将数据推送到一个中心存储如简单的文本文件、数据库或监控服务器。监控主脚本只负责从中心存储读取和展示。这种方式更健壮但部署复杂度高。对于国赛场景我强烈推荐集中式采集。比赛环境通常是稳定的局域网节点数量可控集中式方案能最快实现也最方便评委检查。你的脚本开头就应该定义一个清晰的节点列表。#!/bin/bash # 定义节点IP和角色 declare -A NODES( [192.168.1.101]orderer [192.168.1.102]peer0.org1 [192.168.1.103]peer1.org1 [192.168.1.104]peer0.org2 )2.2 核心监控指标定义这是脚本的灵魂。你需要和区块链系统的“生命体征”打交道。指标选错了脚本写得再漂亮也没用。我们可以将指标分为两大类系统资源指标和区块链业务指标。系统资源指标这是基础任何服务跑在上面都关心这些。CPU使用率长时间接近100%可能意味着交易处理繁忙或存在死循环。内存使用率区块链节点尤其是带状态数据库的可能是内存大户内存不足会导致节点崩溃。磁盘使用率区块链数据增长很快特别是全节点。必须监控数据目录所在磁盘。网络连接数查看节点是否建立了应有的P2P连接。例如使用netstat查看监听端口。进程状态最关键的一点区块链节点的进程如fisco-bcos,peer,orderer是否在运行。区块链业务指标这才是体现你区块链专业水平的地方。节点区块高度通过调用节点的RPC/API接口如FISCO BCOS的getBlockNumber Fabric Peer的peer channel getinfo获取。所有Peer节点的区块高度应该大致相同如果某个节点高度停滞说明同步可能出了问题。交易池状态待处理交易的数量可以反映网络拥堵情况。节点共识状态对于PBFT等共识算法可以检查节点是否是共识委员会成员、当前视图view等。智能合约调用错误率通过日志分析统计一段时间内交易失败的比例。注意国赛题目可能会指定必须监控的几项关键指标。你的脚本必须首先100%覆盖这些指定指标然后再根据自己的理解补充上述通用指标。这体现了你的需求理解能力和扩展性思维。2.3 输出呈现与告警设计监控数据需要被人类快速理解。切忌输出一堆杂乱无章的数字。好的呈现应该结构化使用表格形式区分不同节点和不同指标。可视化在命令行里可以用颜色来区分状态。例如绿色表示正常黄色表示警告红色表示严重错误。分级摘要脚本最后应该有一个“健康度总结”比如“总计4个节点3个健康1个异常peer1.org1 磁盘使用率95%”。告警功能在国赛脚本中不一定强制要求但加上会是一个亮点。简单的实现可以是当某个指标超过阈值如磁盘90%不仅在表格中标红还在最后单独输出一行醒目的告警信息甚至可以模拟发送邮件使用mail命令前提是比赛环境允许。整体脚本流程图逻辑层面初始化定义节点、颜色代码、阈值。循环遍历每一个节点。对于每个节点检查系统指标通过SSH执行top,df,ps,netstat等。检查区块链指标通过curl调用RPC接口或执行节点CLI命令。解析命令返回结果与阈值比较判断状态。汇总所有节点的状态生成彩色表格输出。输出健康度摘要和告警信息。3. 核心模块拆解与Shell脚本实现细节有了设计图我们就可以动手编码了。一个健壮、易读的监控脚本通常由以下几个核心模块构成。3.1 环境检查与依赖声明脚本一开始就应该检查运行环境避免跑到一半因为缺少命令而失败。这是一个很好的编程习惯。#!/bin/bash # 区块链系统监控脚本 v1.0 # 描述用于监控多节点区块链集群的系统与业务状态 set -euo pipefail # 严格模式遇到错误退出使用未定义变量报错管道中任意错误视为整个管道失败。 # 定义颜色输出增强可读性 RED\033[1;31m GREEN\033[1;32m YELLOW\033[1;33m NC\033[0m # No Color # 检查必要命令是否存在 check_dependencies() { local cmds(ssh curl jq awk grep) # jq用于解析JSON如果节点API返回JSON则必需 for cmd in ${cmds[]}; do if ! command -v $cmd /dev/null; then echo -e ${RED}错误未找到命令 $cmd请确保其已安装。${NC} exit 1 fi done } check_dependenciesset -euo pipefail这行是Shell脚本的“安全绳”。-e确保任何命令失败返回非零值时脚本立即停止防止错误累积。-u确保使用未定义的变量时报错。-o pipefail确保管道命令中任何一个环节失败整个管道就失败。在监控脚本中这能帮你快速发现环境配置问题。3.2 节点状态采集函数这是脚本最核心的部分。我们需要为每一类检查编写独立的函数这样代码清晰也便于调试和复用。函数1检查远程节点进程状态# 函数检查指定节点上的某个进程是否在运行 # 参数$1 - 节点IP, $2 - 进程名关键字 check_process() { local node_ip$1 local process_name$2 local ssh_userroot # 根据比赛环境修改可能是ubuntu或其他用户 # 使用ssh执行远程命令通过ps和grep查找进程 # pgrep -f 可以匹配完整的命令行更准确 if ssh -o ConnectTimeout5 -o BatchModeyes ${ssh_user}${node_ip} pgrep -f ${process_name} /dev/null; then echo -e ${GREEN}运行中${NC} return 0 else echo -e ${RED}未运行${NC} return 1 fi }这里有几个关键点-o ConnectTimeout5设置SSH连接超时为5秒避免某个节点无响应导致脚本长时间卡住。-o BatchModeyes禁用密码询问配合SSH密钥使用。这是比赛准备环节的重中之重你必须在监控机和所有被监控节点之间配置好SSH密钥免密登录否则脚本无法自动化。pgrep -f比简单的ps | grep更可靠因为它匹配整个命令行字符串减少误杀例如grep java命令本身也会包含“java”关键字。函数2检查磁盘使用率# 函数检查指定节点上特定目录的磁盘使用率 # 参数$1 - 节点IP, $2 - 挂载点路径如 /data check_disk() { local node_ip$1 local mount_point$2 local ssh_userroot local threshold_warning80 # 警告阈值% local threshold_critical90 # 严重阈值% # 通过df命令获取使用率百分比数字 local usage$(ssh ${ssh_user}${node_ip} df -h ${mount_point} | tail -1 | awk {print \$5} | tr -d %) if [[ -z $usage ]]; then echo -e ${RED}挂载点不存在${NC} return 1 fi if (( usage threshold_critical )); then echo -e ${RED}${usage}%${NC} return 2 elif (( usage threshold_warning )); then echo -e ${YELLOW}${usage}%${NC} return 1 else echo -e ${GREEN}${usage}%${NC} return 0 fi }这里使用了df -h、tail、awk和tr的组合拳来提取纯数字的使用率。阈值判断使用了双层逻辑提供更细致的状态反馈。函数3调用区块链节点API获取区块高度这是体现区块链专业性的地方。不同链的API调用方式不同。示例FISCO BCOS节点JSON-RPC# 函数获取FISCO BCOS节点的区块高度 # 参数$1 - 节点IP, $2 - RPC端口默认8545 get_block_number_bcos() { local node_ip$1 local rpc_port${2:-8545} local rpc_urlhttp://${node_ip}:${rpc_port} # 构造JSON-RPC请求 local json_request{jsonrpc:2.0,method:getBlockNumber,params:[],id:1} # 使用curl调用设置超时并用jq解析结果 local response if response$(curl -s -m 10 --connect-timeout 5 -X POST ${rpc_url} -H Content-Type: application/json -d ${json_request} 2/dev/null); then local block_number$(echo $response | jq -r .result) if [[ $block_number ! null $block_number ~ ^[0-9]$ ]]; then echo $block_number return 0 fi fi echo N/A # 获取失败 return 1 }这里使用了curl的-m最大传输时间和--connect-timeout参数防止因为某个节点RPC服务挂起而阻塞整个脚本。jq -r .result用于从返回的JSON中提取result字段的值。示例Hyperledger Fabric Peer节点通过CLI假设你已经通过SSH登录到了Peer节点所在服务器并且环境变量配置正确。# 函数通过Peer CLI获取通道信息中的区块高度 # 参数$1 - 节点IP, $2 - 通道名称如 mychannel get_block_number_fabric() { local node_ip$1 local channel_name$2 local ssh_userroot # 这条命令需要在Peer容器内或配置好CLI的环境中执行 local commandpeer channel getinfo -c ${channel_name} 2/dev/null | grep Block chain info | awk -F {print \$4} | tr -d , local block_height$(ssh ${ssh_user}${node_ip} $command) if [[ $block_height ~ ^[0-9]$ ]]; then echo $block_height return 0 else echo N/A return 1 fi }3.3 结果汇总与格式化输出采集完所有数据后我们需要一个漂亮的展示。在Shell中printf命令是制作表格的利器。# 打印表头 printf -----------------------------------------------------------------------\n printf | %-15s | %-10s | %-10s | %-12s | %-14s |\n 节点(IP) 进程状态 磁盘(/data) 内存使用率 区块高度 printf -----------------------------------------------------------------------\n # 假设我们已将数据收集到关联数组或临时文件中这里演示循环 for node_ip in ${!NODES[]}; do node_role${NODES[$node_ip]} # 调用之前定义的函数获取数据实际脚本中这些值应提前计算好存储起来 proc_status$(check_process $node_ip fisco-bcos) # 示例进程名 disk_status$(check_disk $node_ip /data) # 假设内存使用率已获取到变量 mem_usage # 假设区块高度已获取到变量 block_height printf | %-15s | %-10s | %-10s | %-12s | %-14s |\n \ ${node_ip}(${node_role}) \ $proc_status \ $disk_status \ $mem_usage \ $block_height done printf -----------------------------------------------------------------------\n\n3.4 健康度总结与简单告警在表格输出后脚本应该给出一个明确的结论。# 健康度总结 echo 健康度总结 total_nodes${#NODES[]} healthy_nodes0 warning_nodes0 critical_nodes0 # 根据之前检查的返回值假设存储在某个数据结构中来计数 # 这里用伪代码逻辑表示 for status in ${all_statuses[]}; do case $status in 0) ((healthy_nodes)) ;; 1) ((warning_nodes)) ;; 2) ((critical_nodes)) ;; esac done echo 总计节点数: $total_nodes echo -e 健康节点: ${GREEN}$healthy_nodes${NC} echo -e 警告节点: ${YELLOW}$warning_nodes${NC} echo -e 异常节点: ${RED}$critical_nodes${NC} # 如果有异常节点输出详细信息 if [[ $critical_nodes -gt 0 ]]; then echo -e \n${RED}!!! 发现异常节点请立即处理 !!!${NC} # 这里可以遍历输出具体是哪些节点、什么问题 fi4. 脚本的健壮性、可维护性与高级技巧一个只能在自己电脑上跑的脚本是玩具一个能在复杂比赛环境中稳定运行的脚本才是作品。以下是提升脚本工业级水准的几个关键点。4.1 错误处理与超时控制网络请求和远程命令执行充满不确定性。必须为每一处可能失败的地方设计兜底策略。为SSH和Curl设置超时如前所述ConnectTimeout、-m参数至关重要。命令执行状态检查ssh命令执行后检查其返回值$?。ssh userhost “command” if [ $? -eq 0 ]; then echo “命令成功” else echo “命令失败可能原因网络、权限、命令不存在” # 记录到日志或使用默认值 fi使用临时文件记录中间状态对于需要汇总的信息可以先将每个节点的检查结果写入一个临时文件或变量最后统一输出。即使中间某个节点检查失败也不影响整体流程只是该节点数据显示为“获取失败”。4.2 配置与代码分离不要把节点IP、端口、阈值、SSH用户等硬编码在脚本主体里。应该将这些易变的信息放在脚本开头或者更好的是放在一个单独的配置文件中如monitor.conf然后用source命令加载。# 在脚本中 CONFIG_FILE./monitor.conf if [[ -f $CONFIG_FILE ]]; then source $CONFIG_FILE else echo “配置文件不存在使用默认值” declare -A NODES([“127.0.0.1”]“peer”) WARNING_DISK80 fi这样当评委要求你监控另一套环境时你只需要修改配置文件而无需动核心代码。4.3 日志记录功能监控脚本不能只把结果输出到屏幕。应该将每次运行的结果特别是异常信息记录到日志文件中便于事后分析。可以使用简单的重定向或者更专业的logger命令。LOG_FILE“/var/log/blockchain_monitor.log” exec “$LOG_FILE” 21 # 将脚本后续所有输出包括错误追加到日志文件 echo “ $(date) 监控开始 ” # ... 脚本主体 ... echo “ $(date) 监控结束 ”4.4 性能优化考虑如果节点很多串行执行SSH检查会非常慢。可以考虑使用并行执行来大幅缩短脚本运行时间。# 使用 和 wait 实现简单并行 for node_ip in “${!NODES[]}”; do ( check_single_node “$node_ip” “/tmp/result_${node_ip}.tmp” ) done wait # 等待所有后台任务完成 # 然后收集所有临时文件的结果进行汇总这里将每个节点的检查任务放到后台执行所有任务同时进行最后再统一收集结果。注意并行执行会增加系统负载且输出顺序可能混乱需要妥善处理结果收集。5. 国赛实战中的常见问题与排查技巧根据我带赛和评审的经验选手在实现监控脚本时90%的问题出在以下几个方面。5.1 SSH免密登录配置失败这是最大的“拦路虎”。问题通常出在权限上。症状脚本执行时卡住或提示“Permission denied”。排查在监控机上执行ssh -v usertarget_ip查看详细连接过程。检查~/.ssh目录权限必须是700 (drwx------)。~/.ssh/authorized_keys在目标服务器上的权限必须是600 (-rw-------)。检查目标服务器SSH配置(/etc/ssh/sshd_config)确保PubkeyAuthentication yes和AuthorizedKeysFile .ssh/authorized_keys已启用。技巧在比赛环境初始化时就把配置SSH免密登录作为第一项任务并写一个简单的测试脚本验证所有节点连通性。5.2 区块链RPC接口无法访问症状获取区块高度返回空或“N/A”。排查检查端口先用telnet node_ip rpc_port或nc -zv node_ip rpc_port测试端口通不通。检查服务登录到节点服务器用ps aux | grep [进程名]确认节点进程在运行。检查监听地址很多区块链节点的RPC服务默认只监听127.0.0.1。你需要修改其配置文件如FISCO BCOS的config.ini中的[rpc]部分的listen_ip将其改为0.0.0.0或本机内网IP才能被其他机器访问。这是非常常见的配置遗漏点检查防火墙确保服务器防火墙如iptables、firewalld开放了RPC端口。5.3 命令解析错误症状awk或grep提取的数据不对或者脚本在某个节点执行后中断。排查先手动执行把脚本中那行复杂的管道命令例如df -h /data | tail -1 | awk ‘{print $5}’ | tr -d ‘%’单独拿出来在目标服务器上手动执行看输出是否符合预期。处理边界情况考虑df命令输出可能因为挂载点不存在而只有一行考虑ps输出在不同Linux发行版下的格式差异你的命令是否足够健壮使用set -x调试在脚本开头或怀疑出问题的函数前加上set -x运行时会打印出每一行执行的命令及其参数非常利于调试。5.4 性能与超时问题症状脚本运行极慢或者总在某个节点超时。排查与优化减少SSH连接次数这是最大的性能瓶颈。不要为检查进程、磁盘、内存分别SSH一次。可以写一个远程检查脚本一次SSH执行所有检查命令并将结果以特定格式如JSON返回。主脚本只需调用一次SSH。合理设置超时根据网络状况调整ConnectTimeout和命令超时。内网环境可以设短一点2-3秒公网或复杂网络设长一点5-10秒。使用控制并发如前所述使用并行执行但要注意不要一次性fork太多后台进程可以用xargs -P或自己写一个简单的并发控制逻辑。5.5 表格输出错乱症状输出的表格列对不齐尤其是在中英文混合或颜色代码影响下。技巧使用printf固定宽度%-15s表示左对齐且宽度为15个字符的字符串。这是对齐的基础。处理颜色代码ANSI颜色代码如\033[1;31m会占用终端控制字符但不影响字符串的“逻辑长度”。printf在计算宽度时会把这些控制字符也算进去导致错位。一个解决办法是在计算列宽时先将带颜色的字符串赋值给变量输出时直接使用该变量而printf的格式控制符只用于其他无颜色的部分。更高级的做法是使用类似column -t的命令进行后期格式化但依赖外部命令。6. 超越基础让脚本在国赛中脱颖而出的思路如果只实现基本功能可能只能拿到及格分。要想获得高分你需要展示出更深层次的思考和工程能力。思路一实现动态发现不要硬编码节点列表。能否让脚本自动发现网络中的区块链节点例如通过扫描特定端口范围如30300-30399用于P2P8545用于RPC或者读取区块链平台自身的配置文件如FISCO BCOS的nodes.json来动态构建监控列表。这体现了自动化运维的思想。思路二增加历史趋势与简单分析本次检查的区块高度是1000上次是999这说明块高在增长网络是活的。你的脚本可以增加一个功能将本次监控的关键指标如各节点块高、磁盘使用率与上一次运行的结果进行对比并计算出变化量如“块高增长10 blocks/min”甚至判断增长是否正常例如一分钟没增长可能意味着出块停滞。思路三输出HTML报告命令行表格适合技术人员但评委可能更喜欢直观的报告。你可以让脚本在运行后生成一个简单的HTML页面用不同的颜色和图表可以使用简单的ASCII图表或引入gnuplot来展示状态。这只需要在Shell脚本中拼接HTML字符串并输出到文件即可。思路四集成告警通知除了在终端输出红色告警是否可以集成简单的通知机制例如如果发现严重错误尝试调用一个模拟的Webhook或者发送邮件使用mail命令或curl调用邮件API。在脚本中体现这种“主动告警”的设计会非常加分。思路五编写详尽的帮助文档和注释你的脚本本身就是一个作品。在脚本开头用注释清晰说明其功能、依赖、配置方法、使用示例。关键函数内部也写上注释。这体现了良好的编程习惯和文档意识。评委在审阅时一眼就能看出你的专业素养。最后记住一点国赛中的“监控脚本”题目考察的从来不仅仅是Shell语法。它考察的是你系统性的运维思维、对区块链平台运行机制的深入理解、解决实际问题的工程化能力以及严谨细致的编码习惯。从理解需求、设计架构到编写健壮的代码、处理各种边界情况再到思考如何优化和扩展每一步都在为你加分。希望这份超详细的解析能帮助你不仅写出一个能跑的脚本更能写出一个让评委眼前一亮的高分作品。