LMAXのチームは、彼らがどのようにして実行できたかについてプレゼンテーションを行っています 1ミリ秒未満のレイテンシで100k TPS 。彼らは a blog 、 technical paper(PDF) および source code 自体でそのプレゼンテーションをバックアップしています。
最近 Martin Fowler が LMAXアーキテクチャに関する優れた論文 を公開し、毎秒600万の注文を処理できるようになり、チームが実行するいくつかのステップを強調していますパフォーマンスがさらに1桁上がりました。
これまで、ビジネスロジックプロセッサの速度の鍵は、すべてをメモリ内で順番に実行することであると説明しました。これを行うだけで(実際に何もばかげたことはありません)、開発者は10K TPSを処理できるコードを作成できます。
次に、優れたコードの単純な要素に集中すると、これを100K TPSの範囲に引き上げることができることがわかりました。これには、適切に因数分解されたコードと小さなメソッドが必要です。基本的にこれにより、Hotspotは最適化のより良い仕事を行うことができ、実行中のコードをキャッシュする際にCPUがより効率的になります。
別の桁に上がるには、もう少し賢さが必要でした。 LMAXチームがそこに到達するのに役立つとわかった点がいくつかあります。 1つは、Javaコレクションのカスタム実装を書くことでした。これらは、キャッシュフレンドリーでガベージに注意するように設計されています。
その最高レベルのパフォーマンスに到達するためのもう1つの手法は、パフォーマンステストに注意を向けることです。私は人々がパフォーマンスを改善するためのテクニックについて多くのことを話していることに長い間気づきましたが、本当に違いを生むのはそれをテストすることです
ファウラーは発見されたものはいくつかあると述べたが、彼はカップルについてのみ言及した。
そのようなレベルのパフォーマンスを達成するのに役立つ他のアーキテクチャ、ライブラリ、テクニック、または「もの」はありますか?
高性能トランザクション処理にはあらゆる種類のテクニックがあり、Fowlerの記事にあるテクニックは、最先端の多くの技術の1つにすぎません。誰かの状況に適用できるかどうかに関係なく、一連のテクニックをリストするのではなく、基本的な原則と、LMAXがそれらの多くに対処する方法について説明する方がよいと思います。
大規模なトランザクション処理システムの場合、次のすべてを可能な限り実行する必要があります。
最も遅いストレージ層で費やされる時間を最小限に抑えます。あなたが持っている最新のサーバーで最も速いものから最も遅いものへ:CPU/L1-> L2-> L3-> RAM->ディスク/ LAN-> WAN。最速の最新の磁気ディスクからのジャンプ最も遅いRAMはsequentialアクセスで1000倍以上です;ランダムアクセスはさらに悪いです。
費やす時間を最小化または排除します待機中。これは、可能な限り少ない状態を共有することを意味します。また、状態mustが共有される場合、可能な限り明示的なロックを回避します。
ワークロードを分散します。 CPUは過去数年でそれほど高速化していませんが、haveは小さくなり、サーバーでは8コアがかなり一般的です。さらに、Googleのアプローチである複数のマシンに作業を分散することもできます。これの素晴らしい点は、I/Oを含めてスケールアップすることですすべて。
Fowler氏によると、LMAXはこれらのそれぞれに対して次のアプローチをとっています。
allの状態でメモリにall状態を保持します。ほとんどのデータベースエンジンは実際にこれを行いますifデータベース全体がメモリに収まりますが、偶然に何かを残したくはありません。リアルタイム取引プラットフォームで理解できます。大量のリスクを追加することなくこれを実現するには、軽量のバックアップおよびフェイルオーバーインフラストラクチャを数多く構築する必要がありました。
入力イベントのストリームには、ロックフリーキュー(「破壊者」)を使用します。従来の耐久性のある メッセージキュー とは対照的notロックフリーであり、実際には通常、非常に遅くなる 分散トランザクション を伴います。
あまりない。 LMAXは、ワークロードが相互依存していることに基づいて、これをバスの下にスローします。 1つの結果が他のパラメータを変更します。これはcriticalの警告であり、Fowlerが明示的に呼び出すものです。 someフェイルオーバー機能を提供するために同時実行を使用しますが、すべてのビジネスロジックは単一スレッドで処理されます。
LMAXはnotが大規模OLTPへの唯一のアプローチです。そして、それ自体は非常に優れていますが、notそのレベルのパフォーマンスを引き出すためには、最先端の手法を使用する必要があります。
上記のすべての原則のうち、ハードウェアが安価であるため、#3がおそらく最も重要で最も効果的です。ワークロードを6ダースのコアと数ダースのマシンに適切に分割できる場合、空は従来の Parallel Computing 技術の限界です。大量のメッセージキューとラウンドロビンディストリビューターだけで、どれほどのスループットを引き出すことができるかに驚かれることでしょう。それは明らかにLMAXほど効率的ではありません-実際にはそれほど接近していません-しかし、スループット、待ち時間、および費用対効果は別の問題であり、ここでは特にスループットについて話しています。
LMAXが行うのと同じ種類の特別なニーズがある場合、特に、急いで設計を選択するのではなく、ビジネスの現実に対応する共有状態の場合は、それらのコンポーネントを試してみることをお勧めします。それ以外の場合は、これらの要件に適しています。ただし、単に高いスケーラビリティについて話している場合は、分散システムについてさらに調査することをお勧めします。分散システムは、現在ほとんどの組織で使用されている標準的なアプローチです(Hadoopおよび関連プロジェクト、ESBおよび関連アーキテクチャ、Cowlers、Fowlerも言及など)。
SSDもまた、画期的なものになるでしょう。間違いなく、彼らはすでにそうです。これで、RAMへのアクセス時間が同等の永続的なストレージを利用できます。サーバーグレードのSSDは依然として非常に高価ですが、採用率が高まると、最終的に価格が下がるようになります。 広範囲にわたって調査されています そして結果はかなり心が揺らぎ、時間の経過とともに良くなるだけなので、「メモリにすべてを保持する」概念全体は、以前よりも重要度が低くなっています。したがって、もう一度、可能な限り並行性に焦点を当てようと思います。
これから学ぶ最大の教訓は、基本から始める必要があるということです。
パフォーマンステストでは、コードをプロファイリングしてボトルネックを見つけ、1つずつ修正します。
「1つずつ修正する」部分にすぐにジャンプする人が多すぎます。彼らは「Javaコレクションのカスタム実装」」を書くのに多くの時間を費やしています。なぜなら、彼らのシステムが遅い理由の全体はキャッシュミスが原因であると知っているからです。それが原因となるかもしれませんが、しかし、そのような低レベルのコードを微調整するためにすぐにジャンプすると、LinkedListを使用する必要があるときにArrayListを使用するという大きな問題を見落とす可能性があります。または、システムが遅い本当の理由は、ORMが遅延しているためです。 -エンティティの子をロードし、リクエストごとにデータベースへの400回の個別のトリップを実行します。
LMAXコードについては十分に説明できないと思うので、特にコメントしませんが、パフォーマンスを大幅に向上させることができた例をいくつか紹介します。
いつものように、これらは問題があり、パフォーマンスを向上させる必要があることがわかったときに適用する必要があるテクニックです-そうでない場合、時期尚早の最適化を行っている可能性があります。
finalでJITコンパイラを支援-フィールド、メソッド、クラスをfinalにすることで、JITコンパイラを実際に支援する特定の最適化が可能になります。具体的な例:
コレクションクラスを配列で置き換える-これにより、コードが読みにくくなり、保守が難しくなりますが、間接的な層がなくなり、利点が得られるため、ほとんどの場合は高速になりますたくさんのニースのアレイアクセス最適化。通常、ボトルネックとして特定した後の内部ループ/パフォーマンスに敏感なコードでは良い考えですが、読みやすくするためにそれ以外は避けてください。
可能な限りプリミティブを使用する-プリミティブは、オブジェクトベースの同等のものよりも根本的に高速です。特に、ボクシングは大量のオーバーヘッドを追加し、厄介なGCの一時停止を引き起こす可能性があります。パフォーマンス/レイテンシを気にする場合は、プリミティブをボックス化しないでください。
最小限の低レベルのロック-ロックは低レベルでは非常に高価です。完全なロックを回避する方法、または大まかなレベルでロックする方法を見つけてください。大規模なデータブロックに対して頻繁にロックする必要がなく、ロックや同時実行の問題を心配することなく低レベルのコードを実行できます。
Aaronaughtからの優れた回答ですでに述べられている以外に そのようなコードは、開発、理解、デバッグが非常に難しい場合があることに注意したいと思います。 LMAXブログ で言及されている彼らの一人として、「非常に効率的ですが...失敗するのは非常に簡単です...」.
上記を踏まえると、Disruptorや類似のアプローチを選択する方が、ソリューションを維持するのに十分な開発リソースを確実に確保できると思います。
全体として、Disruptorアプローチは私にとって非常に有望に見えます。たとえば上記の理由で会社がそれを利用する余裕がない場合でも、それを研究するために何らかの労力を「投資」するよう経営陣に説得することを検討してください(そして [〜#〜] seda [〜#〜] 一般的に) -そうしないと、ある日、顧客が、4倍、8倍などの少ないサーバーを必要とする、より競争力のあるソリューションを支持する可能性があるためです。