redis源代码分析18–持久化之aof
Redis的aof功能的目的是在性能和持久化粒度上对持久化机制提供更好的支持。 快照方式持久化的粒度有时间(秒)和改变的key数两种,如果持久化的粒度较小,对性能会有较大的影响,因为每次都是dump整个db;如果持久化的粒度较大,则在指定时间内指定数目的数
Redis的aof功能的目的是在性能和持久化粒度上对持久化机制提供更好的支持。
快照方式持久化的粒度有时间(秒)和改变的key数两种,如果持久化的粒度较小,对性能会有较大的影响,因为每次都是dump整个db;如果持久化的粒度较大,则在指定时间内指定数目的数据的持久化无法保证。而aof持久化的粒度是每次会修改db数据的命令,因此粒度是最小的了,跟日志方式有点类似,由于仅记录一条命令,性能也最好。另外,跟日志类似,aof文件会越来越大,则可以通过执行BGREWRITEAOF命令在后台重建该文件。
我们先来看看redis如何记录命令的。
call函数是命令执行的函数(前面命令处理章节已详细介绍过该函数)。如果命令执行前后数据有修改,则server.dirty的取值会有变化。在启用了aof机制的情况下,call函数会调用feedAppendOnlyFile保存命令及其相关参数。
static void call(redisClient *c, struct redisCommand *cmd){ long long dirty; dirty = server.dirty; cmd->proc(c); dirty = server.dirty-dirty; if(server.appendonly && dirty) feedAppendOnlyFile(cmd,c->db->id,c->argv,c->argc); --- }
feedAppendOnlyFile会首先检查当前命令所处的db是否跟前一条命令执行所处db一致。若不一致,则需要发布一条选择db的select命令,然后做些命令的转换工作(代码略去)。
紧接着,将命令参数所对应的buf保存到server.aofbuf中,该参数保存了一段时间内redis执行的命令及其参数,redis会在适当的时机将其刷到磁盘上的aof文件中;然后如果有后台重建aof文件,则也将该缓冲区保存到server.bgrewritebuf中,该缓冲区保存了重建aof文件的后台进程运行时redis所执行的命令及其参数,后台进程退出时需要将这些命令保存到重建文件中。
static void feedAppendOnlyFile(struct redisCommand *cmd, int dictid, robj **argv, int argc){ --- server.aofbuf = sdscatlen(server.aofbuf,buf,sdslen(buf)); --- if(server.bgrewritechildpid != -1) server.bgrewritebuf = sdscatlen(server.bgrewritebuf,buf,sdslen(buf)); sdsfree(buf); }
我们来看看server.aofbuf会在什么时机被刷新到磁盘aof文件中。
刷新采用的是flushAppendOnlyFile函数。该函数在beforeSleep中会被调用(事件处理章节已介绍过该函数),而该函数是在处理client事件之前执行执行的(事件循环函数aeMain是先执行beforesleep,然后执行aeProcessEvents),因此,server.aofbuf中的值会在向client发送响应之前刷新到磁盘上。
flushAppendOnlyFile调用write一次性写全部server.aofbuf缓冲区中的数据,并根据配置的同步策略,调用aof_fsync(对系统同步函数fsync的保证)进行同步,这样新的命令及其参数就被附加到aof文件当中了。
static void flushAppendOnlyFile(void){ time_t now; ssize_t nwritten; --- nwritten = write(server.appendfd,server.aofbuf,sdslen(server.aofbuf)); --- sdsfree(server.aofbuf); server.aofbuf = sdsempty(); /* Fsync if needed */ now = time(NULL); if(server.appendfsync == APPENDFSYNC_ALWAYS|| (server.appendfsync == APPENDFSYNC_EVERYSEC && now-server.lastfsync > 1)) { /* aof_fsync is defined as fdatasync() for Linux in order to avoid * flushing metadata. */ aof_fsync(server.appendfd);/* Let's try to get this data on the disk */ server.lastfsync = now; } }
接下来我们看看后台如何重建aof文件。
aof重建靠调用rewriteAppendOnlyFileBackground函数完成。查看该函数的调用关系就可以知道,该函数会在收到bgrewriteaof命令后执行,也会在收到config命令并且从不使用aof机制到开启aof机制时被调用,也会在运行redis的系统作为slave时,跟master建立连接后并在serverCron函数中执行syncWithMaster时调用。
rewriteAppendOnlyFileBackground重建aof的主要逻辑如下(代码略去):
1)使用fork创建一个子进程
2)子进程调用rewriteAppendOnlyFile在一个临时文件里写能够反映当前db状态的数据和命令,
此时父进程会把这段时间内执行的能够改变当前db数据的命令放到server.bgrewritebuf中(参看前面对feedAppendOnlyFile的解释)
3)当子进程退出时,父进程收到信号,将上面的内存缓冲区中的数据flush到临时文件中,然后将临时文件rename成新的aof文件(backgroundRewriteDoneHandler)。
父进程会在serverCron函数中等待执行aof重写或者快照保存的子进程,代码如下:
/* Check if a background saving or AOF rewrite in progress terminated */ if(server.bgsavechildpid != -1||server.bgrewritechildpid != -1){ int statloc; pid_t pid; if((pid = wait3(&statloc,WNOHANG,NULL))!= 0){ if(pid == server.bgsavechildpid){ backgroundSaveDoneHandler(statloc); } else { backgroundRewriteDoneHandler(statloc); } updateDictResizePolicy(); } }
rewriteAppendOnlyFile将反映当前db状态的命令和参数写到一个临时文件中。该函数遍历db中的每条数据,redis中的db其实是一个大的hash表,每一条数据都用(key,val)来表示。从key可以知道val的类型(redis支持REDIS_STRING、REDIS_LIST、REDIS_SET、REDIS_ZSET、REDIS_HASH五种数据类型),然后解码val中的数据。写入时,按照客户端执行命令的形式写入。比如对于REDIS_STRING类型,则先写入”*3\r\n$3\r \nSET\r\n”,然后写入set的key,然后写入val;对于REDIS_LIST类型,将val强制转换为list类型后,先写入”*3\r \n$5\r\nRPUSH\r\n”,然后写入要操作的list的名字,然后写入list的第一个数据,循环前面3个步骤直到list遍历完;对于REDIS_SET类型,则对于每条数据先写入”*3\r\n$4\r\nSADD\r\n”;对于REDIS_ZSET类型,则对于每条数据先写入”*4\r\n$4\r\nZADD\r\n”;对于REDIS_HASH类型,则对于每条数据先写入”*4\r\n$4\r\nHSET\r\n”(代码简单但较琐碎,略去)。
最后我们介绍下redis启动时使用aof重建db的步骤。
启动时重建的关键是构建一个fake client,然后使用这个client向server发送从aof文件中读入的命令。
int loadAppendOnlyFile(char *filename){ --- fakeClient = createFakeClient(); while(1){ --- if(fgets(buf,sizeof(buf),fp)== NULL){ --- } // 解析buf为对应的命令及参数 // 查找命令 cmd = lookupCommand(argv[0]->ptr); --- // 执行命令 cmd->proc(fakeClient); --- } --- }
原文地址:redis源代码分析18–持久化之aof, 感谢原作者分享。

ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

Video Face Swap
完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

SublimeText3 中国語版
中国語版、とても使いやすい

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)

ホットトピック











Redisクラスターモードは、シャードを介してRedisインスタンスを複数のサーバーに展開し、スケーラビリティと可用性を向上させます。構造の手順は次のとおりです。異なるポートで奇妙なRedisインスタンスを作成します。 3つのセンチネルインスタンスを作成し、Redisインスタンスを監視し、フェールオーバーを監視します。 Sentinel構成ファイルを構成し、Redisインスタンス情報とフェールオーバー設定の監視を追加します。 Redisインスタンス構成ファイルを構成し、クラスターモードを有効にし、クラスター情報ファイルパスを指定します。各Redisインスタンスの情報を含むnodes.confファイルを作成します。クラスターを起動し、CREATEコマンドを実行してクラスターを作成し、レプリカの数を指定します。クラスターにログインしてクラスター情報コマンドを実行して、クラスターステータスを確認します。作る

Redisデータをクリアする方法:Flushallコマンドを使用して、すべての重要な値をクリアします。 FlushDBコマンドを使用して、現在選択されているデータベースのキー値をクリアします。 [選択]を使用してデータベースを切り替え、FlushDBを使用して複数のデータベースをクリアします。 DELコマンドを使用して、特定のキーを削除します。 Redis-CLIツールを使用してデータをクリアします。

Redisのキューを読むには、キュー名を取得し、LPOPコマンドを使用して要素を読み、空のキューを処理する必要があります。特定の手順は次のとおりです。キュー名を取得します:「キュー:キュー」などの「キュー:」のプレフィックスで名前を付けます。 LPOPコマンドを使用します。キューのヘッドから要素を排出し、LPOP Queue:My-Queueなどの値を返します。空のキューの処理:キューが空の場合、LPOPはnilを返し、要素を読む前にキューが存在するかどうかを確認できます。

Centosシステムでは、Redis構成ファイルを変更するか、Redisコマンドを使用して悪意のあるスクリプトがあまりにも多くのリソースを消費しないようにすることにより、LUAスクリプトの実行時間を制限できます。方法1:Redis構成ファイルを変更し、Redis構成ファイルを見つけます:Redis構成ファイルは通常/etc/redis/redis.confにあります。構成ファイルの編集:テキストエディター(VIやNANOなど)を使用して構成ファイルを開きます:sudovi/etc/redis/redis.conf luaスクリプト実行時間制限を設定します。

Redisコマンドラインツール(Redis-Cli)を使用して、次の手順を使用してRedisを管理および操作します。サーバーに接続し、アドレスとポートを指定します。コマンド名とパラメーターを使用して、コマンドをサーバーに送信します。ヘルプコマンドを使用して、特定のコマンドのヘルプ情報を表示します。 QUITコマンドを使用して、コマンドラインツールを終了します。

Redisカウンターは、Redisキー価値ペアストレージを使用して、カウンターキーの作成、カウントの増加、カウントの減少、カウントのリセット、およびカウントの取得など、カウント操作を実装するメカニズムです。 Redisカウンターの利点には、高速速度、高い並行性、耐久性、シンプルさと使いやすさが含まれます。ユーザーアクセスカウント、リアルタイムメトリック追跡、ゲームのスコアとランキング、注文処理などのシナリオで使用できます。

Redisデータの有効期間戦略には2つのタイプがあります。周期削除:期限切れのキーを削除する定期的なスキャン。これは、期限切れの時間帯-remove-countおよび期限切れの時間帯-remove-delayパラメーターを介して設定できます。怠zyな削除:キーが読み取られたり書かれたりした場合にのみ、削除の有効期限が切れたキーを確認してください。それらは、レイジーフリーレイジーエビクション、レイジーフリーレイジーエクスピア、レイジーフリーラジーユーザーのパラメーターを介して設定できます。

Debian Systemsでは、Directoryコンテンツを読み取るためにReadDirシステム呼び出しが使用されます。パフォーマンスが良くない場合は、次の最適化戦略を試してください。ディレクトリファイルの数を簡素化します。大きなディレクトリをできる限り複数の小さなディレクトリに分割し、Readdirコールごとに処理されたアイテムの数を減らします。ディレクトリコンテンツのキャッシュを有効にする:キャッシュメカニズムを構築し、定期的にキャッシュを更新するか、ディレクトリコンテンツが変更されたときに、頻繁な呼び出しをreaddirに削減します。メモリキャッシュ(memcachedやredisなど)またはローカルキャッシュ(ファイルやデータベースなど)を考慮することができます。効率的なデータ構造を採用する:ディレクトリトラバーサルを自分で実装する場合、より効率的なデータ構造(線形検索の代わりにハッシュテーブルなど)を選択してディレクトリ情報を保存およびアクセスする
