データベース

NATSとは?Core NATSとJetStreamの仕組みと採用判断を実装視点で解説

NATSは、アプリケーション同士が相手のIPアドレスを知らないまま「サブジェクト」という名前だけでメッセージをやり取りするメッセージングシステムです。サーバー本体の nats-server はGoで書かれた単一バイナリで、外部ミドルウェアなしにノートPCでも起動します。この記事では、Core NATSの通信モデル、JetStreamの永続化と配信保証、クラスタとリーフノードの構成、そして受託開発でNATSを選ぶ条件と見送る場面を、公式ドキュメントの実測に基づいて整理します。

まとめ|NATSが向く構成と見送るべき場面の結論

結論から書きます。マイクロサービス間の同期・非同期通信を1つの基盤にまとめたい、かつ運用に専任チームを置けない規模なら、NATSは第一候補です。単一バイナリで起動し、JetStreamを有効にするだけで永続化まで同じプロセスが担うため、ブローカーとコーディネーション基盤を別々に運用する構成より構成要素が減ります。

一方、数か月分のイベントを貯めて分析基盤へ流し込むことが主目的ならKafka系が素直です。コネクタやスキーマレジストリの厚みが違います。判断を分ける軸は「メッセージを運ぶことが目的か、貯めて再処理することが目的か」の一点。

実装上の落とし穴も先に挙げます。Core NATSは受け取り手がいなければメッセージを捨てる設計であり、これを知らずに受注管理や決済連携へ投入すると、デプロイのたびに欠落が起きます。永続性が要るなら、必ずJetStreamのストリームを定義してから発行してください。

Core NATSの通信モデル|サブジェクト設計と3つのメッセージング方式

NATSの土台がCore NATSです。永続化の仕組みを持たず、接続中の購読者へメッセージを配るだけの軽量な層として設計されています。この層の性質を押さえると、JetStreamが何を足しているのかが正確につかめます。

サブジェクトの階層設計とワイルドカード購読による範囲指定の考え方

NATSでは、キューやトピックを管理画面で事前に作成しません。発行側が orders.jp.created のような文字列(サブジェクト)を指定して送り、購読側が同じ文字列で待ち受けるだけで経路が成立します。サブジェクトはドット区切りのトークン列で、階層構造を自分で決められる点が設計の要です。

ワイルドカードは2種類。* は1トークンだけを置き換え、> はそれ以降のすべてのトークンにマッチします。orders.*.created なら国コード部分だけを任意にでき、orders.> なら注文まわりのイベントをまとめて受け取れる形です。

設計時に決めておきたいのが、トークンの並び順です。「業務ドメイン、拠点、イベント種別」の順のように、絞り込みたい粒度から前へ置くと、あとからワイルドカード購読で範囲を切り出せます。イベント種別を先頭に置くと拠点単位の購読ができません。

Pub-Sub・Request-Reply・キューグループの3方式と使い分け基準

Core NATSは3つの通信パターンを同じ仕組みの上で提供します。1つ目のPub-Subは、1つのサブジェクトに複数の購読者がぶら下がり、全員が同じメッセージを受け取る形です。通知の配信や状態変更のブロードキャストに向きます。

2つ目のRequest-Replyは、発行側が返信用サブジェクトを添えて送り、応答を待つ同期的な使い方です。HTTPのAPI呼び出しをNATS上に置き換えれば、サービスディスカバリを別に用意せず通信を組めます。3つ目のキューグループは、同じグループ名で購読したメンバーのうち1つだけが受け取る負荷分散型。ワーカーを横に増やせば処理能力がそのまま増えます。

使い分けの基準は単純です。全員に届けたいならPub-Sub、応答が要るならRequest-Reply、処理を分担したいならキューグループ。監査ログ用の購読者をPub-Subで足しても既存のキューグループの分配は変わらないため、方式の併用も設計に織り込めます。

Core NATSがat-most-once配信に振り切った設計上の理由

