Redis 永続化

スポンサーリンク

デフォルトの挙動ではRedisのデータはメモリに書き込まれるため、再起動と同時にデータが失われてしまいます。このページではデータが失われないように工夫したり、データのバックアップ・リストアしたりする方法を説明します。

前提

公式ドキュメント

参考になる公式ドキュメントを以下に示します。

動作確認済環境

  • Rocky Linux 8.6
  • Redis 5.0.3

永続化設定

RDBファイル

Redisは一定間隔でRDB(Redis Database)ファイルにデータを書き込みます。書き込み頻度は/etc/redis.confに以下のような書式で定義できます。

save <時間(秒)> <書き込み回数>

デフォルト設定は以下の通りです。

# less /etc/redis.conf 

  <omitted>

################################ SNAPSHOTTING  ################################
#
# Save the DB on disk:
#
#   save <seconds> <changes>
#
#   Will save the DB if both the given number of seconds and the given
#   number of write operations against the DB occurred.
#
#   In the example below the behaviour will be to save:
#   after 900 sec (15 min) if at least 1 key changed
#   after 300 sec (5 min) if at least 10 keys changed
#   after 60 sec if at least 10000 keys changed
#
#   Note: you can disable saving completely by commenting out all "save" lines.
#
#   It is also possible to remove all the previously configured save
#   points by adding a save directive with a single empty string argument
#   like in the following example:
#
#   save ""

save 900 1
save 300 10
save 60 10000

  <omitted>

デフォルト設定では、「900秒で1回」または「300秒で10回」または「60秒で10000回」の書き込みが発生した場合に、RDBファイルが作成されます。

それでは動作確認をしてみましょう。/var/lib/redis/配下のファイルを確認します。前述のRDB作成条件に該当しないならば、何もファイルが作成されていません。RDB作成条件に該当するならば、dump.rdbというファイルが作成されています。dump.rdbというファイルが存在する方は、このファイルのタイムスタンプを記憶しておきましょう。

[root@linux010 ~]# ls -l /var/lib/redis/
total 4
-rw-r--r--. 1 redis redis 362 Nov 23 11:47 dump.rdb
[root@linux010 ~]# 

60秒で10000回の書き込みをした時に、RDBファイルが作成される事を確認します。以下は100000回の書き込みをする操作例です。

for i in {0..10000}
do
 redis-cli SET key${i} value${i} > /dev/null
done

確かにタイムスタンプが更新された事を確認します。

[root@linux010 ~]# date
Wed Nov 23 11:50:35 UTC 2022
[root@linux010 ~]# for i in {0..10000}
> do
>  redis-cli SET key${i} value${i} > /dev/null
> done
[root@linux010 ~]# date
Wed Nov 23 11:51:01 UTC 2022
[root@linux010 ~]# ls -l /var/lib/redis/
total 184
-rw-r--r--. 1 redis redis 187899 Nov 23 11:50 dump.rdb
[root@linux010 ~]# 

AOFの有効化

前述のRDBはある断面のデータを保存する仕組みなので、突然の電源断のような障害に備えた永続化の仕組みではありません。

突然の電源断のような障害に備えるにはAOF(Append Only File)を使用します。AOFはデータベースへの書き込み内容を記録した先行書き込みログのファイルです。RDBMSの知識がある方ならば、PostgresのWALやMySQLのbinlogを想像すれば良いでしょう。

AOFはデフォルトで無効になっています。/etc/redis.confをテキストエディタで開き「appendonly yes」に変更する事でAOFを有効にできます。

# vi /etc/redis.conf 

 <omitted>

# AOF and RDB persistence can be enabled at the same time without problems.
# If the AOF is enabled on startup Redis will load the AOF, that is the file
# with the better durability guarantees.
#
# Please check http://redis.io/topics/persistence for more information.

appendonly yes

# The name of the append only file (default: "appendonly.aof")

appendfilename "appendonly.aof"

 <omitted>

AOFに書き込まれるタイミングはコマンド発行の都度ですが、fsyncを呼び出しディスクに書き込まれるタイミングはデフォルト設定では1秒に1回です。この書き込み頻度は、/etc/redis.confのappendfsyncというパラメタで変更する事ができます。

# vi /etc/redis.conf 

 <omitted>

# More details please check the following article:
# http://antirez.com/post/redis-persistence-demystified.html
#
# If unsure, use "everysec".

# appendfsync always
appendfsync everysec
# appendfsync no

 <omitted>

設定値 意味
always コマンドが発行される都度、ディスクに書き込む
everysec 1秒に1回、ディスクに書き込む
no ディスクに書き込む頻度はOS設定に任せる(多くの場合は30秒に1回)

/etc/redis.confのappendonlyをyesに変更した後、redis-serverを再起動して設定を反映します。

systemctl restart redis.service

再起動後、appendonly.aofというファイルが作成されている事が読み取れます。

[root@linux010 ~]# ls -l /var/lib/redis/
total 184
-rw-r--r--. 1 redis redis      0 Nov 23 12:16 appendonly.aof
-rw-r--r--. 1 redis redis 187899 Nov 23 12:16 dump.rdb
[root@linux010 ~]# 

appendonly.aofは簡単なテキストファイルのフォーマットですので、catコマンドなどで中身を確認する事もできます。

[root@linux010 ~]# redis-cli SET key0 value0
OK
[root@linux010 ~]# ls -l /var/lib/redis/
total 188
-rw-r--r--. 1 redis redis     58 Nov 23 12:19 appendonly.aof
-rw-r--r--. 1 redis redis 187899 Nov 23 12:16 dump.rdb
[root@linux010 ~]# cat /var/lib/redis/appendonly.aof 
*2
$6
SELECT
$1
0
*3
$3
SET
$4
key0
$6
value0
[root@linux010 ~]# 

