3. Kafkaシリーズの設計思想 (1)

最近、公式ドキュメントを読んでいたのですが、Chapter 4 DESIGN の内容はとても良いと思いますので、共有したいと思います。

4.1 モチベーション モチベーション

Kafka は、大企業が持つ可能性のあるすべてのリアルタイム データ フィードを処理するための統合プラットフォームとして機能できるように設計されています。これを行うには、かなり幅広いユースケースを検討する必要がありました。

Kafka は、大企業が持つ可能性のあるすべてのリアルタイム データ フィードの統合プラットフォームとして機能するように設計されています。このためには、かなり幅広いユースケースを考慮する必要があります

リアルタイムのログ集約など、大量のイベント ストリームをサポートするには、高いスループットが必要です。

リアルタイムのログ集約など、大量のイベント ストリームをサポートするには、高いスループットが必要です。

オフライン システムからの定期的なデータ ロードをサポートできるようにするには、大量のデータ バックログを適切に処理する必要があります。

オフライン システムからの定期的なデータ ロードをサポートできるようにするには、大量のデータ バックログを適切に処理する必要があります。

また、従来のメッセージングのユースケースを処理するには、システムが低遅延の配信を処理する必要があることも意味していました。

これは、従来のメッセージングのユースケースを処理するために、システムが低遅延の配信を処理する必要があることも意味します。

新しい派生フィードを作成するために、これらのフィードの分割分散リアルタイム処理をサポートしたいと考えていました。これが、私たちのパーティショニングとコンシューマー モデルの動機となりました。

新しい派生フィードを作成するために、これらのフィードの分割分散リアルタイム処理をサポートしたいと考えています。これが、パーティション モデルとコンシューマー モデルの動機となります。

最後に、ストリームが提供のために他のデータ システムに供給される場合、マシンの障害が発生した場合でもシステムがフォールト トレランスを保証できる必要があることはわかっていました。

最後に、ストリームがサービスのために他のデータ システムに供給される場合、システムがマシン障害の場合にフォールト トレランスを保証できなければならないことがわかっています。

これらの用途をサポートすることで、従来のメッセージング システムよりもデータベース ログに似た、多数の独自の要素を備えた設計に至りました。以下のセクションでは、設計のいくつかの要素について概説します。

これらの用途をサポートすることで、従来のメッセージング システムよりもデータベース ログに似た独自の要素を多数設計することになりました。以下のセクションでは、設計のいくつかの要素について概説します。

4.2 持続性 持続性

ファイルシステムを恐れるな! ファイルシステムを恐れるな!

Kafka は、メッセージの保存とキャッシュをファイルシステムに大きく依存しています。「ディスクは遅い」という一般的な認識があり、永続的な構造が競争力のあるパフォーマンスを提供できるかどうかについて懐疑的です。実際、ディスクは、使用方法に応じて、人々が予想するよりもはるかに遅くも速くもなります。また、適切に設計されたディスク構造は、多くの場合、ネットワークと同じくらい高速です。

Kafka は、ファイル システムに大きく依存してメッセージを保存およびキャッシュします。「ディスクは遅い」という一般的な認識は、永続的な構造が競争力のあるパフォーマンスを提供する能力に疑問を投げかけています。実際、ディスクは、使用方法によっては、予想よりもはるかに遅くなったり速くなったりします。適切に設計されたディスク構造は、通常、ネットワークと同じくらい高速です。

ディスク パフォーマンスに関する重要な事実は、過去 10 年間、ハード ドライブのスループットがディスク シークのレイテンシーから逸脱しているということです。その結果、6 つの 7200rpm SATA RAID-5 アレイを備えた JBOD 構成での線形書き込みのパフォーマンスは約 600MB/秒ですが、ランダム書き込みのパフォーマンスは約 100k/秒に過ぎず、6000 倍以上の差があります。これらの線形読み取りおよび書き込みは、すべての使用パターンの中で最も予測可能であり、オペレーティング システムによって大幅に最適化されています。最新のオペレーティング システムは、大きなブロック倍数でデータをプリフェッチし、小さな論理書き込みを大きな物理書き込みにグループ化する、先読みおよび後書きの手法を提供します。この問題の詳細については、この ACM キューの記事を参照してください。実際、シーケンシャル ディスク アクセスは、場合によってはランダム メモリ アクセスよりも高速であることがわかります。

ディスク パフォーマンスに関する重要な事実は、過去 10 年間で、ハード ドライブのスループットがディスク シークの遅延とは異なることです。したがって、6 つの 7200rpm SATA RAID-5 アレイを備えた JBOD 構成では、線形書き込みパフォーマンスは約 600MB/秒ですが、ランダム書き込みパフォーマンスは約 100k/秒にすぎません。これは 6000 倍以上の差です。これらの線形読み取りおよび書き込みは、すべての使用パターンの中で最も予測可能であり、オペレーティング システムによって大幅に最適化されています。最新のオペレーティング システムは、複数の大きなブロックでデータをプリフェッチし、小さな論理書き込みを大きな物理書き込みにグループ化するための、先読みおよび後書きの手法を提供します。この問題の詳細については、この ACM キューの記事を参照してください。実際に、場合によってはシーケンシャル ディスク アクセスがランダム メモリ アクセスよりも高速になることがわかりました。

