ゴールド、シルバー、シルバーの候補者にとって必須の質問: Redis は本当にシングルスレッドですか?



写真

インタビューの質問「Redis はシングルスレッドですか?」をきっかけに考えたこと
著者: Li Le
出典: IT 読書ランキング

多くの人が面接で次のような質問に遭遇したことがあります: Redis はシングルスレッドですか、それともマルチスレッドですか? この質問は単純であると同時に複雑でもあります。ほとんどの人が Redis がシングルスレッドであることを知っているため、単純であると言われます。また、その答えは実際には不正確であるため、複雑であると言われます。

Redisってシングルスレッドじゃないんですか?Redis インスタンスを起動して確認します。Redis のインストールおよびデプロイ方法は次のとおりです。

// 下载
wget https://download.redis.io/redis-stable.tar.gz
tar -xzvf redis-stable.tar.gz
// 编译安装
cd redis-stable
make
// 验证是否安装成功
./src/redis-server -v
Redis server v=7.2.4

次に、以下に示すように、Redis インスタンスを起動し、コマンド ps を使用してすべてのスレッドを表示します。

// 启动Redis实例
./src/redis-server ./redis.conf

// 查看实例进程ID
ps aux | grep redis
root     385806  0.0  0.0 245472 11200 pts/2    Sl+  17:32   0:00 ./src/redis-server 127.0.0.1:6379

// 查看所有线程
ps -L -p 385806
   PID    LWP TTY          TIME CMD
385806 385806 pts/2    00:00:00 redis-server
385806 385809 pts/2    00:00:00 bio_close_file
385806 385810 pts/2    00:00:00 bio_aof
385806 385811 pts/2    00:00:00 bio_lazy_free
385806 385812 pts/2    00:00:00 jemalloc_bg_thd
385806 385813 pts/2    00:00:00 jemalloc_bg_thd

実はスレッドが6つあるんです!Redis はシングルスレッドだと言われていませんか? なぜスレッドがこんなにたくさんあるのでしょうか?

これら 6 つのスレッドの意味は理解できないかもしれませんが、この例は少なくとも Redis がシングルスレッドではないことを示しています。

01 Redis でのマルチスレッド

次に、上記 6 つのスレッドの機能を 1 つずつ紹介します。

1)redisサーバー:

メインスレッドは、クライアント要求を受信して​​処理するために使用されます。

2)jemalloc_bg_thd

jemalloc は新世代のメモリ アロケータで、Redis の最下層でメモリを管理するために使用されます。

3)バイオ_xxx:

bio プレフィックスで始まるスレッドはすべて非同期スレッドで、時間のかかるタスクを非同期で実行するために使用されます。このうち、スレッド bio_close_file はファイルの非同期削除に使用され、スレッド bio_aof は AOF ファイルをディスクに非同期にフラッシュするために使用され、スレッド bio_lazy_free はデータの非同期削除 (遅延削除) に使用されます。

メインスレッドはキューを通じてタスクを非同期スレッドに分散し、この操作にはロックが必要であることに注意してください。メインスレッドと非同期スレッドの関係は次の図のようになります。

写真

メインスレッドと非同期スレッド メインスレッドと非同期スレッドメインスレッドと非同期スレッド
ここでは、遅延削除を例にして、非同期スレッドを使用する必要がある理由を説明します。Redis は、文字列、リスト、ハッシュ テーブル、セットなどを含む複数のデータ型をサポートするインメモリ データベースです。考えてみてください。リスト タイプのデータを削除 (DEL) するプロセスはどのようなものでしょうか? 最初のステップでは、データベース ディクショナリからキーと値のペアを削除し、2 番目のステップでは、リスト内のすべての要素を走査して削除します (メモリを解放します)。リスト内の要素の数が非常に多い場合はどうなるかを考えてみましょう。このステップは非常に時間がかかります。この削除方法は同期削除と呼ばれ、そのプロセスは次の図に示すとおりです。

写真

同期削除フローチャート 同期削除フローチャート同期削除のフローチャート
上記の問題に対して、Redis は、メインスレッドが削除コマンド (UNLINK) を受け取ると、まずデータベース辞書からキーと値のペアを削除し、削除を分散する遅延削除 (非同期削除) を提案しました。 bio_lazy_free、時間のかかるロジックの 2 番目のステップは、非同期スレッドによって実行されます。このときの処理を以下に示します。

