python实现redis rdb迁移

文章介绍了在尝试多种Redis迁移工具未果后,采用Python编程结合rdb-tools库自编了一个简单的Redis数据迁移脚本。脚本实现了从源Redis实例到目标Redis实例的数据迁移,支持指定数据库和过滤条件。主要涉及Redis连接、RdbParser和自定义回调函数来处理不同类型的Redis数据结构。
部署运行你感兴趣的模型镜像

前言

找了一圈redis迁移工具,包括:redis-port、redis-shake、redis-dump等等,涉及到各种语言和环境,折腾了半天没有成功。。最后还是自己写吧。

利用https://github.com/sripathikrishnan/redis-rdb-tools这个强大的python库简单写一个适用于单机的redis迁移脚本。

python脚本

import datetime
from typing import Dict, Optional, List

import redis
from loguru import logger
from rdbtools import RdbParser, RdbCallback
from rdbtools.encodehelpers import bytes_to_unicode, STRING_ESCAPE_UTF8


class RedisMigrator:
    """redis迁移"""
    def __init__(self, rdb_file: str, redis_config: Dict, source_dbs: Optional[List[int]] = None):
        self.rdb_file = rdb_file
        self.redis_config = redis_config
        self.source_dbs = source_dbs
        self.redis_client = self.init_redis()

    def init_redis(self):
        """初始化redis客户端"""
        redis_pool = redis.ConnectionPool(**self.redis_config)
        redis_client = redis.Redis(connection_pool=redis_pool)
        return redis_client

    def migrate(self):
        """
        迁移
        filters参数支持多种条件过滤
        {"dbs" : [0, 1], "keys" : "foo.*", "types" : ["hash", "set", "sortedset", "list", "string"]}
        """
        callback = MyCallback(redis_client=self.redis_client)
        filters = None
        if self.source_dbs:
            filters = {"dbs": self.source_dbs}
        parser = RdbParser(callback, filters=filters)
        parser.parse(self.rdb_file)


class MyCallback(RdbCallback):
    """回调"""
    def __init__(self, redis_client):
        super(MyCallback, self).__init__(string_escape=STRING_ESCAPE_UTF8)
        self.redis_client = redis_client

    def encode_key(self, key):
        return bytes_to_unicode(key, self._escape, skip_printable=True)

    def encode_value(self, val):
        return bytes_to_unicode(val, self._escape)

    def set(self, key, value, expiry, info):
        logger.info("set")
        key = self.encode_key(key)
        value = self.encode_value(value)
        if expiry:
            now = datetime.datetime.now()
            # 计算距离当前时间的秒数
            expiry = int((expiry - now).total_seconds())
        logger.info("{} {} {}".format(key, value, expiry))

        if not expiry:
            self.redis_client.set(key, value)
        elif expiry > 0:
            self.redis_client.setex(key, expiry, value)

    def hset(self, key, field, value):
        logger.info("hset")
        key = self.encode_key(key)
        value = self.encode_value(value)
        field = self.encode_value(field)
        logger.info("{} {}".format(key, value))

        self.redis_client.hset(key, field, value)

    def rpush(self, key, value):
        logger.info("rpush")
        key = self.encode_key(key)
        value = self.encode_value(value)
        logger.info("{} {}".format(key, value))

        self.redis_client.rpush(key, value)

    def zadd(self, key, score, member):
        logger.info("zadd")
        key = self.encode_key(key)
        score = self.encode_value(score)
        member = self.encode_value(member)
        logger.info("{} {} {}".format(key, score, member))

        self.redis_client.zadd(key, {member: score})

    def sadd(self, key, member):
        logger.info("sadd")
        key = self.encode_key(key)
        value = self.encode_value(member)
        logger.info("{} {}".format(key, value))

        self.redis_client.sadd(key, value)

    def start_database(self, db_number):
        logger.info("Starting database {}".format(db_number))

    def end_database(self, db_number):
        logger.info("End database {}".format(db_number))

