Skip to content

Instantly share code, notes, and snippets.

@ryogrid
Last active February 10, 2024 10:23
Show Gist options
  • Save ryogrid/e78088bc531bc62c10eba1c0d0e0b7fc to your computer and use it in GitHub Desktop.
Save ryogrid/e78088bc531bc62c10eba1c0d0e0b7fc to your computer and use it in GitHub Desktop.
gossipプロトコルベースのオーバレイネットワーク構築ライブラリ Gossip Overlayの実装TODO
■meshとpion/sctpとpion/datachannelを使ったオーバレイネットワーク構築用ライブラリ Gossip Overlayの開発
・【済】read済みのデータをバッファから取り除く
・【済】ローカルのバッファを触る時はconnオブジェクトのmutexのロックをとって行うようにする
・【済】複数のノードとやりとりしても問題ないようにする(meshライブラリのユニキャストを使う時の話)
・【済】meshのオリジナルをimportする形(修正無し)で動作に問題ないか確認する
・【済】password を nil にしなかった場合に暗号化がなされるのか、なされるならどの範囲までか、を確認
 => 同一のpasswordを設定しているノードしか同一のネットワークには参加できない模様。中継も含めて、
   おそらく・・・ノード間の通信は暗号化されている
・【済】新たなデータを受信するまでreadがブロックするようにする(プロキシデーモンの形にする時に必要、と思われる)
・【作業中】ノード間ごとの通信路(conn?)を双方向通信可なチャネルとして抽象化する(コネクションの概念を導入する)
 -【済】一方のノードが一度離脱した後に再度データ送信をはじめた場合にシーケンス番号の整合性がおかしくならないようにする
    (セッションの開始の通知が必要?)
 -【済】SCTPコネクションの一端のピアが離脱した場合に、現在の実装でTCPなどと同様に接続断が発生するのか、の検証
      => 起きない模様
 -【断念】listen してコネクションが確立されたらコネクションに対応するオブジェクトを返して別スレッドに渡したりできるようにする
      (Listenするstreamは常に1つのみ存在する状態にして、そのstreamで得た接続元ピアとstream IDの情報を利用して、Client to Client のstreamを張る)
      -【済】TODOコメントを実装必要な個所に記述
      -【済】TODOコメントの箇所を実装
      -【断念】stream確立後に双方が好き勝手にwrite、readしても動作するか確認
      - 確立したstreamのCloseが他方に伝わるかの確認(C2C stream張る用情報取得用stream、C2C streamの両方)
      - 複数ピアからの接続が動作するかの確認
      - 同一ピアとの異なるstream IDでの複数streamが動作するかの確認
      - BがListenしつつ、ListenしてるピアCへ接続して、A <-> B <-> C というような通信が動作するかの確認
 -【済】pion/datachannel で pion/sctp のストリームをラップしてデータチャネル化する
 -【済】現在のコードに修正を入れて、双方のアドレスを最初から知っている前提で、クライアント to クライアントの
       チャネル確立が動作するか確認
      (基盤コードへの修正でデグレしていないかの確認)
 -【済】1つのピアにおいて、複数のチャネル(クライアントtoクライアント)が張れるかのスパイク
     具体的には、A <-> B 、B <- > C という2つのチャネルが張れて、各々が通信できる
     この確認でも、各ピアは最初から接続先ピアの情報を最初から知っている前提
     https://github.com/ryogrid/gossip-overlay/commit/c8697bf3b9ac0fa43b5bb74c98e054cdcd519dd0
 -【済】A <-> B 、B <- > C と通信をしている際に、Bが2つ両方のチャネルをcloseもしくは、対応するAssociationのshutdownを
     行うことで、AとCが切断を検出できることを確認
     https://github.com/ryogrid/gossip-overlay/commit/aae4fb2bd433a8675c7165f3e3cacbfdd03b8236
 -【済】上の確認において、B <-> C の通信を Associationのshutdownにより行った場合に、他方での通信が問題なく継続される
     ことを確認
     https://github.com/ryogrid/gossip-overlay/commit/5bcac3f2871ced26efc31834c277745ed11efec8
 -【済】同一ピアから同一ピアへ複数チャネルを張る際に、新たにAssosiationオブジェクトを生成する形でチャネルが並立できる
     かの確認。また、一方のAssosiationオブジェクトのshutdownが他方に影響を与えないかの確認も必要
     => B -> C , B <- C と合った時に B が前者をshutdownした。上記は確かであったが、Cにおいてdisconnectionが検出
      されなかったという点は問題として残った ←★★★
      同一ピア間での複数channelなのが原因?タイミング問題?
      https://github.com/ryogrid/gossip-overlay/commit/0d26e65a354e84e4f50c6f659c5d037d02e08249
 -【ダメそうだった】pion/dtls を pion/sctp の下に挟むことができて、かつ、そうするとdisconnectionの検出がうまくいったりしないか試してみる
 -【済】GossiopSessionの実装の修正によって、上の明なcloseでもdisconnectionがdetectできなかったケースをdetectできるようにする
 -【済】datachannelを使うようにしたら暗にdisconnectされた場合でも検出できるか確認
     => されなかった
 -【済】意図的にパケットロスさせた時に再送が行われるか確認する
    => アプリケーションレイヤから見るには再送されたと思われる
    https://github.com/ryogrid/gossip-overlay/commit/d6fc41011fdb1f77b128f39d35dd27993a0ded24
 -【済】上の方での"C2C stream張る用情報取得用stream" 的なところを pion/sctp は用いずに、meshによるオーバレイ上に独自実装
     する
     要は3wayハンドシェイク的なところをある程度信頼性のある形(もしくは失敗した場合は失敗したと分かる形)で実装して、
     元々のサーバ側にクライアント側のアドレス(とストリームの固有ID)が通知できて、相互にクライアントtoクライアントの
     接続確立の処理を初めるタイミングについてある程度の同期がとれれば良い。
    (2wayだと、クライアント側へのレスポンスがロストした時に、サーバ側だけ接続処理を開始してしまうので、ダメ・・・だと思う)