写真

遅延削除のフローチャート 遅延削除のフローチャート遅延削除のフローチャート

02 I/Oマルチスレッド

Redis はマルチスレッドですか? では、なぜ Redis はシングルスレッドであると常に言うのでしょうか? これは、クライアント コマンド リクエストの読み取り、コマンドの実行、およびクライアントへの結果の返しがすべてメイン スレッドで完了するためです。それ以外の場合、複数のスレッドが同時にメモリ内データベースを操作する場合、同時実行の問題をどのように解決すればよいでしょうか? 各操作の前にロックがロックされている場合、単一スレッドとの違いは何でしょうか?

もちろん、このプロセスは Redis 6.0 バージョンでも変更されました。Redis 関係者は、Redis はメモリベースのキーと値のデータベースであると指摘しました。コマンドの実行プロセスは非常に高速です。クライアントのコマンド要求を読み取り、結果をクライアントに返します。通常、クライアント (つまり、ネットワーク I/O) が Redis のパフォーマンスのボトルネックになります。

したがって、Redis 6.0 バージョンでは、作成者はマルチスレッド I/O の機能を追加しました。つまり、複数の I/O スレッドを開くことができ、クライアントのコマンド要求を並行して読み取ることができ、結果をクライアントに返すことができます。並行して。I/O マルチスレッド機能により、Redis のパフォーマンスが少なくとも 2 倍になります。

マルチスレッド I/O 機能を有効にするには、まず構成ファイル redis.conf を変更する必要があります。

io-threads-do-reads yes
io-threads 4

これら 2 つの構成の意味は次のとおりです。

  • io-threads-do-reads: マルチスレッド I/O 機能を有効にするかどうか。デフォルトは「no」です。

  • io-threads: I/O スレッドの数、デフォルトは 1、つまりメイン スレッドのみがネットワーク I/O の実行に使用され、スレッドの最大数は 128 です。この構成は次に従って設定する必要があります。 CPU コアの数。著者は、4 コア CPU の場合は 2 ~ 3 の I/O スレッドを設定し、8 コア CPU の場合は 6 I/O スレッドを設定することを推奨します。

マルチスレッド I/O 機能を有効にした後、Redis インスタンスを再起動し、すべてのスレッドを表示します。結果は次のようになります。

ps -L -p 104648
   PID    LWP TTY          TIME CMD
104648 104648 pts/1    00:00:00 redis-server
104648 104654 pts/1    00:00:00 io_thd_1
104648 104655 pts/1    00:00:00 io_thd_2
104648 104656 pts/1    00:00:00 io_thd_3
……

io-threads を 4 に設定したため、I/O 操作を実行するために 4 つのスレッドが作成されます (メイン スレッドを含む)。上記の結果は期待どおりです。

もちろん、マルチスレッドを使用するのは I/O フェーズのみであり、コマンド リクエストの処理は引き続きシングル スレッドですが、結局のところ、メモリ データのマルチスレッド操作には同時実行性の問題が存在します。

最後に、I/O マルチスレッドが有効になった後のコマンド実行フローは次のようになります。

写真

I/O マルチスレッド フローチャート I/O マルチスレッド フローチャートI / Oマルチスレッドのフローチャート

03 Redisのマルチプロセス

Redis には複数のプロセスがありますか? はい。一部のシナリオでは、Redis はいくつかのタスクを実行するために複数のサブプロセスも作成します。永続性を例に挙げると、Redis は 2 種類の永続性をサポートしています。

  • AOF (Append Only File): コマンドのログ ファイルとみなすことができ、Redis は各書き込みコマンドを AOF ファイルに追加します。

  • RDB (Redis データベース): データをスナップショットの形式で Redis メモリに保存します。SAVE コマンドは、RDB 永続化を手動でトリガーするために使用されます。Redis 内のデータ量が非常に大きく、永続化操作に長い時間がかかり、Redis はコマンド リクエストを単一のスレッドで処理するため、SAVE コマンドの実行時間が長すぎると、必然的に影響を受ける場合について考えてみましょう。他のコマンドの実行。

SAVE コマンドは他のリクエストをブロックする可能性があるため、Redis では永続化操作を実行するサブプロセスを作成するコマンド BGSAVE を導入し、メイン プロセスが他のリクエストを実行する影響を与えないようにしています。

