Rust製のRaftライブラリについては続けている。Rustは、実用的にはとてもいい言語だと思う。
https://github.com/akiradeveloper/sorock
前回は、In-process Multi-Raft(おれが勝手にこう呼んでるだけ)に振り切ったことを話した。
かなり完成に近づいてきたので記事にしておく。まず名前だが、Sorockに変更した。これはおれの母校である麻布高校の創始者の江原素六に由来する。
さて前回、In-process Multi-Raftにする理由はノードのリソースをシャード間で共有することで効率的な実装が可能だからだと話したが、これについては大きなものを2つ実装している。
1つは、ハートビートの最適化である。仮に各シャード(シャードは1000個くらいはあると思ってほしい)がハートビートを定期的に送信すると、大量のハートビートがネットワークを行き交うことになる。これは、ものすごく効率が悪い。そこで解決案として、ノードを出る時にバスに「あいのり」して、RPC数を劇的に減らすことにした。
もう1つの最適化は、これも似たような話なのだが、各シャードが各々にログストレージを独立に持って書き込むのはかなり効率が悪い。そこで、1つのストレージから各シャード向けに仮想的なログを作り出し、そこへの書き込みがバッチ書き込みされるようにした。バッチ書き込みをするとレイテンシが気になるところではあるが、そもそもがRaftというソフトウェアはネットワークを介するから、少なくともそのオーダーのレイテンシごときは許されることになる(もっというと、エントリを適用するためにはレプリケーションをしてコミットを進めないといけないので、書き込みはそもそもレイテンシがかなり高い)。そのように調整したら、レイテンシをあまり損なわずに効率を上げることに成功した。
設計自体もかなり変更した。
まず、APIをシンプルにするため、ログや投票を管理するための構造を抽象化するのをやめて、redbと心中することにした。この決定は賛否あると思うが、決定要因としては純粋Rust製であることが大きく、他のストレージを使う気がしなかった。
内部的な設計もかなり変更した。
大きなところでいうと、シャード上のRaftプロセスを表すRaftProcessという構造があるが、こいつはgRPCについては何も知らないようにした。そして次の段階としてgRPCでノード間RPCを送る能力(送信能力)を与えて、その後、サーバとしての能力(受信能力)を与えるという形にコードを分離した。これは当たり前の設計のように感じるかも知れないが、恐ろしい量の変更を必要とした。
Raftは2014年だかに発表されたアルゴリズムで、非常に美しいアルゴリズムであるため多くの人が自作している。最近ではマグロという人も2025年にもなって自作したいと言いだしたようだ。大学院の授業で触れて感動したからだという。まぁ、感動するだろうなとは思う。おれもしたので。
https://www.docswell.com/s/magurotuna/KV19NP-2025-01-22-osaki-rs-3
ただ、ネットにはものすごくたくさんの実装が存在するのだが、どれもこれもゴミだと思っている。美しいだけの実装だったり、最適化が不十分だったり。
Sorockは本気だ。本気で汎用的で、本気で効率的で、真に正しい実装を目指している。おれが真に最高だと思える実装を目指している。
おれ自身、最初に論文を読んで実装をしたのが2015年だかでその時はScala製で、その後2020年にRust製に着手して今に至るので実に長い時間かけてRaft実装に取り組んでいることになるが、自身の最終魔法詠唱のつもりでやっている。
この戦いが終わったら、おれは人間どもから離れるため山に籠もり、熊とコーヒーを飲みながら囲碁を打つような生活をする予定だ。そしてその時はそう遠くないように思っている。