Core NATSの配信保証はat-most-once、つまり「届くか、届かないか」です。購読者がいないサブジェクトへ発行されたメッセージは、その場で捨てられます。再送キューを持たないぶんメモリとディスクを消費せず、レイテンシのばらつきも小さく保てるという割り切りです。

この性質は欠点ではなく、用途を選ぶ前提条件です。メトリクス配信や、数百ミリ秒後には価値が消える相場データのような用途では、再送のほうがむしろ邪魔。失われては困る業務イベントを扱うなら次章のJetStreamが要ります。IoT寄りの通信で配信品質を段階指定したい場合はMQTTのQoSによる制御も選択肢になり、NATSサーバー自体もMQTTインターフェースを備えています。

JetStreamによる永続化|ストリーム設定と配信保証の実装要点

JetStreamは、NATSサーバーのバイナリに内蔵された永続化レイヤーです。別プロセスや別クラスタは不要で、設定で有効にしたノードがそのままストレージを担います。KafkaやPulsarと構成が大きく分かれるのがこの点です。

ストリームとコンシューマーの役割分担と保持ポリシーの選択基準

JetStreamの中心概念は2つだけ。ストリームは、指定したサブジェクトに流れたメッセージを取り込み、連番を振って保存する格納庫です。コンシューマーは、そのストリームをどこからどの条件で読むかという状態付きのビュー。クライアントはコンシューマーに接続し、受け取ったメッセージを確認応答(ACK)して読み進めます。

保持ポリシーは3種類から選びます。Limits は件数・容量・経過時間の上限に達するまで保持する既定の方式、Interest は購読しているコンシューマー全員が読み終えたら削除する方式、WorkQueue は1回読まれたら消える作業キュー型です。上限に達したときの挙動も Old(古いものから削除)と New(新規を拒否)で選べます。

選択の目安はこうです。イベントを後から再生したいなら Limits、ジョブを1回だけ処理したいなら WorkQueue、購読者が動的に増減する構成でディスクを膨らませたくないなら Interestmax_agemax_bytes は必ず明示してください。

at-least-once配信と重複排除ウィンドウによる二重処理の抑止

JetStreamの配信保証はat-least-onceです。ACKが返らないメッセージはサーバーが再配信するため、同じメッセージが2回届く可能性が構造的に残ります。受信側は冪等に作るのが原則になります。

発行側の重複には、サーバー側の防御があります。メッセージヘッダーに Nats-Msg-Id を付けて発行すると、一定時間内に同じIDのメッセージが再び届いても保存されません。この重複排除ウィンドウは既定で2分。ネットワーク断による発行側のリトライは、この仕組みでほぼ吸収できます。

コンシューマー側で押さえる設定は3つ。恒久的に進捗を残すなら durable_name を指定し、確認応答は ack_policyExplicit にして明示的に返します。読み始める位置は先頭・最新・特定シーケンス番号・特定時刻から選べるため、「1時間前から読み直す」障害復旧が設定変更だけで済みます。

レプリカ数とストレージ種別で決まる耐障害性とディスク消費の設計

ストリームのストレージ種別は FileMemory の2択で、既定はファイル保存です。メモリ保存は再起動で消えるため、テストや極めて短命なデータ以外では選びません。

耐障害性を決めるのがレプリカ数です。既定値は1で、この場合ストリームは1台のサーバー上にしか存在せず、そのノードが落ちればストリームごと止まります。本番では単一障害点です。冗長化する場合は、Raftによる合意形成が働くよう奇数台の構成にしたうえでレプリカ数を上げます。

見落とされやすいのがディスク消費の見積もりです。レプリカ数を3にすれば、同じメッセージがクラスタ全体で3部保存されます。1日あたりの流量に保持期間とレプリカ数を掛けた値が必要容量の下限になります。保持期間は「業務上どこまで遡って再処理するか」から逆算して決めてください。

KVストアとオブジェクトストアをJetStream上に載せる実装判断

JetStreamは、ストリームの上にKey-Valueストアとオブジェクトストアを提供します。KVストアはレプリケーションと永続性を備えたキー値の保管庫で、設定値や機能フラグ、リーダー選出用の状態を置く用途に向きます。値の変更を購読して即座に反映できる点が、外部KVSとの違いです。

