1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

期限切れのRedisデータを復元してテストしたい

Last updated at Posted at 2016-07-05

昔に取得した、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自体の機能として期限切れデータを復元する方法はなかった。

回避策

  1. システムの時刻をバックアップ取得した時刻まで戻してリストアする。
  2. 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

おわり

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?