PostgreSQL Advent Calendar 2025 (23日分)
23日の分を書かせてもらいました!
転職しました
掲題の通りです。
以上。
AndroidスマホでNostrP2Pのサーバが動いた
先日以下のような記事をQiitaに書いたのですが、サーバをずっと動かすとなるとそれが可能なマシンを用意できるか、持っているかが問題だよなー、とか考えてました。
で、そういえば、AndroidスマホならTermuxというAndroid端末内に独自Linux環境を構築するアプリがあるので、使わなくなったAndroidスマホなんかを有効活用して、サーバ動かしておくというのは悪くないのでは、と思い試してみたところ、見事動きました!
(そもそもAndroidはLinuxの一種なので、アプリがユーザに見せるシェルにおいてだけ、chrootでファイルシステムのルートの位置を変更して、あれこれ必要なファイルを配置してあげれば、独自のLinuxユーザランドが作れるよね、というのがTermux、という認識)
まずは、下のサイトなどを参考にしつつ、Fdroidアプリを経由してTermuxをインストール。
Termuxがインストールできたら以下のようにコマンドを実行すればサーバ起動までたどり着けます。
$ apt update $ apt upgrade $ apt install -y golang git $ git clone https://github.com/ryogrid/nostrp2p $ cd nostrp2p $ go build -o nostrp2p main.go $ ./nostrp2p server -l 0.0.0.0:20000 -p <npub形式の公開鍵> -b ryogrid.net:8888
あとは、スマホのIPアドレスを調べて、クライアントに指定すればOK。*1
ちゃんと、ブートストラップサーバにも接続できていました。
なお、サーバを止めるときは Ctrl + c でサーバプロセスを終了させて、exitコマンドでシェルを終了、からのTemuxを普通のアプリと同じように終了させるだけ。
Termuxで構築した環境が不要になった場合は、Termuxをアンインストールすれば、環境とその中で作ったファイル含めて削除してくれるはず。
以下、スクショ。


クライアントのサーバアドレス設定
(今回はWindows用のネイティブクライアントを使いました)

投稿してみたところ

