この記事では、Redis に関する関連知識を提供し、主に永続性が必要な理由、RDB 永続性、AOF 永続性など、永続性に関する関連問題を紹介します。皆さんのお役に立てば幸いです。
推奨学習: Redis ビデオ チュートリアル
Redis のデータ操作はすべてメモリに基づいており、プロセスの終了やサーバーのダウンタイムなどの予期せぬ状況が発生した場合、永続化メカニズムがないと、Redis 内のデータが失われ、復元できなくなります。永続化メカニズムを使用すると、Redis は次回再起動するときに、以前に永続化されたファイルをデータ回復に使用できます。 Redis でサポートされる 2 つの永続化メカニズム:
RDB: 現在のデータのスナップショットを生成し、ハード ディスクに保存します。
AOF: データに対するすべての操作をハードディスクに記録します。
指定された時間内にメモリ上のデータセットのスナップショットをディスクに書き込み、リストアするとスナップショットファイルが保存されます。メモリ内で直接読み取ります。 RDB (Redis Database) の永続化とは、Redis 内のすべての現在のデータのスナップショットを生成し、ハードディスクに保存することです。 RDB 永続化は手動または自動でトリガーできます。
Redis は永続化のために子プロセスを個別に作成 (フォーク) します。最初にデータを一時ファイルに書き込みます。永続化プロセスが完了した後、この一時ファイルは最後の永続性を置き換えるために使用されます。OKファイル。プロセス全体を通じて、メイン プロセスは IO 操作を実行しないため、非常に高いパフォーマンスが保証されます。大規模なデータ リカバリが必要で、データ リカバリの整合性がそれほど重要でない場合は、RDB 方式の方が AOF 方式よりも効率的です。 RDB の欠点は、最後に保存されたデータが失われる可能性があることです。
save
両方bgsave
コマンドは、RDB 永続性を手動でトリガーできます。
save
save
コマンドを実行すると、RDB 永続化が手動でトリガーされますが、save
コマンドは、RDB の永続化が完了するまで Redis サービスをブロックします。 Redis サービスが大量のデータを保存すると、長期的な輻輳が発生するため、お勧めできません。 bgsave
bgsave
コマンドを実行すると、RDB 永続化も手動でトリガーされます。これは、save## とは異なります。 # command. : Redis サービスは通常、ブロックしません。 Redis プロセスはフォーク操作を実行して子プロセスを作成します。子プロセスは RDB の永続化を担当し、Redis サービス プロセスをブロックしません。 Redis サービスのブロックはフォーク フェーズでのみ発生し、一般に時間は非常に短いです。
コマンドの具体的な処理は次のとおりです:
コマンドを実行します。プロセスはまず、現在実行中の RDB または AOF サブスレッドがあるかどうかを判断し、存在する場合は直接終了します。
2. Redis プロセスは子スレッドを作成するためにフォーク操作を実行しますが、Redis プロセスはフォーク操作中にブロックされます。 コマンドが終了し、それ以降、Redis プロセスはブロックされず、他のコマンドに応答できるようになります。
4. 子プロセスは、Redis プロセスのメモリに基づいてスナップショット ファイルを生成し、元の RDB ファイルを置き換えます。 bgsave を使用して Redis プロセスのブロックを軽減します。では、どのような状況で自動的に発動するのでしょうか?
の関連構成は、
sava m n などの構成ファイルに設定されます。これは、データが m 以内に n 回変更されると、秒、
bgsave 操作を自動的にトリガーします。
操作を実行し、生成された RDB ファイルをスレーブ ノードに送信します。
コマンドを実行すると、
bgsave 操作も自動的にトリガーされます。
コマンドを実行するときに、AOF 永続化が有効になっていない場合、
bgsave 操作が自動的にトリガーされます。
bgsave
を実行するたびに、子を作成するためにフォーク操作を実行する必要があります。これは重量のある操作です。頻繁に実行するとコストがかかりすぎます。高いため、リアルタイム永続化、つまり第 2 レベルの永続性を実現できません。
さらに、Redis のバージョンが継続的に繰り返されるため、異なる形式の RDB バージョンが存在し、下位バージョンの RDB 形式が上位バージョンの RDB ファイルと互換性がないという問題が発生する可能性があります。
スナップショット期間 : メモリ スナップショットは技術者が手動で実行できますが、SAVE
または BGSAVE
コマンドですが、ほとんどの実稼働環境では、定期的な実行条件が設定されます。
# 周期性执行条件的设置格式为 save <seconds> <changes> # 默认的设置为: save 900 1 save 300 10 save 60 10000 # 以下设置方式为关闭RDB快照功能 save ""</changes></seconds>
上記の 3 つのデフォルト情報設定の意味は次のとおりです:
# 文件名称 dbfilename dump.rdb # 文件保存路径 dir ./ # 如果持久化出错,主进程是否停止写入 stop-writes-on-bgsave-error yes # 是否压缩 rdbcompression yes # 导入时是否检查 rdbchecksum yes
bgsave
子进程相互不影响。但是,如果主线程要修改一块数据(例如图中的键值对 C),那么,这块数据就会被复制一份,生成该数据的副本。然后,bgsave
子进程会把这个副本数据写入 RDB 文件,而在这个过程中,主线程仍然可以直接修改原来的数据。针对RDB不适合实时持久化的问题,Redis提供了AOF持久化方式来解决
AOF(Append Only File)持久化是把每次写命令追加写入日志中,当需要恢复数据时重新执行AOF文件中的命令就可以了。AOF解决了数据持久化的实时性,也是目前主流的Redis持久化方式。
Redis是“写后”日志,Redis先执行命令,把数据写入内存,然后才记录日志。日志里记录的是Redis收到的每一条命令,这些命令是以文本形式保存。PS: 大多数的数据库采用的是写前日志(WAL),例如MySQL,通过写前日志和两阶段提交,实现数据和逻辑的一致性。
而AOF日志采用写后日志,即先写内存,后写日志。
为什么采用写后日志?
Redis要求高性能,采用写日志有两方面好处:
但这种方式存在潜在风险:
AOF日志记录Redis的每个写命令,步骤分为:命令追加(append)、文件写入(write)和文件同步(sync)。
默认情况下,Redis是没有开启AOF的,可以通过配置redis.conf文件来开启AOF持久化,关于AOF的配置如下:
# appendonly参数开启AOF持久化 appendonly no # AOF持久化的文件名,默认是appendonly.aof appendfilename "appendonly.aof" # AOF文件的保存位置和RDB文件的位置相同,都是通过dir参数设置的 dir ./ # 同步策略 # appendfsync always appendfsync everysec # appendfsync no # aof重写期间是否同步 no-appendfsync-on-rewrite no # 重写触发配置 auto-aof-rewrite-percentage 100 auto-aof-rewrite-min-size 64mb # 加载aof出错如何处理 aof-load-truncated yes # 文件重写策略 aof-rewrite-incremental-fsync yes
以下是Redis中关于AOF的主要配置信息:
appendfsync:这个参数项是AOF功能最重要的设置项之一,主要用于设置“真正执行”操作命令向AOF文件中同步的策略。
什么叫“真正执行”呢?还记得Linux操作系统对磁盘设备的操作方式吗? 为了保证操作系统中I/O队列的操作效率,应用程序提交的I/O操作请求一般是被放置在linux Page Cache中的,然后再由Linux操作系统中的策略自行决定正在写到磁盘上的时机。而Redis中有一个fsync()函数,可以将Page Cache中待写的数据真正写入到物理设备上,而缺点是频繁调用这个fsync()函数干预操作系统的既定策略,可能导致I/O卡顿的现象频繁 。
与上节对应,appendfsync参数项可以设置三个值,分别是:always、everysec、no,默认的值为everysec。
no-appendfsync-on-rewrite:always和everysec的设置会使真正的I/O操作高频度的出现,甚至会出现长时间的卡顿情况,这个问题出现在操作系统层面上,所有靠工作在操作系统之上的Redis是没法解决的。为了尽量缓解这个情况,Redis提供了这个设置项,保证在完成fsync函数调用时,不会将这段时间内发生的命令操作放入操作系统的Page Cache(这段时间Redis还在接受客户端的各种写操作命令)。
auto-aof-rewrite-percentage: 前述したように、運用環境では、技術者が「BGREWRITEAOF
」コマンドを使用することはできません。いつでもどこでも AOF ファイルを書き換えます。そのため、Redis の AOF ファイルの自動書き換え戦略に依存する必要が多くなります。 Redis には、AOF ファイルの自動書き換えをトリガーするための 2 つの設定が用意されています。
auto-aof-rewrite-percentage 現在の AOF ファイルのサイズが特定の書き換え後の最後のサイズを超えるかどうかを意味します。 AOF ファイルのパーセンテージに達したら、AOF ファイルの書き換えを再度開始します。たとえば、このパラメータ値のデフォルト設定値は 100 です。これは、AOF ファイルのサイズが最後の AOF ファイル書き換えサイズの 1 倍を超えた場合に、書き換え操作が開始されることを意味します。
auto-aof-rewrite-min-size: 設定項目は、AOF ファイルの書き換え操作を開始する AOF ファイルの最小サイズを示します。 AOF ファイルのサイズがこの値より小さい場合、再書き込み操作はトリガーされません。 auto-aof-rewrite-percentage と auto-aof-rewrite-min-size は、Redis での AOF ファイルの自動再書き込みを制御するためにのみ使用されることに注意してください。技術者が手動で「BGREWRITEAOF
」コマンドを呼び出した場合、コマンドは無効になります。これら 2 つの制限が適用されます。
AOF は、各書き込みコマンドを AOF ファイルに記録します。時間の経過とともに、AOF ファイルはますます大きくなります。制御しないと、Redis サーバーやオペレーティング システムにさえ影響を及ぼし、さらに、AOF ファイルが大きくなるほど、データの回復が遅くなります。 AOF ファイル サイズの拡大の問題を解決するために、Redis は AOF ファイルを「スリム化」するための AOF ファイル書き換えメカニズムを提供します。
AOF 書き換えを説明する図
AOF 書き換えはブロックされますか?
AOF 書き換えプロセスは、バックグラウンド プロセス bgrewriteaof によって完了します。メイン スレッドはバックグラウンドで bgrewriteaof 子プロセスからフォークし、データベースの最新データを含むメイン スレッドのメモリを bgrewriteaof 子プロセスにコピーします。次に、bgrewriteaof サブプロセスは、メインスレッドに影響を与えることなく、コピーされたデータを 1 つずつオペレーションに書き込み、書き換えログに記録できます。したがって、aof が書き換えられると、プロセスをフォークするときにメインスレッドがブロックされてしまいます。
AOF ログはいつ書き換えられますか?
AOF リライトのトリガーを制御する構成項目は 2 つあります:
auto-aof-rewrite-min-size: 実行時のファイルの最小サイズを示します。 AOF 書き換え、デフォルトは 64MB です。
auto-aof-rewrite-percentage: この値は、現在の aof ファイル サイズと最後の書き換え後の aof ファイル サイズの差を、前回の書き換え後の aof ファイル サイズで割ることによって計算されます。書き換えるサイズを変更します。つまり、最後に書き換えられた AOF ファイルと比較した現在の AOF ファイルの増分サイズ、および最後の書き換え後の AOF ファイル サイズの比率です。
ログを書き換える際に新しいデータが書き込まれた場合はどうすればよいですか?
書き換えプロセスは、「1 つのコピー、2 つのログ」のように要約できます。子プロセスからフォークアウトするとき、および再書き込みするとき、新しいデータが書き込まれると、メインスレッドはコマンドを 2 つのログ メモリ バッファに記録します。 AOF ライトバック ポリシーが常に設定されている場合、コマンドは古いログ ファイルに直接書き戻され、コマンドのコピーが AOF 書き換えバッファに保存されます。これらの操作は新しいログ ファイルには影響しません。 (古いログ ファイル: メイン スレッドで使用されるログ ファイル、新しいログ ファイル: bgrewriteaof プロセスで使用されるログ ファイル)
bgrewriteaof 子プロセスがログ ファイルの書き換え操作を完了すると、プロンプトが表示されます。書き換え操作が完了すると、メインスレッドは AOF 書き換えバッファ内のコマンドを新しいログ ファイルの末尾に追加します。現時点では、高い同時実行条件下では、AOF 書き換えバッファーの蓄積が非常に大きくなり、ブロッキングが発生する可能性があります。Redis は後に Linux パイプライン テクノロジを使用して、AOF 書き換え中の同時再生を可能にしました。残りわずかなデータを再生する必要があります。最後に、ファイル名を変更することで、ファイル切り替えのアトミック性が確保されます。
AOF ログの書き換え中にダウンタイムが発生した場合、ログ ファイルが切り替えられていないため、データのリストア時に古いログ ファイルが引き続き使用されます。
概要操作:
注意喚起
ここでのプロセスとスレッド この概念は少しわかりにくいです。バックグラウンドの bgreweiteaof プロセスでは動作するスレッドが 1 つだけであり、メイン スレッドは Redis 動作プロセスであり、これも単一スレッドであるためです。ここで言いたいのは、Redis メイン プロセスがバックグラウンド プロセスをフォークした後は、バックグラウンド プロセスの操作はメイン プロセスと何の関係もなく、メイン スレッドをブロックしないということです。
#メインスレッドはどのようにして子プロセスをフォークアウトし、メモリデータをコピーするのでしょうか?
Fork は、オペレーティング システムが提供するコピー オン ライト メカニズムを使用して、大量のメモリ データを一度にコピーして子プロセスをブロックすることを回避します。子プロセスをフォークするとき、子プロセスは親プロセスのページ テーブル、つまり仮想と実のマッピング関係 (仮想メモリと物理メモリ間のマッピング インデックス テーブル) をコピーしますが、物理メモリはコピーしません。このコピーは大量の CPU リソースを消費し、コピーが完了する前にメイン スレッドがブロックされます。ブロック時間はメモリ内のデータ量によって異なります。データ量が増えるほど、メモリ ページ テーブルも大きくなります。コピーが完了すると、親プロセスと子プロセスは同じメモリ アドレス空間を使用します。
ただし、メインプロセスはデータを書き込むことができ、このとき物理メモリ内のデータがコピーされます。以下に示すように (プロセス 1 をメインプロセス、プロセス 2 を子プロセスとみなします):
メインプロセスにデータが書き込まれており、そのデータがたまたまページ c にある場合、オペレーティング システムは、このページのコピー (ページ c のコピー) を作成します。つまり、現在のページの物理データをコピーしてメイン プロセスにマップしますが、子プロセスは引き続き元のページ c を使用します。
ログプロセス全体を書き換える場合、メインスレッドはどこでブロックされますか?
AOF 書き換えでは元の AOF ログが再利用されないのはなぜですか?
Redis 4.0 では、AOF ログとメモリ スナップショットを混合して使用する方式が提案されています。簡単に言うと、メモリ スナップショットは特定の頻度で実行され、2 つのスナップショットの間に AOF ログを使用して、この期間中のすべてのコマンド操作が記録されます。
このようにすると、スナップショットを頻繁に実行する必要がなくなり、メインスレッドでの頻繁なフォークの影響が回避されます。また、AOFログは2つのスナップショット間の操作のみを記録するため、すべての操作を記録する必要がないため、ファイルサイズが大きくなりすぎず、書き換えのオーバーヘッドも回避できます。
次の図に示すように、T1 と T2 での変更は AOF ログに記録されます。2 番目の完全なスナップショットが取得されると、この時点でのすべての変更が記録されているため、AOF ログをクリアできます。スナップショットにある場合、ログはリカバリ中に使用されなくなります。
この方法は、RDB ファイルの高速復旧のメリットを享受できるだけでなく、操作コマンドを記録するだけの AOF というシンプルなメリットも享受できるため、実環境で広く使用されています。
データのバックアップと永続化が完了した後、これらの永続化ファイルからデータを復元するにはどうすればよいでしょうか?サーバー上に RDB ファイルと AOF ファイルの両方がある場合、どちらをロードする必要がありますか?
実際、これらのファイルからデータを回復したい場合は、Redis を再起動するだけで済みます。
では、なぜ AOF が最初に読み込まれるのでしょうか? AOF によって保存されたデータはより完全であるため、上記の分析を通じて、AOF では基本的に最大 1 秒のデータが失われることがわかります。
推奨学習:以上がRedis 永続性を完全にマスター: RDB と AOFの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。