Redis の大きなキーは永続性にどのような影響を与えますか?

著者:小林コーディング
グラフィックコンピュータ財団(オペレーティングシステム、コンピュータネットワーク、コンピュータ構成、データベースなど) ウェブサイト:https ://xiaolincoding.com

皆さんこんにちは、シャオリンです。

先週、ある読者から質問がありました: Redis の大きなキーは永続性にどのような影響を与えますか?

·

Redis の永続化方法には、AOF ログと RDB スナップショットの 2 つがあります。

次に、これら2つの永続化方法を詳細に分析および分析します。

大きなキーが AOF ログに与える影響

AOF ログをディスクに書き戻すための 3 つの戦略についてお話ししましょう。

Redis は、AOF ログをハードディスクに書き戻すための 3 つの戦略を提供します。

  • Always、この単語は「常に」を意味するため、各書き込み操作コマンドが実行された後、AOF ログ データが同期的にハードディスクに書き戻されることを意味します。
  • Everysec という言葉は「1 秒あたり」を意味するため、各書き込み操作コマンドが実行された後、まずコマンドが AOF ファイルのカーネル バッファーに書き込まれ、次にバッファーの内容が 1 秒ごとに書き戻されることを意味します。ハードドライブ;
  • いいえ、つまり、ハードディスクへの書き戻しのタイミングはRedisによって制御されず、書き戻しのタイミングを制御するためにオペレーティングシステムに転送されます。つまり、各書き込み操作コマンドが実行された後、コマンドが最初に書き込まれますシステムは、いつバッファの内容をディスクに書き戻すかを決定します。

これら 3 つの戦略は、fsync() 関数を呼び出すタイミングのみを制御しています。

アプリケーションがデータをファイルに書き込む場合、通常、カーネルはまずデータをカーネル バッファーにコピーし、次にそれをキューに入れ、次にいつハードディスクに書き込むかを決定します。

アプリケーションがデータをファイルに書き込んだ直後に、アプリケーションがデータをハードディスクに同期するようにするには、fsync() 関数を呼び出して、カーネルがカーネル バッファー内のデータを直接ハードディスクに書き込むようにします。ハードディスクの書き込み操作が完了するまで待つと、関数は戻ります。

  • Always 戦略は、AOF ファイル データが書き込まれるたびに fsync() 関数を実行することです。
  • Everysec 戦略は、fsync() 関数を実行する非同期タスクを作成します。
  • No 戦略は、fsync() 関数を実行しないことです。

これら 3 つの戦略について個別に説明しましょう. 大きな鍵が持続されると、どのような影響があるでしょうか?

Always ポリシーを使用する場合、メイン スレッドは、コマンドの実行後にデータを AOF ログ ファイルに書き込み、次に fsync() 関数を呼び出して、カーネル バッファー内のデータを直接ハード ディスクに書き込み、ハード ディスクがログに記録されるまで待機します。ディスク書き込み操作が完了すると、関数は戻ります。

Always ストラテジを使用する場合、書き込みが大きな Key である場合、書き込まれたデータの量が多い場合、データがハード ディスクに同期されるため、fsync() 関数の実行時にメイン スレッドが長時間ブロックされます。このプロセスには時間がかかります

Everysec ポリシーを使用する場合、fsync() 関数は非同期で実行されるため、大きなキーを永続化するプロセス (ディスクへのデータ同期) はメイン スレッドに影響しません。

No ポリシーを使用すると、fsync() 関数が実行されないため、大きなキーを永続化するプロセスがメイン スレッドに影響を与えません。

大きなキーが AOF 書き換えと RDB に与える影響

多くの大きなキーが AOF ログに書き込まれると、AOF ログ ファイルのサイズが大きくなり、AOF書き換えメカニズムがすぐにトリガーされます。

AOF 書き換えメカニズムと RDB スナップショット (bgsave コマンド) のプロセスは、タスクを処理するfork()関数。

