FABRKNT
Reth Expert — 本番エンジニアリング
本番エンジニアリング
レッスン 11 / 25·CONTENT18 分40 XP
コース
Reth Expert — 本番エンジニアリング
レッスンの役割
CONTENT
順序
11 / 25

レッスン10 — 本番での Reth フォーク運用

問い

午前 3 時、バリデータは 40 分前からブロックを生成していない。ダッシュボードには: ファイルディスクリプタ枯渇、MDBX ページキャッシュ圧迫、ピア数 2。ユニットテストでは引っかからない、出荷した日にも見えない、3 ヶ月目にまとめてくる — どんな運用規律でこれを防ぐか?

原理(最小モデル)

  • 本番ビルドフラグ 4 つ. target-cpu=native / codegen-units=1 / jemalloc / asm-keccak
  • systemd の上限が支配的. LimitNOFILE=1048576(MDBX ページ + P2P 接続)+ LimitNPROC=infinity
  • 3 ストレージ規律. DB / ログ別ボリューム + NVMe SSD のみ + 定期スナップショット + 成長監視。
  • 絶対値ではなく変化率にアラート. 同期遅延 / ピア数 / MDBX 空きページ / RSS / ブロック取り込み時間 / ExEx 追従遅延。
  • Diff テストが最強の安全網. 同じブロックでバニラ Reth と継続的に diff → 1 ストレージスロットでも乖離はコンセンサスバグ。
  • App-chain トポロジ. 3 データセンター + 4 バリデータ以上 + 各バリデータの前に sentry 2 つ + 別 archive node + 別 RPC フリート。
  • アップグレード = 高さガード + 段階配布. ブロック高さで切り替え、上げていないバリデータは脱落(自業自得)。

具体例

再現可能リリースビルド:

# 再現可能なリリースビルド
RUSTFLAGS="-C target-cpu=native -C codegen-units=1" \
  cargo build --release --features jemalloc,asm-keccak

strip target/release/reth   # またはデバッグシンボルを切り離し

systemd ユニット:

[Service]
ExecStart=/usr/local/bin/reth node --chain custom --datadir /var/lib/reth
Restart=on-failure
LimitNOFILE=1048576
LimitNPROC=infinity
TasksMax=infinity

監視メトリクス:

メトリクスアラート条件
同期遅延(head vs network)N ブロック以上を N を超える時間
ピア数< 5
MDBX 空きページ< 5%
プロセス RSS単調増加
ブロック取り込み時間p99 が目標を超える
ExEx の追従遅延ExEx 依存

Diff テストハーネス(擬似):

# diff ハーネスの擬似コード
for block in mainnet[recent_1000]:
    s1 = reth_vanilla.execute(block)
    s2 = reth_fork.execute(block)
    if s1.stateRoot != s2.stateRoot:
        alert("divergence at block", block, s1, s2)

App-chain 最低トポロジ:

  • 3 データセンターに 4 バリデータ以上
  • 各バリデータの前に sentry 2 つ
  • 別 archive node(バリデータではない、解析クエリ用)
  • 別 RPC フリート(レート制限 + CDN)

アップグレード手順:

  1. アクティベーションのターゲットブロック高を発表
  2. 設定フラグで off のまま新バイナリをバリデータに配布
  3. アクティベーションブロックでコンセンサスルール切り替え — 高さチェックでガード
  4. アップグレードしていないバリデータは脱落 — だからこそ高さガード + 告知

失敗例(誤解)

cargo build --release で本番に出せる」— 間違い。jemalloc なし / asm-keccak なし / target-cpu=native なしでは負荷下のテイルレイテンシが暴れる + keccak ホットパスが遅い + AVX2 / AVX512 が活用されない。1 週目は気づかない、4 週目で疑問、3 ヶ月目で oncall。

「ユニットテストが通れば diff テスト不要」— 間違い。ユニットテスト = 設計者が想像した入力。本番 mainnet ブロックは想像を超える。Diff テストはバニラ Reth と継続比較、1 ストレージスロット乖離もコンセンサスバグ。

「バリデータと公開 RPC を同マシンで動かしてよい」— 間違い。1 回の DDoS でチェーン停止。RPC は別フリート(レート制限 + CDN)+ バリデータの前に sentry。