ブートストラップサーバ(兼Trial用サーバ)への投稿データの転送(自分用サーバがブロードキャスト)も正常に行われ、Trial用サーバに接続したWebクライアントでもちゃんと表示されています。
いやー。Termuxすごいなー。
ピュアP2P分散マイクロブログシステムの第一歩
オーバレイでメッセージをブロードキャストできるだけのものができた!
https://github.com/ryogrid/buzzoon/releases/tag/v0.0.3
試し方(サーバ起動)
ryogrid.net:9999
ryogrid.net:8888
に既にオーバレイネットワークに参加しているサーバが2匹いるのでどちらかに接続。
バイナリはWin環境なら buzzoon.exe、Linux環境なら buzzon_linux、Mac環境ならbuzzoon_mac
ローカルのサーバは下のように起動
$ .\buzzoon.exe server -l 0.0.0.0:20000 -p 1985 -n ryo -b ryogrid.net:9999
- -l オプションはバインドするローカルアドレス
- -p オプションは本来は公開鍵を指定するのだけど署名の検証とか未実装なので、他の人と被らなそうな10進の整数を指定すればおけ
- これはオーバレイNW上でのノードIDとして使われる
- -n オプションはニックネームの設定。Nostrでいう所のkind-0相当をまだ実装していないので、これで指定したニックネームでメッセージが送信されるようにしてある
- -b オプションはオーバレイネットワークに既に参加しているサーバのアドレスを指定。とりあえず ryogrid.netの2ノードのうちのどちらかを指定すればOK
メッセージの送信
上の例だと、http://127.0.0.1:20001/postEvent にRESTのエンドポイントが立っているのでそれを叩く。
(ポートは-lオプションで指定したものに+1)
curlで叩くなら下のような感じ。
$ curl -X POST -H "Content-Type: application/json" -d '{"Content":"こんばんみ"}' http://127.0.0.1:20001/postEvent
レスポンス↓
{
"Status": "SUCCESS"
}
受信したメッセージはサーバのstdoutに出る。
良かったら試してみてね!
私の考える最強のNostrプロトコル拡張(考え中)
分散システムに明るいと自称している私なので、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でも"クラスタ"などという言葉があるが、完全に、もしくはある程度、ソーシャルネットワークの中には分断が起きている
- この分断に着目し、ユーザ数の増加に真正面から対応するのではなく、分断されている"クラスタ"の中でのやりとりであれば大きな遅延なく行えることをターゲットとし、リレーサーバ・クライアントが連携して、上述の担当サーバが決まるようにできれば、フォローしてるユーザ数に(おおむね)比例してリレーサーバへの接続数が増えるようなことは避けられるのではないか、とか
- "クラスタ" うんぬんの話と同様に、フォロワーが非常に多いユーザは同じリレーサーバにまとめる、とかすれば良いのかも?
- 上の方で "リレーサーバのソフトウェアはもっとインテリジェントになる必要がある" と書いたが、そのあたりはこのセクションで記述した内容あたりにつながっていたりする
- リレーサーバがクライアントに言われた通りデータを格納し返すというだけでなく、扱っているデータの中の閲覧が許される部分の内容を分析して、他のリレーサーバと情報を共有するといったことをするようにならないと、ここで書いたようなことは実現できないはずである
ひとまず、以上!
考察: Nostrプロトコルはオーバレイネットワークを構成するためのプロトコルなのではないか?
Nostrプロトコルって何やねんという方はまず以下の記事などを参照いただけると良いかと。
さて、読者の方々がNostrプロトコルの概要は理解している前提で以下、掲題に関して。
数日前にNostr(プロトコル上で構成されたTwitterライクなマイクロブログ)で follow している、あるユーザが、Nostr(プロトコル)はリレーサーバを信頼してないという点でP2Pと同じである、リレーサーバはただのハブである、といった主旨のことを投稿していて、それを読んでハッ!っとひらめいたことがあった。
それは、Nostrプロトコルというのは、本質的にはクライアントをノードとしてpeer-to-peerでやりとりできるオーバレイネットワーク(以降、オーバレイと略記)に近いものを構成するプロトコルなのではないか、という見方である。
- オーバレイでのアドレスは公開鍵
- クライアントがオーバレイ上でのノードに対応づく
- 公開鍵を指定することでP2Pでの通信が可能
- ただし受信されるのは受信側が送信元からのメッセージを待ち受けているタイミング
- 送信時に待ち受けている状態であれば、そのタイミングで受信される
- 受信側が待ち受けしない(=要していない)送信元からのメッセージは受信されない
- 一度送信したメッセージは送信時に相手がオフラインでも、ネットワークに復帰したタイミングで受信できる
- 他のノード群に、ゴシップブロトコル*1等による他のノードとの連携を要する手法を用いずに、比較的高速にメッセージのブロードキャスト/マルチキャストが可能
- なお、この通信においても、受信側のノードは、送信時にオフラインでも、オンラインに戻った際にメッセージを受信できる
で、上のような通信特性を実現しているのが、オーバレイの下のレイヤにいるリレーサーバである。
クライアントから受信したメッセージ*2は、必要があれば他のクライアントにブロードキャスト/マルチキャスト可能であるし、メッセージングミドルウェア(なんちゃらMQといった名前を持つ類のもの)のように、あるクライアントから受け取ったメッセージは、他方のクライアントがリレーサーバに接続して、メッセージの受信をサブスクライブした時点で送信してくれる*3。
オーバレイとして見ると、明確に当てはまらないのは自身や他のノードが、メタデータ(フォローしているユーザの情報、接続しているリレーサーバの情報)を、(脚注の条件を満たすもののうちの)任意のノード*4について、ネットワークから取り出せる点。
この点は、冒頭で"オーバレイネットワークに近いもの"と書いているように、素直にオーバレイネットワークを構成するもの、と言っていない理由の一つ*5。
こう整理すると、クライアントの仕事(必要な処理の総量)がやたらと多い*6のも納得がいく。
他には、例えば、リレーサーバに保持させておいたメタデータが消えてしまったり、内容が欠けてしまったりするのも、オーバレイのレイヤから見るとネットワークが提供する謎機能を使ってる以上仕方なく、オーバレイ上のノード(自身およびその他ノード)によるフォローが必要なのでは?という話になりそうである。
実際、手動にはなるが、Webサービスとしてメタデータが飛んだ場合の復元を可能とするためのサービスが有志により提供されているが、当該サービスは内部的にNostrプロトコルを扱っており、それは一種のクライアントで、オーバレイのレイヤでいえばノードである。
*1:あくまで一例。もっと効率的なプロトコルを利用可能なアーキテクチャをとっている分散システムも多数ある
*3:メッセージングミドルウェアのように到達保証まではしてくれないが
*4:少なくとも取得対象のメタデータの持ち主が当該情報を書き込む先の1つに設定していて、取得する側も当該情報の取得先の一つとして設定しているリレーサーバが存在する
*5:他のノードの助けを借りずに、時差ありでメッセージを受信可能な点や、ブロードキャストができる点もおかしいだろうという話はあるが、それぐらいは特殊なオーバレイである、という整理にしてしまってもよいかな、と
*6:少なくともTwitterライクなマイクロブログのアプリケーションなどでは、ユーザのクライアントに対する設定にもよるが、多数のリレーサーバとWebsocketコネクションを持ち、大量のメッセージを処理する必要があるケースが多い
A small resource consumption oriented Nostr Web client: algia-web
I developed a Nostr client called algia-web!
github.com
The client is listed at "awesome-nostr" page which is popular in Nostr related people, though the listing is requested by myself ^^;
