Bot プログラミングスキル 環境構築・インフラ 開発ログ

🛠️開発記録#257(2025/7/2)NATSによるBot運用設計

0. NATSを使って何をしたいのか

NATS が担う役割 ― 「サービス間の背骨」になる

コンポーネントNATS Core (低遅延)JetStream (永続)
Trader発注シグナルを µs〜ms で配信/ACK(request-reply)約定ログをストリームに書き込み、後で解析可能
Recorderティック・板情報を時系列で蓄積
Analyzerアラートやリアルタイム PnL をサブスクライブ過去データをリプレイしてバックテスト・ML 学習
監視ツール/varz をスクレイプしヘルスチェック/jsz でストア容量やラグを監視

コンテナ分離で得られる 5 つのメリット

  1. 疎結合化
    • 各 Bot(Trader/Recorder/Analyzer)は Subject 名 だけ共有し、言語・リリースタイミングを完全に独立できます。
    • 新戦略を「signals.○○.*」に publish するだけでホットプラグ。
  2. 低遅延パスと重い処理を分離
    • Core はメモリだけで転送 → 約定レースに勝ちやすい。
    • JetStream にディスク書き込みを任せることで、Recorder やバックテストが Trader を“重く”しません。
  3. リプレイ可能なフル履歴が貯まる
    • ティック/約定/PnL など “事実” をそのままストリーム化。
    • 日時指定リプレイで 実戦さながらの回帰テストML 学習データ生成がワンコマンド。
  4. スケールと冗長化が段階的
    • 最初は 1 コンテナでも OK。負荷が上がれば Core/JetStream を別 Pod、さらに Leafnode で地域分散へ――アプリ側コードの修正ゼロ
  5. 運用コストとトラブル対応が軽い
    • 単一バイナリ 10 MB 前後・Pod 3 台で百万 msg/s クラス。
    • CLI -> nats top, WebUI -> :8222、Prometheus exporter は内蔵。

“結局、何ができるようになるの?”

BeforeAfter(NATS 導入)
単一プロセス Bot で 戦略を並列検証できないSubject を増やすだけで 複数戦略を同時運用・A/B テスト
ログをファイルに吐き出し → 後で CSV 読み込みJetStream から 秒単位でリプレイ/フィルタ取得
取引ループと解析処理が同居し GC や I/O でドロップCore ←→ JetStream 二層で I/O 影響ゼロ/ポジション取りこぼし防止
解析用データは外部サービス購入 or Cron 収集自分で高頻度ティックを蓄積 → コスト削減 + 独自 α データ資産
障害時に全 Bot が巻き添え再起動Core クラッシュでも JetStream が メッセージ保護 → 再接続で自動復旧

まとめ
NATS をバックボーンに据えると、
「低遅延の発注パス」「拡張性の高いデータレイク」「戦略量産の土台」
の三つを同時に手に入れられます。これにより、
勝てる Bot を素早く増やし実運用・検証・改良 のサイクルを高速で回せる――
これが最大の実益です。

1. はじめに──なぜ今、NATS なのか?

クラウドネイティブ時代において、メッセージブローカーはもはや「システムの血流」とも呼べる存在です。その中で NATS は「超軽量」「超低レイテンシ」「永続化(JetStream)も内蔵」というユニークな立ち位置を確立し、2018 年には Kubernetes や Prometheus と同列の CNCF Incubating プロジェクトとして正式に採択されました。cncf.io
さらに 2025 年現在、Synadia Cloud(公式マネージド版)は 1 日あたり 1,000億メッセージ超を処理する規模に拡大しており、企業領域での採用も加速度的に進んでいます。synadia.com
こうした実績は、「個人や小規模チームが“将来のスケール”を心配せずに選べるブローカー」としての安心材料になります。


2. NATS の基本構成と用語整理

レイヤ役割主な機能
Coreメモリ上での Pub/Sub、Request-Reply往復レイテンシ µs〜ms、ワイルドカード Subject
JetStream永続ストリーム/KV/Object StoreAt-Least-Once 配信、時刻指定リプレイ、Exactly-Once(時間窓付き)β
クライアント SDK各言語からの API 呼び出しPython、Go、Rust ほか 40 言語以上

NATS 2.11 ではメッセージの バッチ取得 API などが追加され、履歴再生の効率が大きく向上しました。docs.nats.io
「Core と JetStream が同じバイナリ内」という設計のおかげで、学習コストは従来型ブローカーより低く抑えられます。beta-docs.nats.io


3. 典型アーキテクチャ:Recorder・Trader・Analyzer+NATS

graph TD
    %% ノード定義
    Trader["Trader<br/>(発注)"]
    Core["NATS Core<br/>(低遅延)"]
    JetStream["JetStream<br/>(永続)"]
    Recorder["Recorder<br/>(ティック)"]
    Analyzer["Analyzer<br/>(解析)"]

    %% 矢印・ラベル
    Trader -- publish --> Core
    Core -- "request / reply" --> Trader
    Core -->|JetStream(永続)| JetStream
    JetStream --> Recorder
    Recorder -- subscribe --> Analyzer
  • Recorder は板・約定ティックを JetStream に書き込み
  • Trader は Core でサブ ms 受信、ACK は request-reply
  • Analyzer は過去データをリプレイしてバックテストや監視