🛑 予測。 あなたのフォークをデフォルトの cargo build --release でリリース。1 週目、4 週目、3 ヶ月目に見える本番症状は?(答え: 1 週目 = 気づかない(軽負荷)、4 週目 = p99 レイテンシが断片化で悪化、ユーザは「たまに遅い」と言うが本気の問題と認識されない、3 ヶ月目 = jemalloc なしの断片化 + ファイルディスクリプタ枯渇 + 累積された symbol 情報なしのデバッグ困難 → 午前 3 時のページャ → 「動いていたものが急に動かない」「直近変更はない」「ログだけでは原因不明」。ゆっくり忍び寄り、まとめてくる。)

ステップで組み立てる

Step 1: 4 ビルドフラグを暗唱

フラグ理由
-C target-cpu=nativeAVX2 / AVX512 活用
codegen-units=1ビルド時間と引き換えに最適化
features = [jemalloc]テイルレイテンシ安定
features = [asm-keccak]keccak ホットパスの手書きアセンブリ

Step 2: systemd ファイルディスクリプタ上限

LimitNOFILE=1048576。デフォルト 1024 や 8192 では数時間で枯渇 → MDBX が Too many open files → ノードがゾンビ化。

Step 3: アラートは絶対値より変化率

「現在 1000 ピア」より「過去 1 時間で 50 ピア / 分減少」が意味ある。Prometheus + Grafana で rate / increase 関数。

Step 4: Diff テスト規律

for block in mainnet[recent_1000]: assert reth_vanilla.execute(block).stateRoot == reth_fork.execute(block).stateRoot。乖離はフォークの 3 容疑: ① 自分の変更が直接他コードパスに影響、② 共有 utility(gas 計算、precompile)の改変、③ 状態管理の境界条件。

Step 5: アップグレード規律

高さガード + 段階配布。上げていないバリデータは脱落、回復は再 sync。

答え合わせ

  • LimitNOFILE=8192 での失敗シグネチャ: 数時間後 Too many open files エラー → MDBX が新規ページオープン失敗 + P2P が新規接続拒否 → ピア数 0 へ + ブロック書き込み停止 → ノードがログ吐きながらゾンビ化、再起動でカウンタリセットで一時回復、根本原因不明。ログを grep して EMFILE を発見すれば一発、知らないと数時間。
  • diff テスト発見時の 3 容疑: ① 自分の最近の変更が他コードパスに副作用、② 共有 utility(gas 計算、precompile、state root 計算)の改変、③ 状態管理の境界条件(reorg、empty block、過去 hardfork 境界)。自分のコミット履歴を再読 が最初の手。
  • 3 アップグレード未完バリデータが見る現実: ブロック 1000 で 3 が新ルール、1 が旧ルール → ブロック 1001 で旧ルールバリデータは新ルールブロックを reject → 「自分から見ると」分岐 → quorum 不足で投票しなくなる → 残り 3 で多数決継続 → 旧バリデータは脱落(slashing 対象または inactivity ペナルティ)。回復は新バイナリに上げて DB を再 sync。

Expert への接続

本番で Reth fork を走らせるのは、Expert tier の 3 レッスンの交差点に位置する:

合格基準

  • 4 本番ビルドフラグを暗唱できる。
  • systemd 上限の意味と LimitNOFILE 値を即答できる。
  • 6 監視メトリクスを変化率視点で言える。
  • Diff テスト規律を「乖離 = 3 容疑」で説明できる。
  • アップグレード手順を高さガード + 段階配布で言える。

まとめ(3行)

  • 本番ビルド = 4 フラグ(target-cpu=native + codegen-units=1 + jemalloc + asm-keccak)+ systemd 上限調整(LimitNOFILE=1048576)。
  • 監視は絶対値より変化率、6 メトリクス(同期遅延 / ピア数 / MDBX 空き / RSS / 取り込み時間 / ExEx 追従)にアラート。
  • Diff テスト(バニラ Reth と継続比較、1 スロット乖離もコンセンサスバグ)がフォーク最強の安全網 — 加えて App-chain は 3 DC + sentry + 別 RPC フリートのトポロジ + 高さガードアップグレード。