記事ディレクトリ
Redis の原則
序章:
- Redis は、高速な読み取りおよび書き込み速度を備えた純粋なメモリ操作です。
- 中核となるビジネスは、IO 多重化とイベント ディスパッチに基づくシングル スレッド モデルです。
- 情報は 2 つの永続的な方法でディスクに保存できます。
バージョンの変更により、バージョン 6.0 ではマルチスレッドが導入され始めましたが、中核的なビジネスは依然としてシングルスレッドです
中核事業がマルチスレッドを導入しない理由:
- Redis は純粋なメモリ操作ですが、実際、パフォーマンスに影響を与えるのはネットワーク遅延の問題、つまりIO 問題です。
- マルチスレッドの導入により、頻繁なコンテキストの切り替えにより、代わりにリソースが消費される可能性があります
- マルチスレッドの仕組みによりセキュリティ上の問題が生じる可能性があるため、ロックなどのセキュリティ対策の導入が必要
I/Oモデル
Redis で使用される IO モデルを説明する前に、まずすべての IO モデルを紹介します。
ステーション B に関する原則記事を推奨します ビデオ原則記事-27. Redis ネットワーク モデル - Redis シングルスレッドおよびマルチスレッド ネットワーク モデルの変更_哔哩哔哩_bilibili
以下の写真はすべてビデオのスクリーンショットです
I/O には、ユーザー状態とカーネル状態の 2 つの状態が含まれます。
デバイス上のパフォーマンス:ハードウェア デバイスのデータが準備できるまで待機 -> データがカーネル バッファに保存される -> データがカーネル バッファからユーザー バッファにコピーされる
次の 2 つの段階を経ます。
- データの準備ができるまで待ちます
- カーネルバッファからユーザーバッファにデータをコピーします
-
BIO ブロッキング IO: データの準備ができてデータのコピーが完了するまで、両方のステージがブロックされ、データを処理するためのブロックが停止されます。
-
NIO 非ブロッキング IO: 最初のステージは、データの準備ができているかどうかを継続的にポーリングします。ブロッキング IO と比較すると、最初のステージはブロックされません。2 番目のステージは依然としてブロッキング待機状態です。
- 最初の段階はノンブロッキングですが、パフォーマンスは向上しません。また、ポーリング メカニズムにより CPU がアイドル状態になり、CPU リソースが浪費されます。
ブロッキング IO とノンブロッキング IO の違いはデータがないときの処理方式にあり、シングルスレッドの場合、処理中のデータが準備できていないとスレッドはブロックされます。
IO 多重化と上記の 2 つのモデルの違いは、無効な待機を回避するためにデータの準備ができているかどうかを監視することです。
- IO 多重化モデル: 複数のファイル記述子 FD (すべてのファイルの一意の識別子) を監視し、FD データの準備ができたことを検出すると、第 2 段階に進みますが、第 2 段階はまだブロックされています。多重化は複数の FD として理解できます。 、多重化とはスレッドを多重化することを意味します
実際には IO 多重化の実装は 3 つあります。
-
1.1セレクト:
- ユーザー空間では長さ1024のビットマップデータ構造を使用し、監視対象のFDに対応するビットを1に設定し、ビットマップをカーネル空間にコピーし、カーネル空間でデータの準備ができているかどうかを監視します。
- データの準備ができている場合、すべての FD を走査してどの FD データが準備できているかを確認します。データの準備ができていない FD のビット位置は 0 で、準備ができている FD の数を返します。また、別の操作があります。ビットマップはカーネル空間からユーザー空間にコピーされる; それ以外の場合は、結果 0 が返される
- ユーザー空間は、返された結果の数に応じてビットマップを走査し、FD を取得し、データを読み取ります。
- 概要: O(N) の未分化なポーリングの複雑さ。IO イベントが発生したことはわかりますが、どの FD であるかはわかりません。また、ビットマップの合計は 1024 ビットであるため、モニターの数は制限されており、1024 を超えることはできません。カーネル空間からユーザー空間へ
-
1.2投票:
- これは選択プロセスとほぼ同じですが、ビットマップの長さをカスタマイズできるため、接続数の問題が解決されます。
- データ コピーはまだ 2 つあり、データの準備ができていることだけがわかりますが、それがどれであるかはわかりません。ユーザー スペースで再度トラバースする必要があります。さらに多くのモニターとリターンがある場合、次のような問題が発生する可能性があります。パフォーマンスの低下
-
1.3エポール:
-
epoll は赤黒ツリーとリンク リストに基づいており、ユーザー空間をトラバースする必要がなく、時間計算量は O(1)
-
3つの機能を提供
-
epoll_create: 監視対象の FD を記録する赤黒ツリーと記録準備完了 FD のリンク リストを含む構造体を作成します。
-
epoll_ctl : 赤黒ツリーに FD を追加し、コールバック関数 callback を関連付けます。データの準備ができたら、対応する FD が準備完了リストに追加されます。
-
epoll_wait : 準備完了リンク リストが空かどうかを確認し、空でない場合は準備完了 FD の数を返し、準備完了リンク リストをユーザー空間にコピーします。つまり、返された FD セットは準備完了セットであり、必要ありません横断して検出するユーザー空間
2 つのトリガー モード:
LT:
epoll_wait() が記述子イベントの到着を検出すると、このイベントがプロセスに通知されます。プロセスはイベントをすぐに処理しない場合があります。次回 epoll_wait() が呼び出されたときに、プロセスに通知されますこれもデフォルトのモードです。
ET:
LT モードとは異なり、プロセスは通知の直後にイベントを処理する必要があります。
次回 epoll_wait() を呼び出すとき、イベントの到着は通知されません。epoll イベントが繰り返しトリガーされる回数が大幅に削減される
ため、効率は LT モードよりも高く、ファイル ハンドルの読み取り/書き込み操作のブロックによって複数のファイル記述子を処理するタスクが枯渇することが回避されます。
-
-
概要: コピー数を減らします。つまり、監視対象の FD はカーネル内の赤黒ツリーにあるため (監視対象の新しい FD がある場合)、epoll_wait のたびに FD セットをコピーする必要はありません。 、 epoll_ctl を呼び出して赤黒ツリーに追加します) ; 準備完了 FD コレクションをユーザー空間にコピーするだけで、準備完了状態を判断するためにすべての FD を走査するユーザー空間は必要ありません; に保存された FD に基づいて、赤黒ツリー、理論上上限なし、CRUD効率が高く、FD数に性能が影響されない
最適化: データの準備が整ったかどうかをカーネルに渡して判断し、NIO でのカーネル <-> ユーザーの切り替えを削減します。
-
-
信号駆動モデル
- カーネルと関連付けてシグナルを確立し、コールバックを設定します。カーネルが FD の準備ができたら、コールバックしてユーザーに通知します。この期間中、ユーザーはブロックしたり待機したりすることなく他のサービスを実行できます
- 初め
- 多数の IO 操作中は多数の信号が発生し、時間内に信号を処理できないと信号キューがオーバーフローする可能性があります。
-
AIO 非同期 IO
- システム コールがすぐに応答して結果を返すことは、現在のプロセスがイベント処理の結果を待つ必要がなく、他のトランザクションの実行を継続できることを示します。
- どちらのフェーズもブロックされません
同期と非同期の区別: カーネル空間からユーザー空間へのコピープロセスがブロックされるかどうか
JAVAネットワークソケットソケットを使用したIOモデルについて話します
-
バイオ
- 単一スレッドの場合、最初に accpet はクライアントの接続を待機してブロックされ、次にクライアントが接続した後、読み取りはブロックされ、クライアントが情報を送信するまで待機する必要があります。接続されたクライアントが情報を送信していない場合は、常に接続を占有し、他のクライアントは接続できません。
- マルチスレッドの場合、同じ accpet はクライアントの接続を待ってブロックされます。クライアントが接続すると、スレッドはクライアントから送信された情報を読み取ります。接続数が多い場合、多数のスレッドがクライアントは情報を送信しないため、リソースが浪費される可能性があります。
-
NIO
- accpet はブロックせず、ポーリングしてクライアントが接続するのを待ち、接続されたクライアントをリストリストに追加し、ポーリングごとにリストリストを 1 回走査して、情報を送信しているクライアントがあるかどうかを確認します。
- 1w 接続のうちの 1 つだけが情報を送信する場合、9999 回は無意味であり、走査に多くの無駄な時間が消費されます。
-
I/O多重化
- accpet はブロックせず、システムコールに渡され、情報を送信するクライアントがある場合に戻ります。
- select を例にとると、各ポーリングはクライアント接続リストのコピーをカーネルにコピーします。カーネルは、情報を送信しているクライアントがあるかどうかを判断し、存在する場合は返します。
Redisネットワークモデル
-
2 つの ID: クライアントとサーバー
-
2 つのソケット: ServerSocket、ClientSocket
-
3 つのプロセッサ:
- 接続応答: 新しいクライアントがサーバーに接続します
- コマンドリクエスト(読み取り)
- コマンド応答(書き込み):コマンド実行結果
上の写真もビデオのスクリーンショットからのものです
サーバーに Redis サービスを作成したら、サービスを開始します
-
epoll_create と同様のイベント構造体を作成します。
-
サーバーに接続し、ServerSocket を作成し、対応する FD を取得してイベント インスタンスに追加し、epoll_ctl と同様に接続応答プロセッサをバインドします。
- クライアントがサーバーに接続すると、ServerSocket によってバインドされる接続応答プロセッサの処理フロー: 接続されたクライアントの FD を取得してイベント インスタンスに追加し、epoll_ctl と同様にコマンド要求プロセッサをバインドします。
- 準備ができた ClientSocket があるかどうかを監視します。準備ができた ClientSocket がある場合、コマンド リクエスト プロセッサはそれにバインドされます。リクエスト データをバッファに書き込み、バッファ内のデータを解析して redis コマンドにし、コマンドを選択して実行します。結果をバッファ領域に入れ、同時にソケットが属するバッファを出力バッファキューに入れます。
-
FD をリッスンする前に、beforesleep の機能は、出力結果キュー内の Clientsocket を走査し、FD 書き込みイベントをリッスンし、コマンド応答プロセッサをバインドすることです。監視の開始後に ClientSocket の準備ができていない場合、time_out が設定されている場合、スリープ状態になるので epoll_wait の前に
-
epoll_wait と同様のイベントをリッスンします
概要: Redis のコア ビジネスは IO 多重化 + イベント ディスパッチであり、ServerSocket 接続イベント、ClientSocket 読み取りイベント、および ClientSocket イベントを監視し、さまざまなイベントに応じてさまざまなイベント ハンドラーをバインドし、さまざまな処理手順に対応します。
上記はシングルスレッドの場合ですが、主にマルチスレッド IO の問題を導入するために、redis はマルチスレッド バージョンを追加しました。