LavinMQ: 最高のパフォーマンスを得るためのコード理解

CrystalでLavinMQを構築することは、コードベースの制御を優先事項とした積極的な選択でした。10年にわたる学習により、迅速な更新と簡単なバグ修正が優先されてきました。同時に、Crystalを選択したことで、アプリケーションのパフォーマンスを向上させる機会が得られました。
LavinMQは、最大のクラウドメッセージングプラットフォームの1つであるCloudAMQPの創設者である84codesの経験豊富な開発者によって構築されました。サービス内およびサービス間の安定した通信と信頼性の高いメッセージ配信を優先することにより、LavinMQはデータを迅速かつ効率的に処理するように構築され、分離されたシステムコンポーネントが独立して動作し、必要に応じてスケーリングできるようにしました。
LavinMQは、パブリッシャー、キュー、コンシューマー間の多数の接続を処理できます。これは、たとえばIoTアーキテクチャでしばしば必要とされるものです。これは、他のブローカーと比較して非常に高速になるように事前に最適化されたオープンソースのメッセージブローカーであり、1秒あたり100万件のメッセージを簡単に処理できます。
LavinMQには、人々が最も望むすべての機能が含まれており、小さなメモリフットプリントのみを残し、以下をサポートします。
- ストリーミング
- 柔軟なルーティング
- AMQP 0.9.1プロトコル
- 確認応答と確認
- ストリームキュー
- 無制限のキュー長(ディスクスペースに依存)
- レプリケーション
技術的な観点から際立つ特徴を強調しました。どのようにして1秒あたり100万件以上のメッセージを処理し、メモリフットプリントを低く抑えることができるのでしょうか。その半分は、以下の引用によるものです。
メッセージは非常に高速にディスクに書き込まれ、キャッシュはOS自体によって管理されます。これにより、RAMフットプリントを低く抑えながらパフォーマンスが向上します。
しかし、彼らのブログで述べられているように、もう半分はCrystalで開発されていることによるものです。そして、これはいくつかの興味深い方法で実現します。
-
Crystalは、LLVMバックエンドのおかげで効率的にコンパイルされます。これにより、メソッドのインライン化や間接参照の削除などの積極的な最適化が可能になります。
-
Crystalは、開発者がヒープまたはスタックのいずれかにデータを割り当てるのに役立ちます。ヒープ割り当てはコストがかかるため、プログラムのホットパスでスタックにデータを割り当てることで、パフォーマンスが大幅に向上します。Crystalを使用すると、データの保存場所を簡単に選択できます。
-
Crystalのstdlibとコンパイラは、Crystal自体で記述されています。Crystalの優れた特徴の1つは、その読みやすさであり、別の、通常は低レベルの言語に頼ることなく、プログラムによって実行されるコードを読むことができます。
後者が、この投稿の主なポイントです。実際、標準ライブラリのドキュメントはコードを指し示しており、特定のメソッドを呼び出すことによるパフォーマンスへの影響を明確にしています。たとえば、Digest.file
のドキュメントをご覧ください。ソースを表示をクリックすると、メソッドのコードに移動します。
言語とそのstdlibを読み、理解し、さらには貢献できることの重要性は、84codesがCrystalに貢献した1つのいくつかのPRで例示されています。詳細は重要ではありませんが、興味があれば、前述のDigest
クラスのメソッドにバッファリングの重複があることに気づきました。次の抜粋は、貢献の主要部分を示しています。追加された行の差分と、io
オブジェクトのバッファリングを削除することが理にかなっている理由を説明するコメントです。
diff --git a/src/digest/digest.cr b/src/digest/digest.cr
index e6a401e90545..bc38599da7f8 100644
--- a/src/digest/digest.cr
+++ b/src/digest/digest.cr
@@ -213,6 +213,7 @@ abstract class Digest
# Reads the file's content and updates the digest with it.
def file(file_name : Path | String) : self
File.open(file_name) do |io|
+ # `#update` works with big buffers so there's no need for additional read buffering in the file
+ io.read_buffering = false
self << io
end
end
ほんの小さな1行ですが、アプリケーションに大きな影響を与える可能性があります。アプリケーションとコードが依存するライブラリに同じ言語を使用することは、コードの動作とそのパフォーマンスへの影響を理解する上で大きな利点です。
最後に、84codesは標準ライブラリへの多数の改善を担当しているだけでなく、Crystalの開発を支援する主要なスポンサーでもあることに注意したいと思います。言語の限界をさらに押し広げるために、執筆時点では、Crystalプログラムの並列実行を改善するための大きな取り組みを支援しています。おそらく、LavinMQの次のバージョンは、Crystalチームの助けを借りて、さらに限界を押し広げるでしょう!

カール・ホアベルグ、CEO、84codes
Crystalは、読みやすさとパフォーマンスを独自にバランスさせています。さらに、アプリケーションを実行する基礎となるコードを理解できることで、アプリケーションのパフォーマンスを向上させることができます。