子プロセスを作成する過程で、オペレーティング システムは親プロセスの「ページ テーブル」を子プロセスにコピーします. このページ テーブルには、物理​​メモリをコピーすることなく、仮想アドレスと物理アドレスのマッピング関係が記録されます. つまり、 、 2つの仮想空間は異なりますが、対応する物理空間は同じです。


このようにして、子プロセスは親プロセスの物理メモリ データを共有し、物理メモリ リソースを節約できます。ページ テーブルに対応するページ テーブル エントリの属性は、物理メモリのアクセス許可を読み取り専用としてマークします

Redis はますます大きなキーを持つようになるため、Redis は大量のメモリを占有し、対応するページ テーブルが大きくなります。

fork()関数を使用して子プロセスを作成すると、親プロセスの物理メモリはコピーされませんが、カーネルは親プロセスのページ テーブルを子プロセスにコピーします.ページ テーブルが大きい場合、コピー処理は非常に時間がかかる はい、fork 関数が実行されるとブロッキングが発生します

また、fork 関数は Redis のメイン スレッドから呼び出されるため、fork 関数がブロックされている場合は、Redis のメイン スレッドがブロックされていることを意味します。Redis 実行コマンドはメイン スレッドで処理されるため、Redis メイン スレッドがブロックされると、クライアントから送信された後続のコマンドを処理できなくなります。

info コマンドを実行して latest_fork_usec インジケーターを取得できます。これは、Redis の最新のフォーク操作に時間がかかることを示しています。

# 最近一次 fork 操作耗时
latest_fork_usec:315

fork に 1 秒以上かかるなど、長い時間がかかる場合は、最適化の調整を行う必要があります。

  • 1 つのインスタンスのメモリ使用量は 10 GB 未満に制御されているため、fork 関数はすぐに復帰できます。
  • Redis が純粋なキャッシュとしてのみ使用され、Redis データのセキュリティを気にしない場合は、フォーク関数が呼び出されないように、AOF と AOF の書き換えをオフにすることを検討できます。
  • マスター/スレーブ アーキテクチャでは、repl_backlog_buffer が十分に大きくないために、マスター ノードが完全な同期方法を頻繁に使用することを避けるために、repl-backlog-size を適切に増やす必要があります。完全な同期が実行されると、RDB ファイルが作成されます。 、つまり、フォークは関数と呼ばれます。

物理メモリのコピーはいつ行われますか?

親プロセスまたは子プロセスが共有メモリへの書き込み操作を開始すると、CPU はページ フォールト割り込みをトリガーします. このページ フォールト割り込みは、アクセス許可の違反によって引き起こされ、オペレーティング システムは物理メモリ処理を実行します。 「ページフォルト例外処理機能」をコピーし、そのメモリマッピング関係をリセットし、親プロセスと子プロセスのメモリの読み書き権限を読み書き可能に設定し、最後にメモリに書き込みます。このプロセスを「コピーオン」と呼びます。書き込み(コピーオンライト) .

コピー オン ライトは、名前が示すように、書き込み操作が発生した場合にのみ、オペレーティング システムが物理メモリをコピーします. これは、物理メモリのコピー時間が長いために親プロセスが長時間ブロックされるのを防ぐためです. fork が子プロセスを作成するときのメモリ データ。

子プロセスが作成された後に親プロセスが共有メモリ内の大きなキーを変更すると、カーネルはコピー オン ライトで物理メモリをコピーします. 大きなキーが占有する物理メモリは比較的大きいため

そのため、親プロセスのブロックにつながる 2 つのフェーズがあります。

  • 子プロセスを作成する途中で、親プロセスのページテーブルなどのデータ構造をコピーする必要があるため、ブロッキング時間はページテーブルのサイズに関係し、ページテーブルが大きいほどブロッキング時間は長くなります。時間;
  • 子プロセスが作成された後、子プロセスまたは親プロセスが共有データを変更すると、コピー オン ライトが発生します. この間、物理メモリがコピーされます. メモリが大きい場合、自然なブロック時間は長くなります.長くなります。

