入职 Web3 运维日记 · 第 10 日:终极考核 —— 混沌工程 (Chaos Engineering) 与区域级容灾

📅 发布时间:2026/7/4 12:24:44 👁️ 浏览次数:
入职 Web3 运维日记 · 第 10 日:终极考核 —— 混沌工程 (Chaos Engineering) 与区域级容灾
时间入职第 10 天下午 02:00天气晴由于服务器房冷气太足感觉有点冷事件CTO 发起的突袭式演练 (Fire Drill)下午两点我正盯着 Grafana 看板上平稳的曲线发呆。 CTO 和基础设施负责人Head of Infra突然走到了我身后。CTO 笑着说“Alen前几天你搭节点、配监控、搞安全、防夹子做得都不错。你的架构图画得很漂亮号称是高可用 (HA) 的。” 我点点头“是的基于 AWS 多可用区 (Multi-AZ) 设计的。”CTO 拿出了他的笔记本电脑打开 AWS 控制台指着我那台正在跑生产流量的主节点Geth-Primary (ap-southeast-1a)。 “如果我现在把这台机器Terminate (销毁)了公司业务会挂多久”我愣了一下“这是生产环境……” CTO 手指悬在鼠标上“在 Web3真正的故障从来不分环境。你有 5 分钟准备时间。5 分钟后我会手动模拟可用区 A (Zone A) 级大断网。”这就是第 10 天的终极考核人为制造灾难。 1. 下午 02:05第一刀 —— 核心节点“暴毙”我迅速打开了我的备用终端确认我的Warm Standby (热备)节点状态。Node A (Primary): 位于 Zone A处理 100% 流量。Node B (Standby): 位于 Zone B实时同步中Nginx 权重为 0备用。CTO 没有手软直接点击了[Terminate Instance]。 瞬间Node A 的 SSH 连接断开。 Grafana 上Node A 的各项指标Peer Count, Block Height呈断崖式下跌至 0。Nginx 层的反应我之前配置的 Nginx 主动健康检查 (Active Health Check) 开始报错。# Nginx Error Log [error] ... upstream server 172.31.10.100:8545 is down自动切换逻辑我的 Nginx 配置里有这样一段upstream geth_backend { server 172.31.10.100:8545 max_fails3 fail_timeout5s; # Primary server 172.31.20.100:8545 backup; # Standby (平时不接客老大挂了才接) }仅仅过了3 秒钟Nginx 发现 Primary 死了自动激活了backup标记的 Node B。业务表现Scanner 组长在群里喊了一句“刚才好像有两个请求超时报错了但马上又好了。你们在发布吗” 我回复“没事继续跑。”第一关 Pass。读请求 (Read Ops) 几乎无感切换。 2. 下午 02:30第二刀 —— 签名服务断连CTO 见节点切换成功并没有停手。 “节点活着只能查账。如果Redis (Nonce 计数器)所在的主机也挂了呢提现还能发出去吗”他模拟了 Redis 主节点宕机。 我们在 Day 6 为了解决 Nonce 冲突引入了 Redis。如果 Redis 挂了Nonce 就会乱序提现就会卡死。AWS ElastiCache 的表现我使用的是AWS ElastiCache (Cluster Mode Disabled)配置了Multi-AZ 自动故障转移。现象提现服务开始大量报错Connection Refused。持续时间大约25 秒。恢复AWS 自动将位于 Zone B 的从节点 (Replica) 提升为新的主节点 (Master)并更新了 DNS 记录。Alen 的补救 (Retry Policy) 虽然 AWS 自动恢复了但这 25 秒的报错怎么办 我之前在提现服务的代码里强制要求开发加了指数退避重试 (Exponential Backoff)# 提现微服务伪代码 def get_nonce(): for i in range(5): try: return redis.incr(nonce) except ConnectionError: sleep(2 ** i) # 等待 1s, 2s, 4s...正是这个重试机制扛住了那 25 秒的 DNS 切换窗口。没有任何一笔提现请求彻底失败。第二关 Pass。写请求 (Write Ops) 有短暂延迟但数据未丢失。☠️ 3. 下午 03:00第三刀 —— 验证者 (Validator) 的生死抉择这是最惊险的一关。 CTO 问“你的Lighthouse 验证者节点(负责给以太坊网络出块赚钱) 也在 Zone A。现在它挂了你要不要在 Zone B 启动备用的验证者”Alen 的回答“绝对不要坚决不启动”CTO 挑了挑眉“哦为什么你想漏块 (Missed Block) 吗”Alen 的解释“漏块顶多损失一点收益0.05 ETH。 但如果我启动了备用验证者而 Zone A 的原节点其实没有死透只是网络分区它还在那边偷偷签名那么全网就会出现两个我签名的区块。 这叫双重签名 (Double Signing)。 后果是Slashing (罚没)我会瞬间被没收32 ETH并被踢出网络。在验证者运维中Safety (不被罚) Liveness (不漏块)。”CTO 满意地点头“很好。很多新人为了追求 100% 在线率搞了自动验证者故障转移结果把自己搞破产了。” 4. 下午 04:30灾后重建 (IaC)演练结束。Zone A 的废墟还在那儿。 我需要把环境恢复原状。如果是以前我要手动去申请 EC2手动装 Geth手动同步数据。 但现在我有Terraform。操作实录检测Terraform 发现aws_instance.geth_primary状态为terminated。修复terraform apply执行Terraform 自动申请了一台新的 EC2。自动挂载了之前做过快照的io2数据盘数据没丢。UserData 脚本自动拉起 Geth 和 Prometheus Exporter。归位新节点启动后同步了最近几十分钟的区块。我手动在 Nginx 里把它改回 Primary流量切回主可用区。一切就像什么都没发生过一样。 Day 10 总结CTO 合上电脑拍了拍我的肩膀“Alen恭喜转正。你的系统扛住了‘拔网线’。”回顾这 10 天搭建从零拉起 Geth/Lighthouse。安全Nginx 反代与防火墙。监控Prometheus 飞书告警。升级EBS 快照蓝绿部署。钱包KMS 签名与 Nonce 管理。数据归档节点与 Trace 路由。博弈Flashbots 防夹与 MEV 创收。共识Finalized 确认数与 Reorg 防御。容灾Day 10 的多可用区切换。Alen 的最终感悟“Web3 运维很难因为你要懂密码学、博弈论、金融风控。 Web3 运维也很简单因为去中心化本身就是最好的高可用。我们不是在维护一台服务器我们是在维护一个资产高达数千亿美金的分布式账本的一个接入点。 敬畏技术敬畏风险敬畏每一行 Log。”1. 为什么不用 AWS ALB (Application Load Balancer)非要自己折腾 NginxAlen 的回答在 Day 10 这种灾难恢复场景下ALB 确实看起来更省事。但结合 Day 4、Day 7、Day 8 的需求ALB 是完全不够用的。原因一ALB 是“傻瓜式”的 (Layer 7 HTTP)Nginx 是“智能”的 (Layer 7 Logic)ALB 的能力只能根据 URL 路径 (/api) 或 Host (api.bybit.com) 转发。Nginx 的能力可以解析Request Body (请求体)。回顾 Day 7 8我们需要根据 JSON-RPC 里的method: debug_traceTransaction或method: eth_sendRawTransaction这种内容来决定转发给 Alchemy 还是 Flashbots。这是 ALB 做不到的ALB 看不到 Body 里的 JSON 字段。原因二健康检查 (Health Check) 的深度ALB只要 TCP 端口通了或者 HTTP 返回 200它就认为节点是活的。Nginx Lua我可以写脚本去问节点“你的区块高度是多少”如果节点虽然活着HTTP 200但是高度落后主网 500 个块Nginx 可以认为它“半死不活”从而把流量切走。ALB 做不到这么细。原因三成本与完全控制ALB 是按小时流量收费的黑盒。Nginx 是免费的而且我就装在 Geth 节点本机或者单独的网关机我对它的超时时间、重试策略有 100% 的控制权。2. 指数退避重试 是开发写的代码为什么算在运维 Alen 头上Alen 的回答这是SRE (站点可靠性工程)的核心理念“架构师制定规则开发人员实现规则”。开发者的视角他们关注的是“功能实现”。只要redis.incr()能跑通就行。他们往往假设网络是永远稳定的。运维的视角Alen 知道 AWS 发生主从切换时会有15-30 秒的 DNS 漂移时间。在这段时间内Redis 是不可用的。Alen 的工作Code Review (代码审查)在上线前Alen 会检查代码。如果发现开发没写 Retry 逻辑或者写的是while(true)死循环重试这会把恢复中的 Redis 再次打挂Alen 会拒绝上线。SDK 封装在成熟的大厂运维平台组会提供一个标准的BybitRedisClient里面内置了指数退避逻辑。开发直接调用这个 Client不需要自己写 Retry。所以虽然代码是开发敲的但“必须加重试”这个架构决策是 Alen 下达的死命令。3. 原节点没死透只是网络分区 是什么意思关机了还没死透吗Alen 的回答这是一个极其凶险的分布式系统陷阱俗称“脑裂 (Split Brain)”。情况 ACTO 手动点了 Terminate (关机)这是“死透了”。实例被销毁硬盘被卸载。这时候你在 Zone B 启动备用节点是 100% 安全的。情况 B真实世界的故障 —— 光缆被挖断 (网络分区)想象一下Zone A 的机房依然有电服务器依然在跑Geth 依然在运行。但是连接 Zone A 和 Zone B 之间的光缆断了。Zone B 的视角我看不到 Zone A 了心跳检测失败。Zone B 以为 Zone A 挂了。Zone A 的视角我活得好好的只是连不上 Zone B 了。但我还能连上部分互联网。恐怖后果 (Double Signing)Zone A 的节点继续工作给区块 100 签名。Zone B 的备用节点如果你配置了自动启动认为老大死了自己上位也给区块 100 签名。全网视角以太坊网络收到了两个来自同一个验证者私钥的签名但内容不同。判定这不仅是故障这是攻击企图制造分叉。结论对于验证者节点只要你不能 100% 确认老节点物理销毁了就绝对不能启动新节点。宁可挂机不可双签。4. 为什么会被罚款 (Slashing)Alen 的回答这是以太坊 PoS (权益证明)共识机制的“军法”。规则你想当验证者Validator赚钱你必须先抵押32 ETH(约 6-8 万美金) 作为保证金。红线双重签名 (Double Signing)是最严重的罪行。因为这会破坏区块链的唯一性导致网络分叉。惩罚 (Slashing)立刻没收直接从你的 32 ETH 里扣除一部分比如 1 ETH。强制驱逐你的验证者资格被剥夺踢出网络。慢性失血在被踢出的过程中有个排队期你的余额会持续减少。社会性死亡你的验证者公钥被永远标记为“作恶者”。对比漏块 (Downtime)只是**“少赚工资”**几分钟几块钱。双签 (Double Sign)是**“没收家产”**几万美金瞬间蒸发。运维原则保住本金永远比赚那点小钱重要。5.terraform apply怎么做到的不需要安装 Geth 吗Alen 的回答这就是IaC (Infrastructure as Code)的魔力。Terraform 用的不是 YAML而是HCL (HashiCorp Configuration Language)文件后缀是.tf。为什么不需要手动安装 Geth因为我们用了“黄金镜像 (Golden AMI)”“数据快照 (EBS Snapshot)”。自动化流程揭秘AMI (系统盘镜像)Alen 在入职第 3 天的时候其实做过一件事在一台干净的 EC2 上装好了 Linux Geth Prometheus Exporter Nginx。然后把这台机器制作成了一个 AWS AMI比如叫ami-geth-v1.11.5。这个 AMI 里已经有了软件环境开机就能用。Snapshot (数据盘快照)Day 5 升级时做的那个快照里面有几 TB 的区块数据。Terraform 代码 (main.tf)resource aws_instance geth_node { ami ami-geth-v1.11.5 # 引用做好的系统镜像 instance_type r6g.2xlarge # 启动脚本 (User Data) user_data -EOF #!/bin/bash # 1. 挂载数据盘 mount /dev/nvme1n1 /data # 2. 启动服务 (软件都在 AMI 里装好了) systemctl start geth systemctl start nginx EOF } resource aws_volume_attachment ebs_att { device_name /dev/nvme1n1 volume_id aws_ebs_volume.data_disk.id instance_id aws_instance.geth_node.id }总结 当你敲下terraform applyAWS 启动一台已经装好软件的电脑AMI。AWS 把装满数据的一块硬盘插上去EBS。电脑开机执行 UserData 脚本挂载硬盘启动软件。全程 2 分钟不需要人工 SSH 进去敲任何命令。