AOFの破損チェック

redisにはAOFの破損チェックと破損修復の機能を備えています。

以下のようにredis-check-aofコマンドの引数にAOFファイルを与えると、AOFがvalid(破損していないか)をチェックする事ができます。

[root@linux010 ~]# redis-check-aof /var/lib/redis/appendonly.aof 
AOF analyzed: size=58, ok_up_to=58, diff=0
AOF is valid
[root@linux010 ~]# 

それではAOFのファイル破損のシナリオも試してみましょう。AOFファイルで「key0」を含む行を削除します。

systemctl stop redis.service
sed -i '/key0/d' /var/lib/redis/appendonly.aof 

AOFファイルが破損している状態で、redis-serverを起動します。すると、AOFファイルが破損している旨のログが出力されます。

[root@linux010 ~]# systemctl start redis.service 
[root@linux010 ~]# tail -f /var/log/redis/redis.log 
  `-._    `-._`-.__.-'_.-'    _.-'                                   
      `-._    `-.__.-'    _.-'                                       
          `-._        _.-'                                           
              `-.__.-'                                               

30914:M 23 Nov 2022 12:42:48.862 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
30914:M 23 Nov 2022 12:42:48.862 # Server initialized
30914:M 23 Nov 2022 12:42:48.862 # WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.
30914:M 23 Nov 2022 12:42:48.862 # WARNING you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and memory usage issues with Redis. To fix this issue run the command 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' as root, and add it to your /etc/rc.local in order to retain the setting after a reboot. Redis must be restarted after THP is disabled.
30914:M 23 Nov 2022 12:42:48.862 # Bad file format reading the append only file: make a backup of your AOF file, then use ./redis-check-aof --fix <filename>

redis-check-aofコマンドを使用すると、AOFファイルが破損している事が確認できます。

[root@linux010 ~]# systemctl stop redis.service
[root@linux010 ~]# redis-check-aof /var/lib/redis/appendonly.aof
0x              28: Expected \r\n, got: 7661
AOF analyzed: size=52, ok_up_to=23, diff=29
AOF is not valid. Use the --fix option to try fixing it.
[root@linux010 ~]# 

破損を修復するには、redis-check-aofコマンドに--fixオプションを付与します。

[root@linux010 ~]# redis-check-aof --fix /var/lib/redis/appendonly.aof
0x              28: Expected \r\n, got: 7661
AOF analyzed: size=52, ok_up_to=23, diff=29
This will shrink the AOF from 52 bytes, with 29 bytes, to 23 bytes
Continue? [y/N]: y
Successfully truncated AOF
[root@linux010 ~]# redis-check-aof /var/lib/redis/appendonly.aof
AOF analyzed: size=23, ok_up_to=23, diff=0
AOF is valid
[root@linux010 ~]# 

バックアップ操作

SAVE

/etc/redis.confに定義したsave設定でバックアップ頻度を定義する事ができます。しかし、任意のタイミングでバックアップを取得したい時もあるでしょう。このような場合はSAVEコマンドを使用します。

[root@linux010 ~]# redis-cli
127.0.0.1:6379> save
OK
127.0.0.1:6379> exit
[root@linux010 ~]# 

SAVEコマンド実行後、dump.rdbのタイムスタンプが更新されている事がわかります。

[root@linux010 ~]# ls -l /var/lib/redis/
total 8
-rw-r--r--. 1 redis redis  58 Nov 23 12:19 appendonly.aof
-rw-r--r--. 1 redis redis 110 Nov 23 12:22 dump.rdb
[root@linux010 ~]#

あとは、dump.rdbを適当なバックアップサーバへ転送すればデータを保全できます。

scp /var/lib/redis/dump.rdb <バックアップサーバURL>

BGSAVE

前述のSAVEコマンドは、保存が完了するまでRedisクライアントからの読み書きの処理を止めてしまいます。これでは本番稼働中にバックアップを取得する事はできません。

このような問題に対応するのがBGSAVEコマンドです。BGSAVEはRedisクライアントからの読み書きを継続しつつバックアップを実現します。

[root@linux010 ~]# redis-cli 
127.0.0.1:6379> BGSAVE
Background saving started
127.0.0.1:6379> exit
[root@linux010 ~]# 

BGSAVEコマンドはバックグランドでバックアップを取得しますので、バックアップが完了したかどうかはタイムスタンプで判断します。

[root@linux010 ~]# ls -l /var/lib/redis/
total 8
-rw-r--r--. 1 redis redis 23 Nov 23 21:45 appendonly.aof
-rw-r--r--. 1 redis redis 92 Nov 23 22:29 dump.rdb
[root@linux010 ~]# 

LASTSAVEコマンドからもバックアップ完了を判断できます。LASTSAVEは最後のバックアップが完了した時刻を返しますので、LASTSAVEの時刻が更新されていればバックアップが完了したと判断できます。なお、LASTSAVEはエポックタイムで返されますので、適宜、時刻を変換ください。

[root@linux010 ~]# redis-cli 
127.0.0.1:6379> LASTSAVE
(integer) 1669210184
127.0.0.1:6379> exit
[root@linux010 ~]# date --date @1669210184 +"%Y/%m/%d %H:%M:%S"
2022/11/23 22:29:44
[root@linux010 ~]# 
タイトルとURLをコピーしました