Linux が大きなメモリ ページを有効にすると、Redis のパフォーマンスに影響します

Linux カーネルは 2.6.38 以降、メモリ ヒュージ ページ メカニズムをサポートしており、2MB サイズのメモリ ページ割り当てをサポートしていますが、通常のメモリ ページ割り当ては 4KB の粒度で実行されます。

大きなメモリ ページが使用されている場合、クライアントが 100B のデータのみを変更するように要求した場合でも、Redis はコピー オン ライトが発生した後に 2MB の大きなページをコピーする必要があります。逆に従来のメモリページ機構だと4KBしかコピーされません。

2 つを比較すると、各書き込みコマンドによって発生するコピー メモリ ページ単位が 512 倍に拡大され、書き込み操作の実行時間が遅くなり、最終的に Redis のパフォーマンスが低下することがわかります

じゃあ何をすればいいの?非常に簡単です。メモリ ヒュージ ページをオフにします (デフォルトはオフです)。

無効にする方法は次のとおりです。

echo never >  /sys/kernel/mm/transparent_hugepage/enabled

要約する

AOF ライトバック ポリシーが Always ポリシーで構成されている場合、書き込みが大きなキーである場合、fsync() 関数の実行時にメイン スレッドが長時間ブロックされます。データの同期 ハードディスクへのこのプロセスは非常に時間がかかります。

AOF 書き換えメカニズムと RDB スナップショット (bgsave コマンド) のプロセスは、タスクを処理するfork()関数。親プロセス (メイン スレッド) をブロックする 2 つのフェーズがあります。

  • 子プロセスを作成する途中で、親プロセスのページテーブルなどのデータ構造をコピーする必要があるため、ブロッキング時間はページテーブルのサイズに関係し、ページテーブルが大きいほどブロッキング時間は長くなります。時間;
  • 子プロセスが作成された後、親プロセスが共有データ内の大きな Key を変更すると、コピー オン ライトが発生し、その間に物理メモリがコピーされるため、大きな Key が占有する物理メモリは大きい場合、物理メモリのコピーが処理されますが、時間がかかるため、親プロセスをブロックすることができます。

持続性への影響に加えて、大きなキーには次のような影響もあります。

  • クライアントがタイムアウトになり、ブロックされました。Redis はコマンドをシングル スレッド プロセスで実行し、大きなキーを操作するには時間がかかるため、Redis がブロックされ、クライアントから見ると長時間応答がありません。

  • ネットワークの輻輳を引き起こします。大きなキーを取得するたびに、ネットワーク トラフィックは比較的大きくなります. キーのサイズが 1 MB で、1 秒あたりのアクセス数が 1000 である場合、1 秒あたり 1000 MB のトラフィックが生成されます。通常のギガビット ネットワーク カードを搭載したサーバー。

  • ワーカー スレッドをブロックします。del を使用して大きなキーを削除すると、ワーカー スレッドがブロックされ、後続のコマンドを処理できなくなります。

  • メモリは不均等に分散されます。クラスター モデルでは、スロットの断片化が均一な場合、データとクエリのスキューが発生します. 大きなキーを持つ一部の Redis ノードは多くのメモリを占有し、QPS は比較的大きくなります.

大きな鍵を避けるには?

設計段階で大きなキーを小さなキーに分割することをお勧めします。または、定期的に Redis に大きなキーが存在するかどうかを確認します. 大きなキーを削除できる場合は、DEL コマンドを使用して削除しないでください, このコマンドの削除プロセスはメインスレッドをブロックします. 代わりに unlink コマンドを使用してください. (Redis 4.0+) 大きなキーを削除します。このコマンドの削除プロセスは非同期であり、メイン スレッドをブロックしません。

以上!

おすすめ

転載: blog.csdn.net/qq_34827674/article/details/126829220