Chanler

Chanler

「黒馬 Redis 原理」二、ネットワークモデル

ユーザ空間、カーネル空間#

image.png|500

IO モデル#

『UNIX ネットワークプログラミング』は五つの IO モデルをまとめています

  • ブロッキング IO / Blocking IO
  • ノンブロッキング IO / Nonblocking IO
  • IO 多重化 / IO Multiplexing
  • シグナル駆動 IO / Signal Driven IO
  • 非同期 IO / AsyncAsynchronous IO

ユーザ空間のユーザバッファがカーネル空間のカーネルバッファ データが準備できるのを待っています
ハードウェアのハードウェアデバイスがカーネル空間のカーネルバッファ データを準備しています
ユーザ空間のユーザバッファがカーネル空間のカーネルバッファ データを読み取ります

ブロッキング IO / Blocking IO#

image.png|500

ノンブロッキング IO / Nonblocking IO#

image.png|500

IO 多重化 / IO Multiplexing#

ブロッキング IO でもノンブロッキング IO でも、ユーザはある段階で recvfrom を使ってデータを取得する必要がありますが、データが準備できるのを待つ必要があります。要するに、ブロッキング待機かノンブロッキング待機かの違いで、結局はこの一つだけを処理することになります。

しかし、複数のデータソースを同時に監視する場合、どのデータソースが準備できたらそのデータソースを処理するのか、これが IO 多重化です。

image.png|500

Linux ではファイルディスクリプタ file descriptor がすべてに関連付けられます。ここではネットワークソケットであり、複数の fd を同時に待機し、どれが準備できたらそれを処理します。

image.png|500

IO 多重化には select、poll、epoll などのさまざまな方法があります。select と poll は fd セット内に fd が準備できていることはわかりますが、具体的にどれかはわかりません。

image.png|500

IO 多重化 - select#

fd をバイナリビットに変換して保存します。例えば、fd=1 2 5 を監視する場合、最右の 1 2 5 ビットを 1 にマークし、カーネル空間に渡します。

対応するビットの fd が準備できている場合は 1 に再マークし、その他は 0 にします。ユーザ空間に渡されるビットマップを走査し、1 のビットは準備できていることを示します。

利点は非常にスペースを節約できることです。欠点は 1024 を超えることができず、fd_set のコピーが必要で、チェック時には全体を走査する必要があります。

image.png|500

IO 多重化 - poll#

poll は select の 1024 の制限を引き上げ、リンクリストで理論上は無制限に保存できますが、必要はありません。長くなるほど走査時にパフォーマンスが低下します。

image.png|500

IO 多重化 - epoll#

epoll は赤黒木を使用し、カーネル空間内で赤黒木を維持し、すべての監視が必要な fd を記録します。同時に準備完了リストを維持し、すべての準備完了の fd を保存します。

プロセス:ユーザ空間は epoll_create を使用して epoll インスタンスを作成し、epoll_ctl を使用して赤黒木に fd を追加または削除し、epoll_wait を使用して準備完了イベントを待ち、準備完了リストから準備完了の fd を取得します。

ある fd が準備できると、カーネルはそれを準備完了リストに追加します。epoll_wait は準備完了リストから準備完了の fd を取得するだけで、全体の fd セットを走査する必要はありません。

利点:fd の上限がなく、全体の fd セットをコピーする必要がなく、単一の fd と操作を渡し、準備完了の fd のみを返し、ep_poll_callback メカニズムを利用して fd の状態を監視し、すべての fd を走査する必要がありません。

image.png|500

IO 多重化 - イベント通知メカニズム#

監視している fd でイベント(データが読み取り可能、書き込み可能など)が発生すると、カーネルはコールバックメカニズムを通じて、epoll の ep_poll_callback を使用して epoll インスタンスに通知します。

カーネルは準備完了の fd を epoll インスタンスの準備完了リストに追加します。アプリケーションが epoll_wait を呼び出すと、すぐに準備完了リストから発生したイベントの fd を取得して処理できます。すべての監視している fd を走査する必要はありません。

実際には ET モードを使用し、新しいデータのみが通知され、通知されたデータについては、非ブロッキング読み取りをループして完了するまで行います。

image.png|500

IO 多重化 - web サービスプロセス#

image.png|500

シグナル駆動 IO#

シグナル駆動 IO は非ブロッキング IO モデルの一種です。

アプリケーションはシグナルハンドラを設定でき、カーネルが fd が準備できたときにこのシグナルをプロセスに送信します。プロセスがシグナルを受信すると、すぐに recvfrom を実行してデータを読み取ります。

利点:非ブロッキングで、積極的にポーリングする必要がありません。

欠点:データを読み取る際に依然としてブロッキングが正常であり、シグナル処理にはオーバーヘッドがあり、シグナルが失われる可能性があり、高い同時接続の中では IO 多重化ほど効果的ではありません。

image.png|500

非同期 IO#

非同期 IO はユーザが IO 操作を開始した後、すぐに戻り、ブロッキング段階はありません。

カーネルはデータが準備できるのを待つだけでなく、データをカーネル空間からユーザ空間にコピーする責任も負います。IO 操作が完了した後、カーネルはユーザが登録したコールバック関数またはシグナルを使用してユーザプロセスに通知します。

利点:ユーザプロセスが IO リクエストを発起してから完了通知を受け取るまで、完全に非ブロッキングです。

欠点:複雑です。

image.png|500

同期と非同期#

非同期 IO は二段階、つまりデータを読み取る段階でも非同期です。

image.png|500

Redis は単スレッドですか?#

Redis は単スレッドですか、それともマルチスレッドですか?

  • Redis のコアビジネス部分であるコマンド処理は単スレッドです。
  • 全体の Redis はマルチスレッドです。

Redis のバージョン選定プロセスでは、二つの重要なタイムポイントでマルチスレッドのサポートが導入されました:

  • Redis V4.0:古い時間のかかるタスク(例えば、非同期削除コマンド unlink)を非同期で処理するためにマルチスレッドを導入しました。
  • Redis v6.0:コアネットワークモデルにマルチスレッドを導入し、マルチコア CPU の利用率をさらに向上させました。

Redis のコアネットワークモデルは、Redis v6.0 以前は単スレッドで、epoll のような IO 多重化技術を利用してイベントループ内でクライアントの状況を継続的に処理していました。

Redis が単スレッドを選択した理由は?

  • Redis はコマンド処理において純粋なメモリ操作であり、実行速度が非常に速いため、パフォーマンスのボトルネックはネットワーク IO にあり、実行速度よりもネットワーク IO の最適化に集中する方が重要です。
  • マルチスレッドは過剰なコンテキストスイッチを引き起こし、逆に不必要なオーバーヘッドをもたらします。
  • マルチスレッドを導入すると、スレッドセーフの問題が発生し、スレッドロックなどの安全手段を導入する必要があり、逆にパフォーマンスを浪費します。

Redis が実装したネットワークモデル#

image.png|500

image.png|500

|500

image.png|500

image.png|500

この記事は Mix Space によって xLog に同期更新されました。元のリンクは https://blog.0xling.cyou/posts/redis/redis-4

読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。