if __name__ == '__main__':
    # 目标redis配置
    target_redis_config = {
        "host": "127.0.0.1",
        "port": 6379,
        "db": 13,
        "password": "123456"
    }
    # 要迁移的rdb文件
    _rdb_file = r'./dump.rdb'
    # 要迁移的数据库列表,不传代表全部0-15
    _source_dbs = [13]

    migrator = RedisMigrator(rdb_file=_rdb_file, redis_config=target_redis_config, source_dbs=_source_dbs)
    migrator.migrate()

您可能感兴趣的与本文相关的镜像

Python3.8

Python3.8

Conda
Python

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

<think>嗯,用户现在想了解如何恢复RedisRDB和AOF备份文件。他们之前已经问过关于内存碎片的问题,现在转向数据恢复。我需要结合之前提供的引用来整理步骤,同时确保回答结构清晰,符合用户的要求。 首先,用户提到的引用里提到了RDB和AOF的基本概念,以及恢复优先级。根据引用[2],正确的恢复步骤是先关闭AOF,用RDB恢复,再开启AOF。这可能是一个关键点。我需要详细说明这个过程,确保用户能理解每个步骤的目的,比如为什么需要先关闭AOF,避免生成空文件覆盖现有数据。 接下来,用户可能需要具体的操作步骤,包括命令和配置。比如如何停止Redis,如何备份现有文件,如何拷贝RDB或AOF文件到指定目录。这些都需要明确的命令行示例,方便用户直接使用。同时,要注意权限问题,确保用户知道需要检查文件权限和路径是否正确。 另外,用户的问题可能涉及到两种备份文件的恢复情况:只有RDB、只有AOF,或者两者都有。需要分别说明每种情况的处理方式。比如,当同时存在RDB和AOF时,Redis会优先使用AOF,但根据引用[2],恢复时可能需要先禁用AOF,使用RDB恢复后再重新生成AOF。 还有,用户可能关心恢复后的验证步骤,如何确认数据是否成功恢复。比如使用redis-cli的KEYS命令或者检查数据条数。这部分需要给出具体的命令示例,帮助用户进行验证。 此外,注意事项也很重要。比如恢复过程中需要停止Redis服务,避免数据写入冲突;文件权限和路径的正确配置;以及性能影响,比如AOF重写可能消耗资源,需要在低峰期操作。这些都需要在回答中提醒用户,避免他们遇到问题。 最后,用户可能还想知道如何备份RDB和AOF文件,作为恢复的前提。因此,在回答中加入备份的方法也是有必要的,比如使用SAVE命令或配置自动备份策略。 需要确保回答结构清晰,分步骤讲解,每个步骤都有对应的命令和解释。同时,使用代码块和列表来增强可读性。还要注意引用之前的资料,比如引用[2]中的恢复步骤,引用[3]中的配置示例,确保信息的准确性。 可能还需要补充一些常见问题,比如恢复失败的可能原因,如何处理损坏的备份文件,以及如何监控恢复过程。这些虽然不是用户直接问的,但能帮助他们更全面地理解和解决问题。 总之,我需要将恢复过程拆解成详细的步骤,覆盖不同情况(RDB、AOF、混合使用),并提供验证和注意事项,确保用户能够安全有效地完成备份恢复。</think>### Redis RDB/AOF 备份恢复完整指南 --- #### 一、核心恢复原则 1. **恢复优先级** Redis启动时默认优先加载AOF文件(若存在)[^2],恢复流程需遵循: $$恢复优先级 = \begin{cases} \text{AOF文件存在} & \rightarrow \text{优先使用AOF} \\ \text{仅RDB文件存在} & \rightarrow \text{使用RDB} \end{cases}$$ 2. **文件定位规则** ```bash # 默认存储路径(通过redis.conf确认) RDB文件:/var/lib/redis/dump.rdb AOF文件:/var/lib/redis/appendonly.aof ``` --- #### 二、分场景恢复操作 ##### 场景1:仅恢复RDB备份 1. **操作步骤** ```bash # 停止Redis服务(防止数据写入冲突) systemctl stop redis # 备份当前数据文件(重要!) cp /var/lib/redis/dump.rdb /backup/dump.rdb.$(date +%F) # 替换RDB文件 cp /path/to/your_backup.rdb /var/lib/redis/dump.rdb # 修改文件权限 chown redis:redis /var/lib/redis/dump.rdb chmod 660 /var/lib/redis/dump.rdb # 启动服务 systemctl start redis ``` 2. **验证方法** ```bash redis-cli dbsize # 检查数据总量 redis-cli KEYS "*" | wc -l # 统计键数量 ``` ##### 场景2:仅恢复AOF备份 ```bash # 停止服务 systemctl stop redis # 关闭RDB持久化(防止干扰) sed -i 's/^save /# save /g' /etc/redis.conf # 替换AOF文件 cp /path/to/your_backup.aof /var/lib/redis/appendonly.aof # 修复AOF文件(重要!) redis-check-aof --fix /var/lib/redis/appendonly.aof # 修改权限 chown redis:redis /var/lib/redis/appendonly.aof chmod 660 /var/lib/redis/appendonly.aof # 强制启用AOF模式启动 redis-server /etc/redis.conf --appendonly yes ``` ##### 场景3:混合恢复(RDB+AOF) ```bash # 停止服务 systemctl stop redis # 关键配置调整(redis.conf) appendonly no # 先禁用AOF dbfilename dump.rdb # 确认RDB文件名 # 替换文件 cp backup.rdb /var/lib/redis/dump.rdb cp backup.aof /var/lib/redis/appendonly.aof # 分阶段启动(引用[2]推荐流程) redis-server /etc/redis.conf # 先用RDB启动 redis-cli CONFIG SET appendonly yes # 热开启AOF redis-cli BGREWRITEAOF # 触发AOF重写 ``` --- #### 三、生产环境最佳实践 1. **备份策略建议** ```mermaid graph LR A[每日0点RDB快照] --> B[每小时AOF增量] B --> C[备份到S3/OSS] C --> D[异地容灾存储] ``` 2. **自动化恢复验证脚本** ```python #!/usr/bin/env python3 import redis r = redis.Redis(host='localhost') if r.dbsize() > 1000 and r.info('persistence')['aof_enabled'] == 1: print("[SUCCESS] 恢复验证通过") else: print("[ERROR] 恢复异常,检查备份文件完整性") ``` --- #### 四、故障排查手册 | 故障现象 | 解决方案 | 相关命令 | |---------|----------|----------| | AOF文件损坏 | 使用redis-check-aof修复 | `redis-check-aof --fix appendonly.aof` | | RDB版本不兼容 | 使用相同Redis版本恢复 | `redis-server -v` 核对版本 | | 磁盘空间不足 | 清理日志文件或扩容 | `df -h /var/lib/redis` | --- #### 五、关键注意事项 1. **文件权限陷阱** - Redis用户必须对数据目录有读写权限 - SELinux环境需执行: ```bash chcon -R -t redis_var_lib_t /var/lib/redis/ ``` 2. **云数据库特殊要求** - 阿里云/腾讯云等需通过控制台恢复备份 - 禁止直接替换文件(会导致监控异常)[^3] 3. **性能影响预警** - AOF恢复期间可能产生高IO负载 - 建议在业务低峰期操作 --- ### 扩展阅读 1. [Redis官方数据恢复指南](https://redis.io/docs/management/persistence/) 2. 使用`redis-rdb-tools`分析RDB文件内容: ```bash rdb -c memory dump.rdb --bytes 1024 --type string > analysis.csv ``` --- ### 相关问题 1. 如何验证AOF文件的完整性? 2. Redis Cluster模式下备份恢复有什么不同? 3. 为什么AOF文件恢复后体积会突然增大? 4. 如何实现Redis版本的数据迁移? [^2]: 混合恢复需遵循先RDB后AOF的流程 [^3]: 云数据库需通过控制台操作保证服务稳定性
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值