昔に取得した、redisのrdbファイルを復元してテストしたい
redis conf の設定 (抜粋)
dbfilename dump.rdb
dir /usr/local/var/db/redis/
普通にリストアすると
# バックアップ
mv /usr/local/var/db/redis/dump.rdb /usr/local/var/db/redis/dump.rdb.bk
# 前に取得したrdbファイルをコピーして上書き。
cp -i /path/to/backup/rdb/dump.rdb /usr/local/var/db/redis/
# Redis起動
redis-server /path/to/conf/redis.conf
結果
期限切れのデータはデータロード時に削除されてしまう。。。。
いろいろ調べたがRedis自体の機能として期限切れデータを復元する方法はなかった。
回避策
- システムの時刻をバックアップ取得した時刻まで戻してリストアする。
- rdb ファイルを 読み込んで json に変換してまた入れる。
1.システムの時刻をバックアップ取得した時刻まで戻してリストアする。
システム時刻を変更してから、普通にリストアする。
リストア自体はうまくいくが、時刻の設定変えると他のアプリに影響でそうなので不採用。
2. rdb ファイルを 読み込んで json に変換してまた入れる。
以下のツールを使う。
https://github.com/sripathikrishnan/redis-rdb-tools
Install
pip install rdb-tools
JSONに変換
rdb-tools にバグ?があり。-f を指定するとfilter条件が無効化されるため
-f を指定せずに、リダイレクトする。
(https://github.com/sripathikrishnan/redis-rdb-tools/blob/master/rdbtools/cli/rdb.py#L66)
# 全体で取得した結果にDB番号が入ってないのでDBを指定して出力。
rdb --command json --db 1 /path/to/backup/rdb/dump.rdb > /path/to/output/dump.json
これは全部出力されてしまう。
# 全体で取得した結果にDB番号が入ってない(はず。。)、なのでDBを指定して出力。
rdb --command json --db 1 -f /path/to/output/dump.json /path/to/backup/rdb/dump.rdb
Redisにインポート
する機能はrdb-toolsにはないので、自前で書く。
load_rdb_json.py
#!/usr/bin/python
import json
import redis
import argparse
class Callbacks(object):
@staticmethod
def zaddCallback(key, values, client):
for value, score in values.items():
client.zadd(key, value, score)
@staticmethod
def saddCallback(key, values, client):
print "Key:{0}, Values:{1}".format(key, values)
client.sadd(key, values)
class RedisRdbJsonLoader(object):
def __init__(self, host, port, callback, timeout_sec=5):
self.host = host
self.port = port
self.callback = callback
self.timeout_sec = timeout_sec
def load(self, rdb_json_file, given_db_num=None):
rdb_json = json.load(rdb_json_file)
if given_db_num is None:
self.__load_to_each_db(rdb_json)
else:
self.__load_to_db(given_db_num, rdb_json[given_db_num])
def __load_to_each_db(self, rdb_json):
# rdb_json_file includes data in order of db num.
for db_num, db_values in enumerate(rdb_json):
self.__load_to_db(db_num, db_values)
def __load_to_db(self, db_num, db_values):
print "===================="
print "Load value for db {0}".format(db_num)
client = self.__get_redis_client(db_num)
count = 0
for key, values in db_values.items():
self.callback(key, values, client)
count += 1
print "{0}:Value loaded for key {1}".format(count, key)
def __get_redis_client(self, db_num):
return redis.Redis(self.host, self.port, db_num, socket_timeout=self.timeout_sec)
__TYPE_ACTION_MAPPING = {
# 'string': setCallback,
# 'list': lpushCallback,
'set': Callbacks.saddCallback,
'zset': Callbacks.zaddCallback,
# 'hash': hsetCallback
}
def get_parser():
parser = argparse.ArgumentParser(description='Load Jsonized rdis *.rdb file into redis server.')
parser.add_argument('-H', '--host', help="Hostname of Redis server.", default='localhost')
parser.add_argument('-p', '--port', help="Port number of Redis server.", default=6379, type=int)
parser.add_argument('-n', '--db_num', help="Target DB of Redis server to load data. if this value was given, only first element of json data will be used.", default=None, type=int)
parser.add_argument('-f', '--data_file', help="Path to data file.", required=True, type=argparse.FileType('r'))
parser.add_argument('-t', '--data_type', help="Redis type to load.", default='zset', choices=__TYPE_ACTION_MAPPING.keys())
parser.add_argument('--timeout_sec', help="Redis timeout sec.", default=5, type=int)
return parser
def execute(args):
with args.data_file as file:
callback = __TYPE_ACTION_MAPPING[args.data_type]
RedisRdbJsonLoader(args.host, args.port, callback, args.timeout_sec).load(file, args.db_num)
if __name__ == '__main__':
execute(get_parser().parse_args())
インポートの実行
特定DBにのみインポートする場合
python load_rdb_json.py -n 1 -f /path/to/output/dump.json
全部インポートする場合
python load_rdb_json.py -f /path/to/output/dump.json