オブジェクトストアは、1メッセージに収まらない大きなデータをチャンク分割して保存し、オブジェクト単位のメタデータを持たせる仕組みです。数MB規模の生成物をサービス間で受け渡す程度なら実用範囲に入ります。

ただし汎用ストレージの置き換えと考えるのは無理があります。KVストアはRDBのような検索や結合を持たず、オブジェクトストアはS3系ほどのライフサイクル管理や権限制御を備えていません。「メッセージング基盤の周辺にある小さな状態」を同じ運用系へ寄せる機能、という位置づけが妥当です。

サーバー構成と運用|クラスタ・リーフノードと監視エンドポイント

NATSの運用が軽いと言われる理由は構成要素の少なさです。動かすプロセスは nats-server の1種類だけで、クラスタ化してもJetStreamを有効にしても、増えるのは設定であってコンポーネントではありません。

単一バイナリ起動からクラスタ構成へ広げる際の設定手順と注意点

導入の流れは次の順で進めます。

  1. 単体で nats-server を起動し、既定のクライアントポート4222への疎通を確認する
  2. 設定ファイルでJetStreamを有効にし、保存先ディレクトリと最大ストレージ量の上限を明示する
  3. 3台構成にしてクラスタ設定を追加し、ノード間の経路が張れているかを確認する
  4. ストリームとコンシューマーを定義し、レプリカ数を上げてノード停止試験を行う

注意点は2つ。1つは、JetStreamのストレージ上限を設定しないまま本番投入すると、ディスクを使い切ってサーバー全体が停止する事故につながること。もう1つは、クラスタ化してもレプリカ数1のままではストリームが冗長化されない点です。クラスタ構成とストリーム冗長化は別の設定であり、前者だけでは可用性は上がりません。

リーフノードでエッジ拠点と中央クラスタをつなぐ構成の使いどころ

リーフノードは、拠点や現場に置いた小さなNATSサーバーを中央クラスタへぶら下げる仕組みです。拠点側のアプリケーションはローカルのサーバーに接続し、そのサーバーが中央との接続を1本にまとめます。拠点内の通信は外へ出ず、必要なサブジェクトだけが中央へ流れます。

この構成が効くのは、工場や現場拠点のように回線が細い、あるいは断続的に切れる環境です。中央への接続が切れている間もローカル内のPub-Subは動き続けるため、現場の制御系が止まりません。地理的に離れた複数クラスタを束ねる場合は、上位をゲートウェイでつなぐスーパークラスタ構成も選べます。

逆に、拠点が1つしかない構成でリーフノードを入れるのは過剰です。ノードが増えれば認証情報の配布と証明書更新の対象も増えます。拠点数が2〜3で回線も安定しているなら、中央クラスタへ直接つないだほうが軽く済みます。

監視エンドポイントで確認する接続数・ストリーム状態と健全性判定

NATSサーバーは、クライアント用ポートとは別に読み取り専用のHTTP監視インターフェースを持ちます。ポートは設定次第ですが8222が慣例で、以下のエンドポイントが並びます。

  • varz:バージョン、稼働時間、メモリ、各種カウンタのスナップショット
  • connz:接続中のクライアント一覧と認証・購読の内訳
  • routez:クラスタ内の他ノードとの接続状況
  • jsz:そのノードが保持するストリーム数とコンシューマー数などJetStreamの状態
  • healthz:健全なら200、異常なら503を返すヘルスチェック

監視設計の基本形は、healthz をロードバランサーと死活監視に、jsz をストレージ使用量とレプリカ健全性のアラートに割り当てる形です。connz は接続リークの検知に効きます。クライアント側の接続クローズ漏れは負荷試験で表面化せず本番で数日かけて詰まるため、接続数の時系列は最初から取っておいてください。

Kafka・RabbitMQとの構造差|スループットと運用コストの比較

