分散システムに明るいと自称している私なので、Nostr *1なアプリケーション(ここではマイクロブログ型SNSとする)をスケール可能(全体のユーザ数が増加しても使えるものであり続ける)にするためにはどうすればよいかと、思考実験レベルで考えてみている。
これならいける!というところにはたどり着いていないけれど、アイデアとか、糸口になるかなーみたいな気づきはあったのでここに記す。
Nostrの特徴として維持されないといけないこと
大事。
- 中央集権的なサーバに頼らない
- リレーサーバは気軽に建てられて運営をやめてもユーザに迷惑がかからない
- (ボランティアベースになるというところはひとまず仕方がない、ということにしておく)
- リレーサーバに要求されるマシンスペックや通信リソースがべらぼうな量にならない
- クライアントはそれなりに遅延なくデータを取得できる
- (ピュアP2Pなアーキ等だと遅くなりがちであるということを意識してのところ)
スケールさせる上での課題は何か?
前提知識
- (少なくとも現状の仕様では、)フォローされているユーザAとフォローしているユーザBは共通のリレーサーバへの接続が少なくとも1つないと、BはAの投稿を取得することができない
- 接続するリレーサーバを変更した際などに、フォローしてるユーザを見失う、フォロワーを置き去りにしてしまう、ということが起きる
- 現状ではユーザ数がさして多くなく、定着したユーザの同質性からコンセンサスを成立させられているので、例えばJPなユーザは特定のいくつかのリレーサーバに接続していればOK、というようなユーザ側の工夫でどうにかなっているところがある
- ユーザは自身の投稿やメタデータの冗長性を確保するため、また上のポチで記述したようにフォロワーが接続しているリレーサーバにデータを送信する必要があるため、少なくとも3つから5つ程度のリレーサーバには自身の投稿のデータやメタデータを送信している
課題
- ① 1つのリレーサーバがさばけるクライアント数には当然限界が存在するので、現在存在するリレーサーバの台数だけでは、ユーザの増加に対応しきれない
- => (抜本的にアーキを変更して、クラサバ一体型のピュアP2Pにでもしない限り、)リレーサーバを増やす必要はあるはず。それ以外の対策については後述
- ②上のポチで記述した通りリレーサーバが増えた場合、多数のリレーサーバが存在する中で、ユーザは接続すべきリレーサーバを適切に選択することができない
- 前提知識のところでコンセンサスがあるのでどうにかなっていると書いたが、ユーザ数が増加して、各々のペルソナも多様になった場合、同じような方法ではどうにもならなくなる
- 各クライアントはフォロイー、フォロワーが少なくとも1つ(冗長性を考えれば2-3程度)のリレーサーバを共通に持つようにマッチングがとれている必要があるが、そのようなリレーサーバ群をユーザが知る手段は(コンセンサスが成立していない場合、)存在しない
どのような手がありそうか?(≒拡張の余地がありそうなところ)
- 最低限、リレーサーバの連携は必要なはず。また、リレーサーバのソフトウェアはもっとインテリジェントになる必要がある
- 可能であれば、スケールさせるための仕組みにクライアントを協力させることも考えられる
- クライアント間の連携も通信コスト的に見合うならやってもよさそう
- とはいえ、クライアント間でのP2Pでの直接通信まで踏み込むのは筋悪そうなので考えない
以下に、上の思いつきを詳細化していく。
が、まずはそもそもクライアント側の要件は何であるかを確認する。
クライアント側の情報取得に関する要件
- クライアントは最低限フォローしているユーザの投稿のデータは受信できる必要がある
- (どれだけの期間分受信できればワークするかは想定するユーザの使い方によって変わるので明確化は難しい)
- リレーサーバに持たせている各種メタデータも(自前で持っておくこともしたほうがいいし、仕様として整理が必要そうな気はするものの、)受信できる必要がある
- (複数の端末やクライアントで同時にアプリケーションを利用可能であるという利便性は捨てられない、と思う)
クライアントの動作環境等に関連する要件
- スマホ程度のスペックでも動作し、通信量に制約のあるモバイルネットワークでも無理なく使える
- (パケ死やバッテリ消費やばい問題が起きない)
- なお、スマホ等のモバイルデバイスでの通信に着目すると、恒常的に大量の通信を要することはクリティカルだが、(私の知る範囲では、)Websocketのコネクション数が多い事自体は、数十程度に収まっていれば、問題とならない・・・はず(要エビデンス)
要件を踏まえて、以下。
具体的に必要な仕様拡張他
確実なもの(課題①に対応する内容)
- クライアントが、利用するデバイスや環境、ユーザの求める機能性に合わせて必要なデータ量を絞れるようになる
- クライアントがイベントのサブスクライブをしている際に、イベント情報を1つ1つ個別に送ると、各々に重複する情報があって無駄が多いケースがあるようなので、一つのメッセージに複数の同種のイベント情報をまとめられるように仕様拡張する
- サーバ側の処理負荷は増すかもしれないが、サーバ・クライアントともに通信量は削減されるはず
アイデアレベルのもの(課題②に対応する内容)
- リレーサーバが連携する前提で、分散ハッシュテーブル(DHT)の仕組みを使って、公開鍵の値からあるユーザを担当するリレーサーバを決めるようにする*2
- あるユーザのデータを保持しているリレーサーバを、全てのリレーサーバが lookup することができるようになるため、当該ユーザのデータを取得したいユーザ(クライアント)は、初回は適当なリレーサーバにサブスクライブ要求を投げ、要求を受け付けたリレーサーバはその要求をHTTPでのリダイレクトのような形で担当リレーサーバに回し、リダイレクトされたクライアントは以後、リダイレクト先の担当リレーサーバにサブスクライブのリクエストを行う
- イベントデータを投げる場合も基本的には同様
- 冗長性の確保のため、担当リレーサーバは1つであるものの、それをマスターとして、他に(ここではひとまず)2つ、のスレーブ担当のリレーサーバがDHTの仕組みの中で、共通のルールに基づき定められる形とし、それらのアドレス情報はデータを投げつけるクライアント、サブスクライブするクライアントのいずれにも、リダイレクトが行われた際に返却されるようにする
- データを投げつける際はマスターだけでなくスレーブ全てに投げるものとする
- サブスクライブするクライアントはマスターと、スレーブのうちの1つで、合わせて2つのリレーサーバに接続するものとする
- どちらかかがダウンしたりサービスを停止したら、もう一つのスレーブに接続する
- マスターを主体として、常にスレーブは規定台数維持され、足りなくなれば新たに追加し、そのアドレスをクライアントに通知する
- マスターがいなくなった場合は一番古株のスレーブがマスターに成り代わり、新たなスレーブを1つ決定し、マスターが切り替わったことと、新たなスレーブのアドレスをクライアントに通知する
- あるユーザのデータを保持しているリレーサーバを、全てのリレーサーバが lookup することができるようになるため、当該ユーザのデータを取得したいユーザ(クライアント)は、初回は適当なリレーサーバにサブスクライブ要求を投げ、要求を受け付けたリレーサーバはその要求をHTTPでのリダイレクトのような形で担当リレーサーバに回し、リダイレクトされたクライアントは以後、リダイレクト先の担当リレーサーバにサブスクライブのリクエストを行う
DHTで担当サーバを決めるアーキの良いところと良くないところ
- 良いところ
- 良くないところ
- この手のものはうまく実装しないと期待通りに動かない場合が往々にしてある()
- クライアント観点では、フォローしているユーザにおおむね比例して接続すべきリレーサーバが増える
- 1つのリレーサーバは複数のユーザを担当することになるので、完全に比例するかと言えばそうではない
- ただし、接続数が増えはするが、受信しなければならないデータの量は基本的には変わらない(はず)
なんとなく思っていること
- Twittetrでも"クラスタ"などという言葉があるが、完全に、もしくはある程度、ソーシャルネットワークの中には分断が起きている
- この分断に着目し、ユーザ数の増加に真正面から対応するのではなく、分断されている"クラスタ"の中でのやりとりであれば大きな遅延なく行えることをターゲットとし、リレーサーバ・クライアントが連携して、上述の担当サーバが決まるようにできれば、フォローしてるユーザ数に(おおむね)比例してリレーサーバへの接続数が増えるようなことは避けられるのではないか、とか
- "クラスタ" うんぬんの話と同様に、フォロワーが非常に多いユーザは同じリレーサーバにまとめる、とかすれば良いのかも?
- 上の方で "リレーサーバのソフトウェアはもっとインテリジェントになる必要がある" と書いたが、そのあたりはこのセクションで記述した内容あたりにつながっていたりする
- リレーサーバがクライアントに言われた通りデータを格納し返すというだけでなく、扱っているデータの中の閲覧が許される部分の内容を分析して、他のリレーサーバと情報を共有するといったことをするようにならないと、ここで書いたようなことは実現できないはずである
ひとまず、以上!