很多团队拿到平行链插槽之后,第一件事就是琢磨这个 Collator 节点到底该怎么跑。网上关于 Polkadot 生态的教程大多停在"装个节点同步数据"这一步,真正讲到 Collator 出块、注册、Session Keys、Docker 和 Systemd 两种模式怎么选怎么配的内容很少,零散且容易踩坑。这篇文章基于我自己实际部署和维护 Collator 节点的经验,把从环境准备、节点编译、容器化运行、Systemd 托管到链上注册质押的完整流程串起来,适合手里已经有平行链插槽、准备接入主网或测试网的团队参考,也适合刚接触 Substrate 系区块链、想搞明白 Collator 和普通全节点到底差在哪的开发者阅读。
1. 先搞清楚 Collator 到底在干什么,再动手部署
1.1 从平行链视角理解 Collator 的定位
Polkadot 的中继链本身不执行平行链的业务逻辑,平行链的交易和状态转换发生在各自的链上。为了保证中继链的验证人(Validator)能够安全地确认平行链区块,必须有一个角色负责"打包候选区块 + 生成状态转换有效性证明",然后把候选区块连同证明一起提交给中继链验证人。这个角色就是 Collator(收集人)。
很多文档把 Collator 类比成"平行链的出块节点",这个说法严格来说不够准确。平行链的最终有效区块是由中继链验证人确认后写进中继链的,Collator并不直接产出"最终确认"的区块。你可以把它理解成"带着提案去上会的人":Collator 开会前准备好候选方案和全部支撑材料(有效性证明),验证人审核通过后,方案才正式生效。没有 Collator,平行链就没人提交候选区块,自然也就无法出块。
Collator 的全节点身份和出块身份是两位一体的。它必须同步中继链的全量数据,同时维护平行链自身的全节点数据,还需要在本地执行 Wasm 运行时来构建区块、生成有效性证明。这意味着 Collator 的机器负载比普通验证人的 RPC 节点更高,尤其是 CPU 和内存,因为每次出块都要在本地跑一遍区块执行逻辑。也正因为如此,Collator 的运维要求和普通全节点完全不同,不能拿一台低配 VPS 硬扛。
1.2 出块流程拆解:从交易池到中继链确认
Collator 的一次完整出块流程大概是这样的:
- 同步最新平行链头(从自己的平行链数据库中)和中继链状态。
- 从平行链交易池中取回待打包交易,按运行时逻辑构建候选区块。
- 在本地执行区块,生成新的状态根(State Root)和相应的有效性证明(Proof of Validity)。
- 如果中继链上当前轮次安排了这个平行链的验证人,Collator 就把候选区块和证明提交上去。
- 验证人验证通过后,候选区块进入可用性(Availability)流程,随后被写入中继链。
这个流程每 6 秒(Polkadot 一个中继链区块的时间约为 6 秒,平行链出块时间由各自链的运行时决定)就会循环一次。所以 Collator 的 CPU 预算很紧张:既要跑中继链节点,又要跑平行链节点,还要在出块窗口内完成区块构建和证明生成。因此部署时的参数调优和资源隔离非常重要,我后面会详细展开。
1.3 Docker 与 Systemd 怎么选:没有银弹,只有适不适合
我见过不少团队在"到底用 Docker 还是 Systemd 跑节点"这个问题上反复纠结。其实两种模式我都跑过,各有各的适用场景,完全没必要互相否定。
| 维度 | Systemd 原生进程 | Docker 容器 |
|---|---|---|
| 进程管理 | systemd 原生托管,Restart、日志、限额都是系统级能力 | 依赖容器 restart 策略和 docker 日志驱动 |
| 环境隔离 | 弱,主机环境变更可能影响节点 | 强,依赖隔离在镜像内,主机环境干净 |
| 版本切换 | 手动替换二进制,回滚简单直接 | 换 tag 重新 create,镜像多占一份磁盘 |
| 调试方便度 | journalctl 直接拉日志,gdb 好挂载 | 需要 exec 进入容器,核心转储路径要小心 |
| 多节点进程 | 一个服务一个进程,职责清楚 | 可以同容器跑多个进程,但不推荐 |
| 系统资源限制 | 通过 Systemd 的 MemoryMax、CPUWeight 控制 | 通过 docker run --memory / --cpus 控制 |
我的建议很简单:如果团队有专职运维、节点数量多、要统一管理配置,选 Systemd;如果团队更偏开发、希望环境一致、经常在 staging 和 production 之间切换,选 Docker。两者不冲突,很多正式团队是外层 Systemd 托管 docker 容器进程,内层容器跑节点,这样既能享受容器化的环境一致,又能用 systemd 统一管理开机自启和失败重启。后面的章节我会把三种方式都写出来,你可以按自己的运维习惯挑选。
2. 环境准备:硬件、系统、端口,一步都别省
2.1 硬件选型建议:别拿测试网的标准跑主网
Collator 的资源消耗主要来自三块:中继链数据同步与验证、平行链数据同步、本地区块执行与有效性证明生成。我根据实际跑下来的观察给一组参考配置,主网和测试网可以对应调整。
| 角色/场景 | CPU | 内存 | 磁盘(NVMe SSD) | 网络 |
|---|---|---|---|---|
| 测试网 Collator | 4 核 | 16 GB | 500 GB | 上下行 100 Mbps |
| 主网 Collator(最低) | 8 核 | 32 GB | 1 TB | 上下行 250 Mbps |
| 主网 Collator(推荐) | 16 核 | 64 GB | 2 TB | 上下行 500 Mbps |
磁盘是最容易忽略的坑。中继链全量状态加上平行链自己的状态,实际占用增速很快。我见过有人用 500GB 跑主网,三个月磁盘就见底了,最后只能紧急迁移数据目录。如果条件允许,直接上 2TB NVMe,宁可多一点富余也别赌磁盘不会涨。另外磁盘 io 必须好,Solidigm 或三星的企业级盘都行,数据库用的是 ParityDB,读写模式是大量随机小文件,机械硬盘完全跑不动。
CPU 方面尽量选支持 SHA-NI 指令集的现代处理器。Substrate 节点在做区块哈希和 Merkle 证明时会用到 SHA256,SWAR 版本的 EVM 执行和 Runtime 执行也依赖这些指令加速。实测同样配置下,支持 SHA-NI 的 CPU 同步速度能快 20% 以上,这不是玄学,是指令集优化。
2.2 系统初始化与基础组件
我自己的服务器统一用的 Rocky Linux 9,和 RHEL 系一脉相承,比较稳。Ubuntu 24.04 LTS 也行,但这里是记录我实际用的环境。
系统层面要做的几件事:
# 创建独立用户,不要用 root 直接跑节点 useradd -m -s /usr/bin/bash polkadot # 安装基础工具 dnf install -y curl wget git htop jq psmisc lsof # 调整系统文件句柄上限 ulimit -n 65536 # 持久化配置 echo "polkadot soft nofile 65536" > /etc/security/limits.d/polkadot.conf echo "polkadot hard nofile 65536" >> /etc/security/limits.d/polkadot.conf为什么不用 root 跑节点?安全是一方面,更重要的是 Substrate 节点如果发现以 root 运行,会有极大概率拒绝启动或者打印高危警告,因为 root 权限对整个数据目录的读写没有约束,一旦被攻破就是整个机器沦陷。用独立用户可以把伤害半径控制在节点数据目录内。
端口方面,默认中继链 P2P 用 30333,平行链如果通过--relay-chain-port指定另一个 P2P 端口,或者使用--port区分。RPC 通常 9933,WS 是 9944。主网部署时这些端口不要全部对公网开放,尤其是 RPC,建议仅绑定内网 IP 或者干脆用 SSH 隧道访问,我下面会详细说。
2.3 网络规划与防火墙配置
Collator 节点必须能被外部节点连接,否则无法参与平行链的候选区块传播。P2P 端口(30333)需要公网可达,防火墙放行 TCP/UDP。但 RPC 和 WS 端口不要暴露在公网,原因很简单:Collator 节点有author_rotateKeys这类敏感接口,如果开了--unsafe-rpc-external且暴露公网,等于把节点的控制权交给所有能访问到的人。
推荐的做法是:
# 仅放行 P2P 端口 firewall-cmd --permanent --add-port=30333/tcp firewall-cmd --permanent --add-port=30333/udp firewall-cmd --permanent --add-port=30334/tcp firewall-cmd --permanent --add-port=30334/udp # 如果平行链单独映射 firewall-cmd --reload # RPC/WS 端口只绑定内网 # 在节点启动参数中写 --rpc-external 但配合 bind 内网地址 # 或者干脆不加 --rpc-external,只从本机通过 SSH 隧道访问RPC 访问我又踩过一个大坑,就是--rpc-methods=unsafe开起来后忘了关,结果节点被内网其他服务扫到,被调用author_rotateKeys拿到了新的 session keys,导致注册地址被换掉。这属于安全事件级别的问题。正确的做法是,只在注册 Session Keys 那几分钟内临时开--rpc-methods=unsafe,注册完立刻改回--rpc-methods=safe并重启节点。
3. Systemd 完整部署:从编译到守护进程的每一步
3.1 获取节点二进制:编译还是直接下载 release
Polkadot 生态的平行链节点一般是基于 Substrate 的polkadot-parachain二进制,不同平行链可能会有自己的分支和 tag。我在部署时优先选择官方 release 提供的预编译二进制,省时省心。编译虽然可控,但耗时非常长,一台 16 核机器编一个 release 版也要 30-60 分钟,而且依赖链版本对不上很容易编译失败。
# 直接下载 release 二进制(以某个平行链 v1.2.0 为例) wget https://github.com/paritytech/polkadot-sdk/releases/download/polkadot-v1.12.0/polkadot-parachain chmod +x polkadot-parachain mv polkadot-parachain /usr/local/bin/如果确实要编译,注意版本锁定:
git clone https://github.com/paritytech/polkadot-sdk cd polkadot-sdk git checkout polkadot-v1.12.0 cargo build --release -p polkadot-parachain-bin编译需要提前准备好 nightly Rust 工具链和 WebAssembly 编译目标,这个在官方文档里有写。没特殊需求就别自找麻烦,直接下载 release。
下载后先跑一次polkadot-parachain --version确认能执行,然后验证是否带上了--collator子命令。有些链的运行时版本较老,可能默认编译的是无 collator 特性的二进制,要看节点是不是真的能切到--collator模式。
3.2 数据目录初始化与链规格文件
Collator 需要两个数据目录:一个给中继链(Rococo 或 Kusama/Polkadot),一个给平行链自己。Substrate 节点会把两者放在同一个 base-path 下,通过--chain和--parachain-id区分目录结构。实际占用的目录在 base-path 会看到polkadot(中继链)和para-1000(平行链 ID)这样的子目录。
初始化这一步通常不是必须的:节点启动后会自动从创世区块开始同步,不需要像 PoW 链那样先下载 snapshot。但如果使用 warp sync,需要保证数据目录干净,否则会报错。我这里的做法是提前把数据目录和权限准备好,避免启动后才发现权限问题:
mkdir -p /data/parachain chown -R polkadot:polkadot /data/parachain链规格文件(chain spec)可以从平行链官方仓库拿到,通常是 raw 格式。注册时要注意 raw 格式和 JSON 格式的区别,节点启动--chain参数接收 raw 文件路径,不能直接拿 JSON 格式的规格硬跑。
3.3 编写干净的 Systemd Unit:参数逐个说清楚
下面是完整的 Systemd Unit 文件,我把关键参数逐项拆开解释。这个文件我压了很多坑在里面,直接复制的话大概率能跑通。
[Unit] Description=Polkadot Parachain Collator Node After=network-online.target Wants=network-online.target [Service] User=polkadot Group=polkadot EnvironmentFile=/etc/polkadot/collator.env ExecStart=/usr/local/bin/polkadot-parachain \ --chain /etc/polkadot/chain-spec-raw.json \ --collator \ --name "MyTeamCollator01" \ --base-path /data/parachain \ --port 30333 \ --relay-chain-port 30334 \ --rpc-port 9933 \ --ws-port 9944 \ --prometheus-port 9615 \ --execution=wasm \ --database=ParityDb \ --sync=warp \ --pruning=archive \ --rpc-methods=safe \ --state-cache-size 67108864 \ --trie-cache-size 67108864 Restart=on-failure RestartSec=15 TimeoutSec=300 KillSignal=SIGTERM LimitNOFILE=65536 MemoryMax=32G MemoryHigh=24G [Install] WantedBy=multi-user.target这里有几个参数值得单独拿出来说。
EnvironmentFile是我的习惯用法。把部分参数(比如链名、BP 账户、硬编码值)放进环境变量文件,这样改配置的时候不用编辑 Unit 文件本身,也方便集中管理敏感信息和易变参数。文件内容类似:
CHAIN=/etc/polkadot/chain-spec-raw.json NAME=MyTeamCollator01然后在 ExecStart 中引用:--chain ${CHAIN}。Systemd 支持 EnvironmentFile 加载变量,这条链路跑得很顺。注意 ExecStart 中引用的环境变量要写成${VAR}或者$VAR,Systemd 的变量展开方式和 shell 有点区别,我用--name ${NAME}这种写法实测没问题。
--execution=wasm这个参数在 Collator 上要格外留意。默认情况下,节点优先用本机原生代码执行 Runtime,如果本机没有对应 Runtime 的原生实现,或者原生实现和链上 Wasm 版本不一致,就会出现状态分歧。Collator 因为要在本地构建区块并生成有效性证明,必须保证执行结果和链上一致,所以强制--execution=wasm最稳妥。虽然性能比原生慢一点,但正确性优先。
--sync=warp是快速同步模式。第一次启动建议用 warp,它只下载区块头和最新的状态快照,能几小时内追到最新高度。后续持久运行会把缺失的历史区块慢慢补齐。但有一个限制:如果平行链要求 archive 节点提供历史状态查询,warp 同步的初始状态可能不够全,需要配合--pruning=archive并在追上链头后关掉 warp 做完整补齐。我实战中直接--sync=warp+--pruning=archive跑,追到最新后没有遇到历史查询问题,但你要是做区块浏览器或者 RPC 服务,建议还是全量同步更保险。
--database=ParityDb值得所有 Collator 用。ParityDb 是 Substrate 生态新的默认存储引擎,比 RocksDb 占用更少磁盘、写放大更小。我实测两个引擎在同样数据量下,ParityDb 能省接近 30% 的磁盘空间,同步速度还更快。如果你已经在 RocksDb 上同步了一半,不建议直接切,因为存储格式不兼容,需要重新同步。
MemoryMax=32G和MemoryHigh=24G是 Systemd 的内存软硬限制。我给的是 32G 内存机器上的配置,软限制是 24G,超过 24G 时系统会尽量回收匿名页,超过 32G 直接触发 OOM Kill 保护机制。如果你机器是 16G,把这两个值改成 12G/16G 就好。注意不要设得太紧,否则节点在构建有效证明的内存尖峰期可能被杀掉。
3.4 启动、日志与状态验证
启动服务并设置开机自启:
systemctl daemon-reload systemctl enable polkadot-collator systemctl start polkadot-collator日志查看和状态验证:
journalctl -u polkadot-collator -f -n 200 systemctl status polkadot-collator curl -s http://localhost:9933 -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","method":"system_health","params":[],"id":1}'system_health返回中有一个peers字段,正常情况下节点会有 5-30 个对等节点,如果一直是 0,说明防火墙或者 P2P 端口没有打通。还有一个isSyncing字段,刚启动时为 true,等追上链头后变 false。
另外提一句,启动初始阶段中继链 warp 同步会疯狂下载状态数据,日志里会出现大量[Relaychain] Imported、Syncing信息,这时候不需要任何干预。我见过有人看到Warp sync is in progress就以为卡住了,其实等它跑完就好了。
4. Docker 部署完整流程:容器化也有自己的坑
4.1 镜像选择与数据卷规划
Docker 部署首先要解决镜像来源。大部分平行链团队会把编译好的节点镜像推到 Docker Hub 或者 GitHub Container Registry。我用的是自己构建的镜像,因为团队里有的链节点需要灌入额外的 Runtime 补丁,直接拉官方镜像不一定对上版本。
Dockerfile 大概长这样:
FROM ubuntu:22.04 RUN apt-get update && apt-get install -y ca-certificates curl && \ rm -rf /var/lib/apt/lists/* COPY polkadot-parachain /usr/local/bin/polkadot-parachain COPY chain-spec-raw.json /etc/polkadot/chain-spec-raw.json RUN useradd -m -u 1000 polkadot USER polkadot VOLUME ["/data"] EXPOSE 30333 30334 9933 9944 9615 ENTRYPOINT ["/usr/local/bin/polkadot-parachain"]这里有个容易被 Docker Desktop 误导的点:容器内不要用 root 身份跑节点,镜像里要显式创建用户并切换到它。Substrate 节点对 root 用户同样会打印警告甚至拒绝启动,和 Systemd 模式的原因一致。
数据卷规划上,把整个/data目录挂载出来,里面会同时存在中继链和平行链两个目录。Docker 模式下容器层写数据是不可接受的,因为容器一旦删除重建,数据就全没了。所以 docker run 的-v参数是生命线。
4.2 docker run 完整参数与限制选项
docker run -d --name collator \ --restart unless-stopped \ --cpus=8 \ --memory=32g \ --log-opt max-size=500m \ --log-opt max-file=3 \ -p 30333:30333/tcp \ -p 30333:30333/udp \ -p 30334:30334/tcp \ -p 30334:30334/udp \ -p 127.0.0.1:9933:9933 \ -p 127.0.0.1:9944:9944 \ -p 9615:9615 \ -v /data/parachain:/data \ -e RUST_LOG=info \ myorg/parachain-collator:latest \ --chain /etc/polkadot/chain-spec-raw.json \ --collator \ --name "MyDockerCollator01" \ --base-path /data \ --port 30333 \ --relay-chain-port 30334 \ --rpc-port 9933 \ --ws-port 9944 \ --prometheus-port 9615 \ --execution=wasm \ --database=ParityDb \ --sync=warp \ --pruning=archive \ --rpc-methods=safe \ --state-cache-size 67108864 \ --trie-cache-size 67108864端口这里我特意做了一件事:RPC 端口映射只绑定127.0.0.1,而不是0.0.0.0。容器内 RPC 仍然监听 9933,但宿主机上只有本机能访问,从公网完全扫不到。需要远程 RPC 时就 SSH 隧道连宿主机端口,比直接暴露安全得多。
日志驱动加上了--log-opt max-size=500m和--log-opt max-file=3,这是很多人容易忽略的坑。Docker 默认的 json-file 日志驱动不限制大小,Collator 这种高频日志服务,跑一周可能攒几十 GB 的日志文件。我见过最夸张的一次,日志占掉了整块数据盘,导致节点直接 OOM。这个参数加进去就可以从源头控制日志膨胀。
--memory=32g给容器设置的是硬限制,超过这个值容器会被 OOM Kill。这里要注意 Docker 的内存限制和 Systemd 的 MemoryMax 语义略有不同,Docker 限制的是 cgroup 的内存上限,而 Systemd 的 MemoryMax 同样基于 cgroup,两者都有效,只是实现层级不一样。如果外层用 Systemd 管理容器进程,可以在 Systemd 的 Unit 里再套一个 MemoryMax,形成双保险。
4.3 Docker 容器 + Systemd 外层托管组合玩法
Docker 容器默认有--restart unless-stopped策略,容器崩溃会自动重启,理论上不需要 Systemd 再来管一层。但容器内进程异常退出时,Docker daemon 自己会重启它,如果你外面再套 Systemd 的 Restart=always,就可能产生"双重重启"的竞争条件,有时容器还没拉起来 Systemd 又给它停了,很烦。
我实测下来比较稳的玩法是:容器启动参数里不加--restart,由外层 Systemd 负责重启容器本身。这样如果容器内节点崩溃,Docker 会先把容器状态标记为 Exited,Systemd 感知到服务失败后重新执行docker start collator,整个生命周期循环受 Systemd 管理,日志也更统一地落入 journalctl。
[Unit] Description=Parachain Collator Docker Container After=docker.service Requires=docker.service [Service] User=root ExecStartPre=/usr/bin/docker start collator ExecStart=/usr/bin/docker attach collator ExecStop=/usr/bin/docker stop collator Restart=on-failure RestartSec=15 [Install] WantedBy=multi-user.target这个玩法的好处是重启策略完全收敛到 Systemd 一个地方,坏处是需要保证docker start是幂等的(容器已经启动的话会报错,但 ExecStartPre 失败会导致服务启动失败)。为了避免这个坑,更简单的方案是只要容器自身的 restart 策略就够了,不需要套 Systemd。写出来的目的是告诉你两种方式怎么取舍,没有必须怎样。
5. 注册 Collator:Session Keys 与质押配置实战
5.1 节点跑起来之后:如何从"全节点"变成"出块节点"
很多人在这里会卡住:节点明明启动成功了,中继链也同步了,为什么平行链还是没有块?原因很简单——你还没有在链上注册成为该平行链的 Collator。
注册的前提有三件事:第一,平行链 Collator 候选名单(CollatorSelection)里有你的账户;第二,你的节点已经获得了 Session Keys,并且绑定了这个 Keys;第三,你质押了足够的代币作为保证金。
CollatorSelection 是平行链运行时里的一个 pallet,不同平行链可能有自己的治理方式和入池门槛,有些链需要先通过链上治理提案加入候选名单,有些链直接调用collatorSelection.registerAsCandidate就可以。这个过程在测试网上比较宽容,主网上通常要等选举周期结束并质押足额代币。
5.2 获取节点 Session Keys 并完成映射
获取 Session Keys 的方法有两种:author_rotateKeys和author_insertKey。author_rotateKeys会生成一组全新的 keys 并自动写入节点 keystore,返回一个十六进制字符串,这个字符串就是需要注册到链上的 Session Keys。
curl -s http://127.0.0.1:9933 -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","method":"author_rotateKeys","params":[],"id":1}'返回的 JSON 中 result 字段就是 keys,类似0x...。拿到后去链上调用session.setKeys、传入 keys 和空 proof(有的链要求 proof),然后广播交易。
这里一定要注意:调用author_rotateKeys之前,节点必须已经运行了一段时间且区块高度已经追上链头,否则 keys 可能无法被网络正确验证。我遇到过在同步中途调用,结果 keys 注册成功但节点出块时发现签名不匹配,最后只能重新 rotate 一次,白白浪费一个 session 周期。
5.3 质押代币与 CollatorSelection 状态确认
在 CollatorSelection pallet 里,通常会有一个candidateExists或者isCandidate查询接口,你需要这些查询来确认账户已经在候选列表中。质押的数量因平行链而异,有的链要求几万到几十万个原生代币,有的链接受中继链代币作为保证金,具体看运行时设计。
我建议在主网上正式质押前,先在测试网完整跑一遍流程:注册、质押、等待 session 轮换、确认出块。测试网的参数和主网越接近越好,不然等你上了主网发现保证金不足或参数不对,又要重新发起交易,又慢又贵。
有一个细节值得注意:Collator 的 Session Keys 绑定的是节点账户,但质押的保证金通常冻结在候选账户(Candidate Account)里。这两个账户可以分开,你可以用一个冷钱包质押,用一个热账户跑节点,之间通过session.setKeys和collatorSelection.setInvulnerables(如果有管理员权限)联动。不过 Collator 出块奖励通常直接打给节点账户,所以热账户还是要保管好。
5.4 注册成功后的验证方法
注册并质押成功后,怎么判断自己真的在出块?几个检查点:
- 查看平行链是否有新的区块头产生,可以通过中继链浏览器找到该平行链的最新区块高度,对比你本地节点的同步高度是否一致。
- 查看节点日志里是否出现
Prepared block for proposing和Proposed block之类的信息。 - 通过 Polkadot 生态的 Telemetry 服务搜索节点名称,看看是不是有
authority标记。
日志是关键,这里贴一段我在主网实测可以看到的输出模式:
2024-06-11 12:00:01 [Parachain] 💤 Idle (24 peers), best: #123456 (0x1234...), finalized #123455 (0xabcd...) 2024-06-11 12:00:03 [Parachain] ♻️ Preparing a proposal for block 123457... 2024-06-11 12:00:04 [Parachain] 🔥 Prepared block for proposing at height 123457 (0 ms) with 30 transactions.如果一直卡在Preparing a proposal但始终不进入Prepared,大概率是 Wasm 执行超时或者本机资源不足。如果日志连Preparing都没有,说明你还没有被调度到出块,检查候选名单是否生效、session keys 是否绑定成功。
6. 常见问题排查与日常运维记录
6.1 节点状态巡检:每天看这几项就够了
Collator 的日常巡检并不复杂,我习惯每天早上写个脚本,把这几个指标拉一遍:
- 中继链 peer 数:
system_health的 peers 字段。 - 平行链本地高度 vs 最新高度:
chain_getHeader对比,超过 10 个区块落后就需要关注。 - 是否在出块:最近 10 分钟日志里有没有
Prepared block。 - 磁盘与内存:
df -h和数据目录增长速率。 - 进程是否活跃:systemd 服务状态和进程 CPU 占用。
我把这些指标接入了 Prometheus,节点本身的--prometheus-port 9615提供了很多内部指标,包括交易池大小、同步状态、keystore 状态等,比单纯看日志强得多。Grafana 上配个简单的看板,10 分钟扫一眼就能确认节点健康。
6.2 经典故障实录:磁盘爆满、同步滞后、OOM 连环坑
我先讲一个最典型的案例。某个平行链的 Collator 在我电脑上跑了两个月之后,突然有一天出块延迟持续拉大,从 6 秒一个块变成 3 分钟一个块。我看日志没有报错,但磁盘使用率已经 97%。Collator 节点每次出块要把候选区块写入本地数据库,磁盘接近满时写入延迟飙升,直接拖垮出块节奏。当时我立刻清理了旧的 warp sync 临时文件,把日志驱动上限调低,又删了两个没有用的容器镜像,勉强救回了一条命。这块磁盘最后我还是换了 2TB,彻底解决。
第二个常见问题是从 warp 同步切到正常同步后,节点一直报状态根不匹配。这是因为 warp 同步的初始状态只恢复了最新状态切片,没有恢复完整的历史状态,但--pruning=archive又要求全量历史。我的解决办法是:先只跑--sync=warp追到链头,确认状态一致后,再在启动参数中去掉--sync=warp,让节点用正常模式补齐缺失的历史区块。这个过程比较耗时,但在数据完整性和性能之间是合理的折中。
第三个问题是 OOM。有一段时间我偷懒没给节点设置任何内存限制,结果某次改进了本地构建区块的逻辑,内存尖峰直接爆掉了 32G 机器的物理内存,整个节点被杀。从那以后我给所有节点都加了内存限制。注意限制不能太紧,我给 32G 机器用 28G 的软限制,给 64G 机器用 48G 的软限制,留出足够余量给页面缓存。
6.3 版本升级与迁移:老节点数据如何平滑过渡
Polkadot 生态的节点升级频率不低,尤其是平行链运行时升级时,节点头通常也需要同步升级。我升级节点的习惯是:先在测试网跑一遍新版本,确认无异常后,生产环境择机操作。
升级步骤如果是 Systemd 模式:停服务,备份旧二进制,覆盖新二进制,启动服务,看日志确认导入正常。如果是 Docker 模式:拉新镜像,换容器 tag 重建数据卷挂载。数据目录完全不变,只是二进制替换,一般几分钟就能完成。
迁移服务器时,数据目录可以直接 rsync。注意 rsync 的时候节点必须停止,不然数据库文件处于不一致状态。还有个细节,rsync 大目录时用-av --partial --progress,中途断了能接着传。我迁过一次 1.2TB 的数据,千兆网跑了 3 小时,全程没有出现问题。
迁移完成后,启动节点前把数据目录权限改回来,确保用户归属正确。启动后节点会先重新校验数据库,可能花点时间,别看到卡住就慌。
6.4 让 Collator 一直稳跑的几个注意事项
最后把这些经验浓缩成几条注意事项,都是我在生产环境踩过坑之后总结的:
- 日志别散着存。Systemd 模式用 journald 统一管理,Docker 模式一定设置 max-size/max-file,不要把日志写到数据盘同一分区,至少分区隔离。
- 数据盘独立。系统盘(/)和数据盘(/data)分开,数据盘满了不会拖垮系统进程。
- 永远不要直接改链上参数。Collator 节点的
--chain参数指向的链规格文件如果更新,要仔细核对新老版本的共识差异,改错了会导致分叉。 - 写监控脚本,别只靠人肉巡检。至少把端口连通、进程存活、区块同步滞后这三个指标监控起来,异常立刻报警。
- 不要用最低配硬件跑主网。CPU 和内存的富余直接决定出块稳定性,尤其在网络高峰期或链上活动频繁时,硬件不足很快就露馅。
我个人在实际操作中的体会是,Collator 节点的部署并不难,真正拉开差距的是细节。同在一条平行链上,有人能用一台 8 核 32G 的机器稳定出块,有人给了 16 核 64G 还是掉块,关键差异基本都出在参数调优、日志管理、数据目录规划和升级节奏上。只要把这篇里提到的这些点都处理好,你的 Collator 大概率能稳稳当当跑很久。我也会继续在我自己维护的节点上验证这些配置在更多平行链上的表现,有新的经验再回来补充。