NATSの評価は、ベンチマーク値より「何を捨てて何を得た設計か」で見たほうが実務判断に近づきます。ここでは代表的な2製品との構造差を整理します。

Kafkaとの構造差|パーティション前提かサブジェクト前提かの違い

Kafkaはトピックをパーティションに分割した追記専用ログで、順序保証はパーティション単位に閉じます。コンシューマーグループのメンバーが増減するとサーバー側でリバランスが走ります。Kafkaが大規模なイベント基盤で選ばれる理由は、この分割モデルと周辺エコシステムの厚みです。

JetStreamのストリームはサブジェクトにひも付いた格納庫で、パーティションという概念を前面に出しません。コンシューマーの増減はクライアント側の操作で完結し、サーバー側のリバランスは起きない構造です。運用は軽くなる反面、パーティション数でスループットを線形に伸ばす設計にはならず、単一ストリームへ極端に集中する流量には向きません。

取り込み量が大きく、長期保持と再処理が前提の規模ではKafka側に分があります。サービス間連携が主目的なら、構成要素の少なさでNATSが優位です。

RabbitMQとの比較で見えるルーティング表現力と運用負荷の差

RabbitMQはエクスチェンジとバインディングでルーティング規則を組み立てる方式で、ヘッダー条件や複雑な分岐まで表現できます。管理画面から経路を定義できるため、運用担当者が設定でルーティングを変えられる点が強みになります。

NATSは、この役割をサブジェクトの命名規約に寄せた設計です。経路の表現力そのものはRabbitMQに及びませんが、定義すべき構成物がストリームとコンシューマーだけで済むぶん、設定ミスの余地は小さくなります。比較軸の詳細はRabbitMQとKafkaの違いを整理した記事の観点がそのまま流用できます。

メッセージ基盤3製品の比較表|保持・順序保証・運用コストの整理

設計判断で参照する主要な軸だけを並べます。

観点 NATS JetStream Apache Kafka RabbitMQ
配信保証 少なくとも1回 少なくとも1回 確認応答で再送
保持の考え方 上限と保持方針で制御 ログ保持期間で制御 消費後に削除が基本
順序の単位 ストリーム単位 パーティション単位 キュー単位
ルーティング サブジェクト階層 トピックとパーティション エクスチェンジ定義
構成要素 単一バイナリ1種 ブローカーと管理層 ブローカーとプラグイン
向く規模 小〜中規模の連携基盤 大規模な分析連携 中規模の業務連携

表の「向く規模」は流量の絶対値ではなく、運用に割ける人手との比で決まる項目です。専任のプラットフォームチームがいないなら、機能の多さより構成要素の少なさを優先したほうが、結果的に安定して動きます。

NATSを採用すべき条件と見送るべき場面|受託開発での判断基準

ここからは判断を言い切ります。技術的な優劣ではなく、受託開発の現場で「入れてよいか」を決める条件です。

NATSを採用してよい3つの条件と受託開発案件での適合パターン

次の3条件がそろうとき、NATSは有力な選択肢になります。第一に、サービス間通信で同期呼び出しと非同期イベントの両方が要ること。Request-ReplyとPub-Subを同じ基盤で賄えるため、gRPCとメッセージキューを別々に用意する構成より依存が減ります。

第二に、運用体制が小さいこと。単一バイナリで完結する構成は、インフラ担当が兼任の案件でも維持できます。第三に、拠点やエッジ機器が絡むこと。リーフノードで拠点内通信を閉じられる設計は、回線品質が読めない現場で効きます。

適合パターンの典型は、複数の業務サービスをイベントで疎結合につなぐ構成です。設計の考え方はイベント駆動アーキテクチャの基本構成と共通で、NATSはその実装手段の1つ。イベント収集から後段のストリーム処理までを一体で設計するなら、データ分析基盤構築・MLOps構築支援のように基盤設計から運用まで通しで請け負う体制のほうが、分析要件との齟齬が出にくくなります。

NATSを見送るべき場面|長期保管と分析連携が主目的のケース