-【済】同一ピアへのchannelを増やす場合、既存のAssosiateオブジェクト?でstream IDの異なるものを張る形にしないといけないか
     確認して、そうであれば、そういう形に修正(1channel 1OverlayClientというI/Fの見直しが必要になりそう・・・)
     => 異なるAssosiateオブジェクトで問題なかったので、既存のI/Fのままでいけた
・【済】デバッガを使える状態にする
・【済】ライブラリとして使える形にする
・【済】ライセンス回りを整理する
・【済】単純なユースケースのアプリケーションに組み込んでみて、通信の安定性やら、(明な)channelの切断時の動作に問題ないか確認
     => https://github.com/ryogrid/gossip-port-forward にて確認した。SSHの通信なんかも特に問題なく通っている模様
・【済】タイムアウト回りの実装が不十分であったため修正(ただ、タイムアウトが発生するケースのテストはできていない・・・)
・【済】DataChannelオブジェクトをcloseしても通信相手にその情報が伝わらないことを忘れていたので対処
     AssociationオブジェクトのShutdownも併せて実施するOverlayStreamクラスを追加。
     各種アプリケーションでは、OverlayStreamオブジェクトを扱うよう修正
・【済】gossip-overlay-streamのドキュメントをもう少し書き足す(ブートストラップノードのことや、中継が平文で行われる
    ことを書いておかないと)
・【済】channelを張っている状態で一方のピアのプロセスが突然終了するなどした場合に、他方のReadやWriteがエラーとなるように
    => gossipレイヤで定期的にハートビートを送ってリモートピアの生死監視をするようにした
・【済】作ったライブラリでGolangによるChord実装のgord (https://qiita.com/taisho6339/items/7f849b65e2deab6759a1) を
    オーバレイ上で動作するようにしてみる(put、getのI/Fを内部的にも、外部向けにも持っていないのでそこの実装も必要)
 -【済】ひとまず、データのputが全ノードが揃ってstabilizeされた後でしか起きない前提でのput、getを実装
    (ノード参加による担当範囲の変更が起きない前提なのでノード間のデータの委譲は実装しない。put時の
     レプリケーションも行わない)
 -【済】connect-goでprotoファイルからコード生成する際の手順をドキュメント化しておく
 -【済】gossip-overlayで構成したネットワーク上で動作するように修正する(現状、かなり不安定かつ低速)
 -【済】オーバレイ上でのコネクションの確立が滅茶苦茶に遅いので、アプリケーションからは透過的にOverlayStreamに
     対応するコネクションをプーリングする(サーバ側やクライアント側がcloseを呼んでも残る。サーバ側とクライアント側で
     利用するコネクションを対応づけるための、信頼性のある通信路をホスト間に一つ用意する必要がありそう)
     => connect-go で生成したRPCコードをHTTP/2で動くようにする形で解決。ただし、TCPではうまくいくが、
       オーバレイ通信を行わせるとうまくいかなかった(gossip-overlayかgord-overlayの実装の問題と思われる)
       ので、オーバレイNW上で通信させる処理をプロキシとして切り出すことでどうにかした
・ HTTPコネクションが切れてしまった場合の異常系の実装
・put/getを開始した後でのノード参加とノードダウンを想定したput、getの実装
 (put時のレプリカの作成および、get時のマスタがダウンしていた場合のレプリカの取得)
・ノード参加時およびノードダウン時のデータの担当範囲変更とレプリカ担当ノード数の維持
 (ノード間でのデータの委譲や、レプリカデータの複製が必要)
・クライアント側の情報通知のためのハンドシェイク的なものがパケットロストなどで失敗した際に
 期待通りリトライされるかのテスト(実装はされているがテストはされていない状態)
 ↑できれば、複数プロセスでのテストの仕組みの整備をここでしておきたい
・ネットワーク上のピアのリストを取得できるようにする
・ブロードキャストもできるようにする?(信頼性のあるものにしようとした場合、全ノードにユニキャストするような実装に
 なりそうだが、それだとgossipプロトコルベースである利点が活かせていない感もある。単発のパケット発信(つまり小メッセージ)
 に要件を限定すればmeshライブラリのブロードキャストで到達性は担保される・・・と思われる
・任意のプログラムからオーバレイネットワークに参加できるようにするプロキシを書く
 (対象のプログラムにおけるノードのIDからgossip-overlayの64bit uintのIDが一意に求められるなら、
  分散KVSのオーバレイ化の時に作成したものとほぼ同様にして、コネクション確立時(プロキシへの接続時)、
  最初にコネクション確立対象ノードの64bit ノードIDを書き込んでもらえば、最低限通信できるようにする
  ことは可能)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment