[Redis] Redisシングルスレッドが高い同時実行性をサポートできるのはなぜですか?Redis6.0の後にマルチスレッドが導入されたのはなぜですか?

1.Redisシングルスレッドが高い同時実行性をサポートできるのはなぜですか?

redisとmemcachedの違いは何ですか?redisのスレッドモデルとは何ですか?Redisシングルスレッドが高い同時実行性をサポートできるのはなぜですか?

  これは、redisを尋ねるときの最も基本的な質問です。redisの最も基本的な内部原則と特性の1つは、redisは実際にはシングルスレッドの作業モデルであるということです。これがわからない場合は、後でredisをプレイすると出てきます何も知らないという問題ではありませんか?

  インタビュアーがredisとmemcachedの違いについて質問する可能性もありますが、memcachedは、初期には主要なインターネット企業で使用されていた一般的なキャッシュソリューションでしたが、現在は基本的に近年redisであり、memcachedを使用している企業はありません。もう。

redisとmemcachedの違いは何ですか?

  • 保存方法:memcachedはすべてのデータをメモリに保存し、停電後にハングアップします。データはメモリサイズを超えることはできません。redisの一部はハードディスクに保存されるため、データの耐久性を確保できます。
  • データサポートタイプ:memcachedは比較的単純なデータタイプをサポートします。Redisには複雑なデータ型があります。
  • 低レベルモデル:それらの間の最下位レベルの実装と、クライアントと通信するためのアプリケーションプロトコルは異なります。一般的なシステムはシステム関数を呼び出すため、Redisはそれ自体でVMメカニズムを直接構築しました。これは、移動と要求に一定の時間を浪費します。

memcachedと比較して、redisはより多くのデータ構造を持ち、より豊富なデータ操作をサポートできます。より複雑な構造と操作をサポートするためにキャッシュする必要がある場合は、redisが適しています。


  Redisはクラスターモードをネイティブにサポートします。redis3.xバージョンでは、クラスターモードをサポートできますが、memcachedにはネイティブクラスターモードがありません。クラスターへのフラグメント化された書き込みデータを実装するには、クライアントに依存する必要があります。

パフォーマンスの比較
  redisは単一のコアのみを使用し、memcachedは複数のコアを使用できるため、各コアに平均して小さなデータを格納する場合、redisのパフォーマンスはmemcachedよりも高くなります。100kを超えるデータでは、memcachedのパフォーマンスはredisのパフォーマンスよりも高く、redisは最近ビッグデータの保存のパフォーマンスを最適化しましたが、それでもmemcachedよりもわずかに劣っています。

Redisスレッドモデル

  Redisは内部でファイルイベントハンドラーを使用します。このファイルイベントハンドラーはシングルスレッドであるため、redisはシングルスレッドモデルと呼ばれます。つまり、redisのシングルスレッドは、redisインスタンス全体が1つのスレッドはなく、redisコマンドを実行するコアモジュールがシングルスレッドであることを意味し、他のRedisモジュールには独自のモジュールのスレッドがあります。Redis4.0にはマルチスレッドの概念。たとえば、redisは、マルチスレッドを介してバックグラウンドでオブジェクトを削除し、redisモジュールを介して実装されたコマンドをブロックします。Redisは、IO多重化メカニズムを使用して複数のソケットを同時に監視し、対応するイベントハンドラーを選択して、ソケット上のイベントに従って処理します。

ファイルイベントハンドラーの構造は、複数のソケット、IO多重化プログラム、ファイルイベントディスパッチャー、イベントハンドラー(接続応答ハンドラー、コマンド要求ハンドラー、コマンド応答ハンドラー)の4つの部分で構成されます。
  複数のソケットが可能です。異なる操作が同時に生成されます。各操作は異なるファイルイベントに対応しますが、IO多重化プログラムは複数のソケットを監視し、ソケットによって生成されたイベントをキューに入れ、イベントディスパッチャはイベントが発生するたびにそれをキューから取り出します。処理のために対応するイベントハンドラーに渡されます。

クライアントとredis間の通信プロセスを見てみましょう。
ここに画像の説明を挿入
  クライアントsocket01はredisのサーバーソケットに接続の確立を要求します。このとき、サーバーソケットはAE_READABLEイベントを生成します。IOマルチプレクサがサーバーによって生成されたイベントを監視した後ソケット、イベントはキューにプッシュされます。ファイルイベントディスパッチャは、キューからイベントを取得し、それを接続応答プロセッサに渡します。接続応答プロセッサは、クライアントと通信できるsocket01を作成し、socket01のAE_READABLEイベントをコマンド要求プロセッサに関連付けます。

  この時点でクライアントがキー値の設定要求を送信すると仮定すると、redisのsocket01はAE_READABLEイベントを生成し、IOマルチプレクサはイベントをキューにプッシュします。このとき、イベントディスパッチャはキューからイベントを取得します。前のsocket01のAE_READABLEイベントは、コマンド要求プロセッサーに関連付けられているため、イベント・ディスパッチャーは、処理のためにイベントをコマンド要求プロセッサーに渡します。このコマンドは、socket01のキー値を読み取り、独自のメモリでキー値の設定を完了するようにプロセッサに要求します。操作が完了すると、socket01のAE_WRITABLEイベントがコマンド応答プロセッサに関連付けられます。

  クライアントがこの時点で返された結果を受信する準備ができている場合、redisのsocket01はAE_WRITABLEイベントを生成します。これもキューにプッシュされ、イベントディスパッチャは関連するコマンド応答プロセッサを見つけ、コマンド応答プロセッサはこれを入力します。 to socket01 okなどのこの操作の結果、socket01のAE_WRITABLEイベントとコマンド応答プロセッサの関連付けを解除します。

これで通信は完了です。

redisシングルスレッドモデルが非常に効率的であるのはなぜですか?要約すると、次の点があります。

  • 純粋なメモリ操作
  • コアはノンブロッキングIO多重化メカニズムに基づいています
  • シングルスレッドは、複数のスレッドの頻繁なコンテキスト切り替えの問題を回避します

2. Redis 6.0の後にマルチスレッドが導入されたのはなぜですか?

1.従来のブロッキングIOモデル

  リアクターモデルを見る前に、従来のブロッキングIOモデルについて言及する必要があります。
  従来のブロッキングIOモデルでは、独立したAcceptorスレッドがクライアントの接続を監視し、クライアントがそれを要求するたびに、クライアントが処理するための新しいスレッドを割り当てます。複数のリクエストが同時に着信すると、サーバーは対応する数のスレッドを割り当てます。これにより、CPUが頻繁に切り替わり、リソースが浪費されます。
  一部の接続要求が来て何もしませんが、サーバーは対応するスレッドも割り当てます。これにより、不要なスレッドオーバーヘッドが発生します。これは、レストランに行って食事をし、メニューを長時間保持し、それが本当に高価であることに気づき、そして去るようなものです。この間、注文を待っているウェイターは対応するスレッドと同等であり、注文は接続要求と見なすことができます。
ここに画像の説明を挿入
  同時に、接続が確立されるたびに、スレッドが読み取りと書き込みのメソッドを呼び出すと、読み取りと書き込みのデータができるまでスレッドはブロックされます。その間、スレッドは他のことを実行できません。これは上のレストランでの食事の例です。周りを回ると、これが最も費用効果の高いレストランであることがわかります。このレストランに戻ったとき、私はメニューをとって長い間見ていました、そしてウェイターもあなたが注文を終えるのを待っていました。このプロセスの間、ウェイターは何もできませんが、待機して待機することしかできません。このプロセスは、ブロッキングと同等です。
ここに画像の説明を挿入
  このように、スレッドはリクエストごとに割り当てられる必要があり、スレッドは処理されるまでブロックされる必要があります。一部のリクエストは、接続するだけで何もせず、スレッドを割り当てる必要があります。これには、高いサーバーリソースが必要です。高い同時実行性のシナリオに遭遇した、私は想像できません。接続数が比較的少ない固定アーキテクチャを検討できます。

2.疑似非同期IOモデル

  スレッドプールとタスクキューを使用して、スレッドプールを通じて最適化されたソリューション。これは、疑似非同期IOモデルと呼ばれます。
クライアントがアクセスするときは、クライアントの要求をタスクにカプセル化し、処理のためにバックエンドスレッドプールに配信します。スレッドプールは、メッセージキューと、メッセージキュー内のタスクを処理するための複数のアクティブなスレッドを維持します。
ここに画像の説明を挿入
  このソリューションは、リクエストごとにスレッドを作成することによって引き起こされるスレッドリソースの枯渇の問題を回避します。ただし、最下層は依然として同期ブロッキングモデルです。スレッドプール内のすべてのスレッドがブロックされている場合、それ以上の要求に応答することはできません。したがって、このモードでは接続の最大数が制限され、根本的に問題を解決することはできません。
  上記のレストランを例にとると、レストランのオーナーが一定期間営業した後、顧客が増え、店内の元の5人のウェイターは1対1のサービスでは対応できません。したがって、上司は5人のスレッドプールアプローチを使用します。ウェイターは、別のゲストにサービスを提供した直後に1人のゲストにサービスを提供します。
  このとき、問題が発生します。注文が非常に遅いお客様もいらっしゃるので、ウェイターは注文が完了するまで長時間待たなければなりません。5人の顧客すべての注文が非常に遅い場合、5人のウェイターは永遠に待たなければならず、残りの顧客はサービスを受けられなくなります。これは、上記のようにスレッドプール内のすべてのスレッドがブロックされている状況です。
では、この問題をどのように解決できるでしょうか。心配しないでください。Reactorモードが表示されようとしています。

3.リアクターのデザインパターン

  リアクターモードの基本的な設計アイデアは、I / O再利用モデルに基づいています。
  ここでI / O再利用モデルについて話しましょう。従来のIOマルチスレッドブロッキングとは異なり、I / O多重化モデルの複数の接続はブロッキングオブジェクトを共有し、アプリケーションは1つのブロッキングオブジェクトを待機するだけで済みます。接続に処理可能な新しいデータがある場合、オペレーティングシステムはアプリケーションに通知し、スレッドはブロックされた状態から戻り、ビジネス処理を開始します。
  どういう意味ですか?店主もお客さんの注文が遅いという問題を発見したので、大胆なアプローチを採用し、ウェイターを1人だけ残しました。ゲストが食事を注文すると、ウェイターは他のゲストを楽しませ、ゲストが食事を注文した後、ウェイターに直接電話してサービスを提供します。ここでの顧客とウェイターは、それぞれ複数の接続と1つのスレッドと見なすことができます。ウェイターは顧客をブロックし、別の顧客が食事を注文すると、彼女はすぐに他の顧客にサービスを提供しに行きました。
  リアクターの設計アイデアを理解した後、シングルリアクターのシングルスレッド実装を見てみましょう:
ここに画像の説明を挿入
  リアクターは、I / O多重化プログラムを介してクライアント要求イベントを監視し、イベントを受信した後、タスクディスパッチャーを介してそれらを配布します。

  • 接続確立要求イベントの場合、アクセプターによって処理され、対応するハンドラーが確立されて、後続のビジネス処理を担当します。
  • 非接続イベントの場合、Reactorは対応するハンドラーを呼び出して、読み取り->ビジネス処理->書き込み処理プロセスを完了し、結果をクライアントに返します。

プロセス全体が1つのスレッドで完了します。
ここに画像の説明を挿入
シングルスレッドの時代で
  は RedisはReactorシングルスレッドモデルに基づいて実装されています。
  IO多重化プログラムは、ユーザーの要求を受信すると、そのすべてをキューにプッシュして、ファイルディスパッチャーに配信します。後続の操作では、reactorのシングルスレッド実装に見られるように、プロセス全体が1つのスレッドで完了するため、Redisはシングルスレッド操作と呼ばれます。
ここに画像の説明を挿入
シングルスレッドのRedisの場合、これはメモリに基づいており、コマンド操作時間の複雑さが低いため、読み取りと書き込みの速度が非常に速くなります。
マルチスレッド
  は、マルチスレッド時代のRedis6バージョンで導入されました。前述のように、Redisのシングルスレッド処理は非常に高速ですが、なぜマルチスレッドを導入するのですか?シングルスレッドのボトルネックはどこにありますか?
  最初に2番目の質問を見てみましょう。Redisでは、シングルスレッドのパフォーマンスのボトルネックは主にネットワークIO操作にあります。つまり、CPU時間のほとんどは、読み取り/書き込みネットワークの読み取り/書き込みシステムコールの実行中に消費されます。いくつかの大きなキーと値のペアを削除する場合、それらを短時間で削除することはできないため、単一のスレッドの場合、後続の操作がブロックされます。
  上記のReactorモードでのシングルスレッド処理メソッドを思い出してください。非接続イベントの場合、Reactorは対応するハンドラーを呼び出して、読み取り->ビジネス処理->書き込み処理フローを完了します。これは、このステップがパフォーマンスのボトルネックを引き起こすことを意味します。
Redisは、マルチスレッド処理を通じてネットワークデータの読み取りと書き込みおよびプロトコル分析を処理するように設計されています。コマンドの実行には、引き続きシングルスレッド操作が使用されます。

総括する

リアクターモード

  • 従来のブロッキングIOモデルは、クライアントスレッドとサーバースレッドの間に1:1を割り当てますが、これは拡張に役立ちません。
  • 疑似非同期IOモデルはスレッドプール方式を使用しますが、最下層は依然として同期ブロッキング方式を使用しており、接続の最大数が制限されています。
  • Reactorは、I / O多重化プログラムを介してクライアント要求イベントを監視し、タスクディスパッチャーを介してそれらを配布します。
    シングルスレッド時代
  • Reactorシングルスレッドモードに基づいて、IO多重化プログラムを介してユーザーの要求を受信した後、すべての要求はキューにプッシュされ、処理のためにファイルディスパッチャーに渡されます。

マルチスレッド時代

  • シングルスレッドのパフォーマンスのボトルネックは、主にネットワークIOにあります。
  • ネットワークデータの読み取りと書き込み、およびプロトコル分析はマルチスレッド方式で処理されます。コマンドの実行には、引き続きシングルスレッド操作が使用されます。

記事の出典:
[1] Redisがシングルスレッドであるのに、高い同時実行性をサポートできるのはなぜですか?
[2]、Redis6.0マルチスレッド

おすすめ

転載: blog.csdn.net/dl962454/article/details/115218011