見送る場面をはっきり書きます。イベントを数か月〜数年単位で保管し、あとから全期間を再処理して分析に回すことが主目的なら、NATSは選びません。JetStreamでも長期保持は設定できますが、分析基盤への接続部品が薄く、結局は自作コネクタを保守し続けることになります。

2つ目の見送り条件は、社内にKafka運用の実績と人員がすでにある場合です。技術的にNATSのほうが軽くても、運用ノウハウのない基盤を1つ増やすコストが上回ります。既存クラスタにトピックを1つ足すほうが、総保有コストでは有利になるケースがほとんどです。

業界標準プロトコルの互換が要件に入る案件も対象外です。AMQP 0-9-1に沿った相互接続が契約要件なら、該当プロトコルを一次サポートする製品を選んでください。NATSは独自プロトコル前提の設計であり、互換性を後付けで満たそうとすると構成が歪みます。

導入初期に起こりやすい失敗|Core NATSのまま本番投入する誤り

導入初期の失敗で最も多いのが、検証時にCore NATSで動作確認し、そのまま本番へ持っていくパターンです。開発環境では発行と購読が同時に立ち上がっているため取りこぼしが起きません。本番でデプロイやスケールインが走った瞬間、購読者が一時的に消えてメッセージが失われます。

2つ目は、サブジェクト命名を決めずに実装を始めるケース。あとから階層を変えると、購読側のワイルドカード指定とストリームのサブジェクト定義を全面的に直すことになります。命名規約は最初に文書化し、拠点コードやテナントIDのようにあとから増える要素をトークンとして先に確保しておいてください。

3つ目は監視の後回しです。ストレージ上限に達したときの挙動は保持ポリシー次第で変わり、新規メッセージを拒否する設定なら発行側でエラーが出続けます。jsz によるストレージ使用率の監視は、ストリームを定義した日に同時に組み込みます。

よくある質問

NATSの導入検討で寄せられる質問に回答します。

NATSとKafkaはどちらを選ぶべきですか?

目的で分かれます。サービス間のメッセージを運ぶことが主目的で、運用体制が小さいならNATSが向きます。イベントを長期保持して分析基盤へ流すことが主目的なら、コネクタがそろうKafkaを選んでください。迷うときは「6か月前のメッセージを読み返す要件があるか」で切り分けられます。要件があるならKafka側です。

Core NATSだけで本番運用しても問題ありませんか?

失われても業務に影響しないメッセージに限れば問題ありません。メトリクス配信、キャッシュの無効化通知、表示用の相場更新などが該当します。受注や決済のように欠落が業務事故になるデータでは、必ずJetStreamのストリームを定義してください。Core NATSは購読者がいなければその場で破棄するため、デプロイ中の数秒間で欠落が発生します。

JetStreamのメッセージはどのくらい保持できますか?

設定次第で、件数・容量・経過時間のいずれかの上限に達するまで保持されます。数か月の保持も技術的には可能ですが、レプリカ数を掛けた実ディスク消費が効くため、実運用では数日〜数週間に収める設計が現実的です。「1日あたりの流量×保持日数×レプリカ数」で必要容量を先に見積もり、上限値を明示しておけばディスク枯渇による停止を避けられます。

NATSはMQTTの代わりに使えますか?

NATSサーバーはMQTTインターフェースを備えているため、MQTTクライアントからの接続を受けること自体は可能です。ただし既存のIoTデバイスがQoSやRetainメッセージの挙動に依存している場合は、対応範囲を個別に検証してください。デバイス側の実装が固定されている案件では、専用ブローカーを立てるほうが確実です。

既存のRabbitMQからNATSへ移行する価値はありますか?

現状で運用が回っているなら、移行の価値は限定的です。正当化されるのは、拠点やエッジを含む分散構成へ広げたい、あるいはブローカーとプラグインの運用負荷を減らしたいという動機があるときに限られます。エクスチェンジで組んだルーティングをサブジェクト設計へ置き換える作業は手間がかかるため、新規サービスから段階的に切り替えてください。

関連記事

資料請求

RELATED POSTS 関連記事