Ponz Dev Log

ゆるくてマイペースな開発日記

メッセージング基盤のNATSを超ざっくり解説する

システム間を疎結合に保ちつつ非同期で通信しようとすると、必然的にメッセージング基盤が必要になります。

もしメッセージング基盤を手っ取り早く使うのであれば、クラウドベンダーのサービス、例えばAmazon SNSGoogle Cloud Pub/Subを使うのが一番です。(自分で環境を立てなくて済むならその方法を選択した方がいいというのが自論です)

ただし、手元に環境を用意したり接続用のロールやサービスアカウントを作るのは面倒です。

OSSはどうでしょうか?メッセージングやストリーミング処理のデファクトスタンダードとなっているKafkaという素晴らしいプロダクトがあります。

ただし、耐障害性もありスケーラビリティを実現するためにZookeeperの複雑性を受け入れなければいけないので、これまた面倒臭いです。(もちろん、Amazon MSKやConfluent Cloudのようなマネージドサービスを使う手もあります)

aws.amazon.com

では、もっと簡単にPub/Subスタイルのメッセージングを自前で用意できないのかと探して見つけたのがNATSでした。

nats.io

詳しいところは技術書典7に出す同人誌で書こうと思いますが、 NATSは何が特徴で何が他よりもすごいのか、頭の整理のためにもブログ記事として書き記しておきます。

Subject-based messaging

メッセージのやりとりは全てSubjectを通じて行います。

KafkaやAmazon SNSのようなPub/Sub型のメッセージングに慣れた方はメッセージの購読にTopicやSubscriptionを作成したでしょう。 驚くことにNATSには TopicやSubscriptionがありません 。PublisherとSubscriberの間に立つ登場人物は Subjectただ1つです

PublisherはSubjectを指定してメッセージを配信し、同じSubjectを購読しているSubscriberにNATSがメッセージをルーティングしてくれるのです。 「NATSは(メッセージ)キューではなくルータ」であると主張している方もいます。

Flexible Subject

全てのメッセージのやりとりはSubjectを通じて行うと書きましたが、配信先は1つに限定されません。 Subjectにはワイルドカードを使えます。

ワイルドカードにも2種類あり、特定の1階層のみ全てのメッセージを受け取る * (アスタリスク)と、特定の階層以下全て階層向けのメッセージを受け取る > (不等号) があります。

例えば、time.* というSubjectを購読するSubscriberは、Publisherが time.ustime.jp に向けて配信したメッセージのどちらからも受け取れます。ただし、time.jp.tokyo のようなさらに下の階層までSubjectが指定されてメッセージが配信され場合はSubscriberはメッセージを受け取れません。 time.> というもう1つのワイルドカードを使ったSubjectならば受け取ることができます。

Kafkaに慣れた方ならば、1Topicに対して複数のSubscriptionがぶら下がり、これらのSubscription全てをSubscribeしている状態をイメージしていただくと良いです。

3style messaging

メッセージングのスタイルにも3種類あります。

  • Pub/Sub
  • Request/Reply
  • Queue Group

Pub/Subを拡張してメッセージの返信(Request/Reply)もできることが特徴です。 AWSだと最近Temporary Queueというものができましたが、やっていることはこれと近いですね。

aws.amazon.com

また、Queue Groupのようなロードバランサーの仕組みがあるのも特徴ですね。

Zero Configuration

設定なしにメッセージングを始められるのも特徴です。 例えば以下のようなことを実現するのに設定は全く不要です。サーバーやクライアントを構成したら自動的に設定されます。

  • Subjectにメッセージを配信するための設定
  • Subjectをからメッセージを購読するための設定
  • SubjectからSubscriberへのメッセージ配信のロードバランシングの設定
  • 災害対策のためのNATSサーバークラスタ冗長化

Simple Client

クライアントも実装が楽チンです。クライアントライブラリ自体が30以上の言語の実装があり、インターフェイスもシンプルであるためです。 Node.jsのクライアントライブラリである nats.js を例にとると、以下のようにしてメッセージの配信・購読が可能になります。

github.com

Pub/Sub messaging with NATS

全てのメッセージがSubjectを通じてやりとりされるため、クライアント側も実装が簡単です。見た目もスッキリしていますね。

Deliver AT MOST ONCE

NATSはメッセージを1回しか配信しません。(At Most Once戦略)

これはディスクやDBのような2次ストレージにメッセージを保存していないためです。 裏を返すとメッセージを管理する手間が省けるのでシンプルではあると言えます。(物は言いようですね) この特性のため、受け取りに失敗した or 購読する前に配信されたメッセージを再送する手段がありません。

その一方でKafkaは稼働しているマシンのディスクにメッセージを書き込んでいるため、始点を指定してメッセージを再送できます。

また、ストリーミング処理のための拡張実装であるNATS StreamingやLiftbridgeはこの問題を解決して最低1回(At least once)配信できるようになります。

github.com

www.infoq.com


もう少し深掘りしたことや本番運用に向けたNATSのクラスタリング・認証認可の話は技術書典7で出す本をお楽しみに!!