この分離により、取引系が GC やディスク I/O の影響を受けることなく、解析系はいつでも過去に遡った検証ができます。


4. 低遅延 × 永続化を両立させる仕組み

Core はノンブロッキング I/O と最小限のプロトコルでメッセージを転送します。JetStream は同じプロセス内でディスクへ書き込み、必要に応じてコンシューマにリプレイします。しかも Exactly-Once 配信(時間窓付き)が 2.2 系以降で利用可能になり、金融システムにも適用しやすくなりました。beta-docs.nats.io
2.11 のバッチ取得 API と組み合わせることで、バックテスト用の大量データ取得も従来比で大幅に高速化できます。nats.io


5. 個人開発スタートアップガイド

5-1. ローカル開発(最小環境)

brew install nats-server            # macOS
nats-server -js &                   # JetStream 有効で起動
  • WebUI:http://localhost:8222 でダッシュボードを即確認
  • テストは pytest 実行前にサーバーをバックグラウンド起動し、終了後 killall nats-server

5-2. Docker Compose 例

services:
  nats:
    image: nats:2.11
    command: ["-js"]
    ports: ["4222:4222", "8222:8222"]
  trader:
    build: ./trader
    depends_on: [nats]
  recorder:
    build: ./recorder
    depends_on: [nats]

5-3. Kubernetes 例

helm repo add nats https://nats-io.github.io/k8s/helm/charts/
helm install my-nats nats/nats --set nats.jetstream.enabled=true

HPA を設定すれば、瞬間的なティックバーストにも自動で Pod が増減します。


6. Bot コンポーネント別の NATS 利用パターン

コンポーネント主な Subject 設計推奨 API
Recorderticks.<symbol>, fills.*JetStream Stream(work, interest=limits)
Tradersignals.entry, signals.exitCore + Request-Reply
Analyzerpnl.update, risk.alertJetStream Consumer:Pull モード

「Publisher と Subscriber の合意事項=Subject 名だけ」という疎結合は、戦略の増殖やコードリファクタ時に真価を発揮します。


7. 戦略量産を支える Subject 設計術

  1. 名前空間化signals.<strategy>.<instrument>
  2. バージョン付けv1.signals.entryv2.signals.entry
  3. ルート分離:低遅延系(Core)は signals.*、バッチ系(JetStream)は audit.*

こうしておくと「新戦略を試す=Subject を 1 行追加」だけで済み、ホットプラグが容易になります。


8. スケールアップ・冗長化のステップ

フェーズ追加する機能効果
Step 0単一サーバーローカル開発〜小規模運用
Step 13 ノードクラスタフェイルオーバー確保
Step 2Core / JetStream を別クラスタに分離解析系 I/O が取引系に影響しない
Step 3Leafnode / Super-cluster東京↔海外で自動フェイルオーバー

Pod・ノードを段階的に増やすだけでアプリ側コードを変更せずにスケールできる点が、NATS の大きな魅力です。


9. 運用監視とトラブルシューティング

  • Prometheus Export/varz, /jsz をスクレイプ
    • 例:container_memory_usage_bytes{pod="nats-0"}
  • アラート例
    • varz.out_msgs の急増 → 無限ループ検知
    • jsz.store > 80 % → ストレージ逼迫
  • CLI デバッグ:「nats-box」コンテナで nats stream infonats top が即利用可能

10. よくある落とし穴と回避策

回避策
JetStream を有効にしたまま大量ティックを保存し、ディスクが溢れる--max-age--max-bytes を必ず設定
Exactly-Once が必要な処理で重複排除を怠るNats-Msg-Id ヘッダ+ユニーク制約で冪等化
nats CLI が入っておらず運用が不便synadia/nats-box を sidecar に追加

11. Kafka/RabbitMQ との比較早わかり表

項目NATS 2.11KafkaRabbitMQ
ランタイム単一バイナリ(~10 MB)JVM + ZooKeeperErlang
低遅延◎ µs〜ms◯ ms◯〜△ ms〜十 ms
永続化JetStream 内蔵デフォルトデフォルト
Exactly-Once時間窓付き β〇(トランザクションAPI)△(プラグイン依存)
運用コスト低(Pod 3 でも実用)高(Brokers + ZooKeeper)

12. ケーススタディ:小規模→中規模 Bot 運用の成長曲線

  1. Month 0-1:単一サーバーで Recorder+Trader を同居
  2. Month 2:JetStream を有効化し、Analyzer コンテナを追加
  3. Month 3-4:戦略別に Subject を分け、A/B テストを並列運用
  4. Month 6:Leafnode で海外リージョンを追加し 24h 稼働を実現

「コード改修ゼロで拡張できる」ため、インフラ作業より戦略開発にリソースを集中できます。


13. まとめ──先行導入で得られる優位性と次の一歩

  • 低遅延・永続化・軽量運用 がワンバイナリで手に入り、個人開発でも“将来のスケール”を見据えた設計が可能です。
  • まだ仮想通貨 Bot 界隈では採用事例が多くないため、ティック履歴の先行蓄積戦略量産の即応性などで優位性を築けます。
  • まずは Core+JetStream を 1 プロセスで立てる最小構成から始め、負荷・運用フェーズに応じて Leafnode やアカウント分割を段階的に導入することをおすすめします。

-Bot, プログラミングスキル, 環境構築・インフラ, 開発ログ