BGSAVE コマンドを手動で実行して確認できます。まず、GDB を使用して Redis プロセスを追跡し、ブレークポイントを追加して、永続化ロジックで子プロセスをブロックさせます。次のように:

// 查询Redis进程ID
ps aux | grep redis
root     448144  0.1  0.0 270060 11520 pts/1    tl+  17:00   0:00 ./src/redis-server 127.0.0.1:6379

// GDB跟踪进程
gdb -p 448144

// 跟踪创建的子进程(默认GDB只跟踪主进程,需手动设置)
(gdb) set follow-fork-mode child
// 函数rdbSaveDb用于持久化数据快照
(gdb) b rdbSaveDb
Breakpoint 1 at 0x541a10: file rdb.c, line 1300.
(gdb) c

ブレークポイントを設定した後、Redis クライアントを使用してコマンド BGSAVE を送信すると、結果は次のようになります。

// 请求立即返回
127.0.0.1:6379> bgsave
Background saving started

// GDB输出以下信息
[New process 452541]
Breakpoint 1, rdbSaveDb (...) at rdb.c:1300

ご覧のとおり、GDB は現在子プロセスを追跡しており、プロセス ID は 452541 です。Linux コマンド ps を使用してすべてのプロセスを表示することもできます。結果は次のとおりです。

ps aux | grep redis
root     448144  0.0  0.0 270060 11520 pts/1    Sl+  17:00   0:00 ./src/redis-server 127.0.0.1:6379
root     452541  0.0  0.0 270064 11412 pts/1    t+   17:19   0:00 redis-rdb-bgsave 127.0.0.1:6379

子プロセスの名前が redis-rdb-bgsave であることがわかります。これは、このプロセスが RDB ファイル内のすべてのデータのスナップショットを保持することを意味します。

最後に、2 つの質問について考えてみましょう。

  • 質問 1: サブスレッドではなくサブプロセスを使用するのはなぜですか?

RDBではデータのスナップショットを永続的に保存するため、サブスレッドを使用するとメインスレッドとサブスレッドでメモリデータを共有することになり、メインスレッドも永続化したままメモリデータを変更するため、データの不整合が発生する可能性があります。メインプロセスと子プロセスのメモリデータは完全に分離されており、この問題は存在しません。

  • 質問 2: 10GB のデータが Redis メモリに保存されていると仮定します。永続化操作を実行するために子プロセスを作成した後、この時点で子プロセスにも 10GB のメモリが必要ですか? 10GBのメモリデータをコピーするのは時間がかかりますよね。また、システムのメモリが 15GB しかない場合でも、BGSAVE コマンドは実行できますか?

ここでコピーオンライトという概念があり、forkシステムコールで子プロセスを作成した後、メインプロセスと子プロセスのメモリデータを一時的に共有しますが、メインプロセスがメモリデータを変更する必要がある場合、システムは自動的にこのメモリ ブロックのコピーを作成し、メモリ データの分離を実現します。

BGSAVE コマンドの実行フローを次の図に示します。

写真

BGSAVE実行処理 BGSAVE実行処理BGS AV実行処理

04 まとめ

Redis のプロセス モデル/スレッド モデルはまだ比較的複雑です。ここでは、いくつかのシナリオでのマルチスレッドとマルチ処理について簡単に紹介するだけです。他のシナリオでのマルチスレッドとマルチ処理については、読者自身がまだ検討していません。

著者について
Li Le: TAL の Golang 開発専門家であり、西安電子科学技術大学で修士号を取得しています。かつて Didi で働いていたこともあります。テクノロジーとソース コードを深く掘り下げることに意欲的です。彼は、次の本の共著者です。 「Redis を効率的に使う: データ ストレージと高可用性クラスターを 1 冊で学ぶ」および「Redis5 の設計とソース コード分析」「Nginx の基盤となる設計とソース コード分析」。

▼多読

ここに画像の説明を挿入します

「Redis の効率的な使用: データ ストレージと高可用性クラスターを 1 冊で学ぶ」 「Redis の効率的な使用: データ ストレージと高可用性クラスターを 1 冊で学ぶ」Redis を効率的に使用する : データ ストレージと高可用性クラスターを 1で学ぶ

推奨される言葉: Redis データ構造と基盤となる実装を深く掘り下げ、Redis データ ストレージとクラスター管理の問題を克服します。

おすすめ

転載: blog.csdn.net/qq_32682301/article/details/136363807