このパフォーマンスの相違を補うために、最新のオペレーティング システムは、ディスク キャッシュ用のメイン メモリの使用をますます積極的に行っています。最新の OS は、メモリが再利用されたときにパフォーマンスの低下をほとんど伴わずに、すべての空きメモリをディスク キャッシュに喜んで転用します。すべてのディスクの読み取りと書き込みは、この統合されたキャッシュを経由します。この機能は、ダイレクト I/O を使用しないと簡単にオフにできないため、プロセスがデータのインプロセス キャッシュを保持している場合でも、このデータは OS ページキャッシュに複製され、事実上すべてが 2 回保存されます。

このパフォーマンスの違いを補うために、最近のオペレーティング システムでは、ディスク キャッシュにメイン メモリを使用することが増えています。メモリを再利用する場合、最近のオペレーティング システムは、ほとんどパフォーマンスを低下させることなく、すべての空きメモリをディスク キャッシュに喜んで移動します。すべてのディスクの読み取りと書き込みは、この統合されたキャッシュを経由します。これは、ダイレクト I/O を使用しないと簡単にオフにできないため、プロセスがデータのインプロセス キャッシュを維持している場合でも、そのデータが OS ページ キャッシュに複製され、事実上すべてが 2 回保存される可能性があります。

さらに、私たちは JVM の上に構築しており、Java のメモリ使用量に時間を費やしたことがある人なら誰でも、次の 2 つのことを知っています。

また、私たちは JVM の上に構築されており、時間を割いて Java のメモリ使用量を研究したことのある人なら誰でも、次の 2 つのことを知っています。

1. オブジェクトのメモリ オーバーヘッドが非常に高く、多くの場合、格納されるデータのサイズが 2 倍になります (またはさらに悪化します)。

オブジェクトには非常に高いメモリ オーバーヘッドがあり、多くの場合、保存されるデータのサイズが 2 倍になります (またはさらに悪化します)。

2. Java ガベージ コレクションは、ヒープ内データが増加するにつれて、ますます面倒で遅くなります。

Java Garbage Collection は、ヒープ内のデータが大きくなるにつれて、扱いにくく遅くなります

これらの要因の結果として、ファイルシステムを使用し、ページキャッシュに依存することは、メモリ内キャッシュまたはその他の構造を維持するよりも優れています。すべての空きメモリに自動的にアクセスできるようにすることで、利用可能なキャッシュを少なくとも 2 倍にし、コンパクト ファイルを格納することでさらに 2 倍にする可能性があります。個々のオブジェクトではなくバイト構造。そうすることで、GC のペナルティなしで、32GB のマシンで最大 28 ~ 30GB のキャッシュが得られます。さらに、このキャッシュはサービスが再起動されてもウォームのままですが、インプロセス キャッシュはメモリ内で再構築する必要があります (10 GB のキャッシュの場合は 10 分かかる場合があります)。それ以外の場合は、完全にコールド キャッシュで開始する必要があります。 (これはおそらくひどい初期パフォーマンスを意味します)。また、キャッシュとファイルシステム間の一貫性を維持するためのすべてのロジックが OS 内にあるため、コードが大幅に簡素化されます。これは、一度限りのインプロセス試行よりも効率的かつ正確に行う傾向があります。ディスクの使用状況が線形読み取りを優先する場合、先読みは、ディスク読み取りごとに有用なデータをこのキャッシュに効果的に事前入力します。

これらの要因により、ファイルシステムを使用してページ キャッシュに依存することは、メモリ内キャッシュやその他の構造を維持するよりも望ましいことです。利用可能なすべてのメモリに自動的にアクセスすることで、利用可能なキャッシュを少なくとも 2 倍にし、場合によってはコンパクト バイトを保存することでさらに 2 倍にします。個々のオブジェクトではなく構造。これを行うと、GC ペナルティなしで 32 GB のマシンで最大 28 ~ 30 GB のキャッシュが作成されます。また、サービスが再起動されても、このキャッシュはウォームのままですが、インプロセス キャッシュはメモリ内で再構築する必要があります (10 GB キャッシュの場合は 10 分程度)、または完全にコールド キャッシュから開始する必要があります (これは、初期パフォーマンスが低いことを意味する場合があります)。これにより、キャッシュとファイルシステム間の一貫性を維持するためのすべてのロジックが OS 内にあるため、コードが大幅に簡素化されます。これは、多くの場合、1 回限りのプロセスで実行するよりも効率的で正確です。ディスクの使用状況が線形読み取りを優先する場合、先読みは基本的に、すべてのディスク読み取りで有用なデータをこのキャッシュに事前入力します。

これは、非常に単純な設計を示唆しています。メモリ内にできる限り多くを維持し、スペースが不足したときにパニックでファイルシステムにすべてをフラッシュするのではなく、それを逆にします。すべてのデータは、必ずしもディスクにフラッシュすることなく、ファイル システム上の永続的なログにすぐに書き込まれます。実際には、これはカーネルのページキャッシュに転送されることを意味します。

