システム間を疎結合に保ちつつ非同期で通信しようとすると、必然的にメッセージング基盤が必要になります。
もしメッセージング基盤を手っ取り早く使うのであれば、クラウドベンダーのサービス、例えばAmazon SNSやGoogle Cloud Pub/Subを使うのが一番です。(自分で環境を立てなくて済むならその方法を選択した方がいいというのが自論です)
ただし、手元に環境を用意したり接続用のロールやサービスアカウントを作るのは面倒です。
OSSはどうでしょうか?メッセージングやストリーミング処理のデファクトスタンダードとなっているKafkaという素晴らしいプロダクトがあります。
ただし、耐障害性もありスケーラビリティを実現するためにZookeeperの複雑性を受け入れなければいけないので、これまた面倒臭いです。(もちろん、Amazon MSKやConfluent Cloudのようなマネージドサービスを使う手もあります)
では、もっと簡単にPub/Subスタイルのメッセージングを自前で用意できないのかと探して見つけたのがNATSでした。
詳しいところは技術書典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.us
と time.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というものができましたが、やっていることはこれと近いですね。
また、Queue Groupのようなロードバランサーの仕組みがあるのも特徴ですね。
Zero Configuration
設定なしにメッセージングを始められるのも特徴です。 例えば以下のようなことを実現するのに設定は全く不要です。サーバーやクライアントを構成したら自動的に設定されます。
- Subjectにメッセージを配信するための設定
- Subjectをからメッセージを購読するための設定
- SubjectからSubscriberへのメッセージ配信のロードバランシングの設定
- 災害対策のためのNATSサーバークラスタの冗長化
Simple Client
クライアントも実装が楽チンです。クライアントライブラリ自体が30以上の言語の実装があり、インターフェイスもシンプルであるためです。
Node.jsのクライアントライブラリである nats.js
を例にとると、以下のようにしてメッセージの配信・購読が可能になります。
全てのメッセージがSubjectを通じてやりとりされるため、クライアント側も実装が簡単です。見た目もスッキリしていますね。
Deliver AT MOST ONCE
NATSはメッセージを1回しか配信しません。(At Most Once戦略)
これはディスクやDBのような2次ストレージにメッセージを保存していないためです。 裏を返すとメッセージを管理する手間が省けるのでシンプルではあると言えます。(物は言いようですね) この特性のため、受け取りに失敗した or 購読する前に配信されたメッセージを再送する手段がありません。
その一方でKafkaは稼働しているマシンのディスクにメッセージを書き込んでいるため、始点を指定してメッセージを再送できます。
また、ストリーミング処理のための拡張実装であるNATS StreamingやLiftbridgeはこの問題を解決して最低1回(At least once)配信できるようになります。
もう少し深掘りしたことや本番運用に向けたNATSのクラスタリング・認証認可の話は技術書典7で出す本をお楽しみに!!