これは非常に単純な設計を示唆しています。メモリに可能な限り多くを保持し、スペースが不足したときにすべてをファイルシステムにフラッシュしてパニックに陥らせる代わりに、それを元に戻します。すべてのデータは、ディスクにフラッシュすることなく、ファイルシステム上の永続的なジャーナルにすぐに書き込まれます。実際には、これはカーネルのページキャッシュに移動されることを意味します

ページキャッシュ中心の設計のこのスタイルは、こちらの Varnish の設計に関する記事で説明されています (健全な傲慢さとともに)。

このページ キャッシュ中心のデザイン スタイルは、こちらの Varnish デザインに関する記事で説明されています (やや誇張されています)。

一定時間で十分 一定時間で十分

メッセージング システムで使用される永続的なデータ構造は、多くの場合、メッセージに関するメタデータを維持するために、関連付けられた BTree またはその他の汎用ランダム アクセス データ構造を持つコンシューマごとのキューです。BTree は利用可能な最も用途の広いデータ構造であり、メッセージング システムでさまざまなトランザクションおよび非トランザクション セマンティクスをサポートすることを可能にします。ただし、かなり高いコストがかかります。Btree 操作は O(log N) です。通常、O(log N) は本質的に定数時間と同等と見なされますが、これはディスク操作には当てはまりません。ディスク シークは 1 ポップあたり 10 ミリ秒で行われ、各ディスクは一度に 1 つのシークしか実行できないため、並列処理は制限されます。したがって、ほんの一握りのディスク シークでさえ、非常に高いオーバーヘッドにつながります。ストレージ システムでは、非常に高速なキャッシュ操作と非常に低速な物理ディスク操作が混在しているため、

メッセージング システムで使用される永続的なデータ構造は、通常、コンシューマごとのキューであり、メッセージに関するメタデータを維持するために BTree またはその他の汎用ランダム アクセス データ構造が関連付けられています。BTree は、メッセージング システムでさまざまなトランザクションおよび非トランザクション セマンティクスをサポートできる、利用可能な最も一般的なデータ構造です。ただし、かなり高いコストがかかります。Btree 操作は O(log N) です。通常、O(log N) は本質的に定数時間と同等と見なされますが、これはディスク操作には当てはまりません。ディスクのシークは 10 ミリ秒で発生し、各ディスクは一度に 1 つのシークしか実行できないため、並列処理は制限されます。そのため、少数のディスク シークでも非常に高いオーバーヘッドが発生する可能性があります。ストレージ システムでは、非常に高速なキャッシュ操作と非常に低速な物理ディスク操作が混在しているため、ツリー構造では通常、固定キャッシュでデータが増加するにつれてパフォーマンスが超線形に観察されます。つまり、データが 2 倍になると、2 倍よりも遅くなります。

直観的には、ロギング ソリューションでよくあるように、単純な読み取りとファイルへの追加に基づいて永続的なキューを構築できます。この構造には、すべての操作が O(1) であり、読み取りが書き込みや相互をブロックしないという利点があります。パフォーマンスがデータ サイズから完全に切り離されているため、これには明らかなパフォーマンス上の利点があります。1 台のサーバーで、多数の安価で回転速度の遅い 1 TB 以上の SATA ドライブを最大限に活用できるようになりました。シーク パフォーマンスは劣りますが、これらのドライブは大量の読み取りと書き込みに対して許容できるパフォーマンスを備えており、価格は 1/3、容量は 3 倍です。

直観的には、ロギング ソリューションでよくあるように、単純な読み取りとファイルへの追加の上に永続キューを構築できます。この構造の利点は、すべての操作が O(1) であり、読み取りが書き込みや相互をブロックしないことです。パフォーマンスはデータ サイズから完全に切り離されているため、これには明らかなパフォーマンス上の利点があります。1 台のサーバーで、多くの安価で低回転の 1 TB SATA ドライブを最大限に活用できるようになりました。シーク パフォーマンスが低いにもかかわらず、これらのドライブは、1/3 の価格と 3 倍の容量で許容できる大容量の読み取りおよび書き込みパフォーマンスを備えています。

パフォーマンスを低下させることなく実質的に無制限のディスク領域にアクセスできるということは、メッセージング システムには通常見られないいくつかの機能を提供できることを意味します。たとえば、Kafka では、メッセージが消費されるとすぐにメッセージを削除しようとする代わりに、メッセージを比較的長期間 (たとえば 1 週間) 保持できます。これにより、後述するように、消費者にとって大きな柔軟性がもたらされます。

パフォーマンスを低下させることなく事実上無制限のディスク領域にアクセスできるということは、メッセージング システムでは一般的に見られない機能を提供できることを意味します。たとえば、Kafka では、メッセージが消費されるとすぐに削除しようとする代わりに、メッセージを比較的長期間 (たとえば 1 週間) 保持できます。後で説明するように、これにより消費者に多くの柔軟性がもたらされます。

公式アカウントのアルゴリズムのニッチに注目してください

おすすめ

転載: blog.csdn.net/SJshenjian/article/details/129938222