【Azure Developer】一个复制Redis Key到另一个Redis服务的工具(redis_copy_net8)
介绍一个简单的工具,用于将Redis数据从一个redis端点复制到另一个redis端点,基于原始存储库转换为.NET 8:https://github.com/LuBu0505/redis-copy-net8

Redis Copy .NET8
Redis Copy 控制台工具允许将 Redis 数据从一个 Redis 服务端复制到另一个。

Note: 不支持redis集群
软件要求
运行 Redis Copy 工具需要以下软件。它可能会在其他版本上运行.
- .NET 8
- VS Code / Visual Studio 2022
下载源代码
clone https://github.com/LuBu0505/redis-copy-net8.git
使用方式
选项 1 -- 使用 AppSetting.json
将“< ... >”替换为真实的redis端点
{
"SourceRedisConnectionString": "<source redis name>:6380,password=<your password>,ssl=True,abortConnect=False", //Source Redis ConnectionString
"DestRedisConnectionString": "<Destination redis name>:6380,password=<your password>,ssl=True,abortConnect=False" //Destination Redis ConnectionString
}

选项 2 -- 使用命令参数
redis-copy-net8.exe
Parameter Description:
--se Required. SourceEndpoint *.redis.cache.windows.net
--sa Required. Source password
--sp (Default: 6380) Source port
--sssl (Default: true) Connect Source over ssl --de Required. DestinationEndpoint *.redis.cache.windows.net
--da Required. Destination Password
--dp (Default: 6380) Destination port
--dssl (Default: true) Destination Source over ssl
--help Display this help screen.
--version Display version information. eg: redis-copy-net8.exe --se <xxxxxx.redis.cache.chinacloudapi.cn> --sa <******************> --de <xxxxxx.redis.cache.chinacloudapi.cn> --da <******************>

Redis Copy 工具的工作流程
第 1 阶段:准备Redis源和目标信息
- 使用 StackExchange.Redis ConnectionMultiplexer 类,默认创建20个连接。
- 检查源redis的Used Memory、Keyspace信息
- 根据Keys数量拆分成更多子任务
var infoGroup = sourcecon.BasicRetryInfo((conn) => conn.GetServer(conn.GetEndPoints()[0]).Info());
foreach (var info in infoGroup)
{
if (info.Key.Equals("Memory"))
{
Console.WriteLine($"==\t# {info.Key}");
var lists = info.ToList().Where(i => i.Key.Equals("used_memory_human") || i.Key.Equals("maxmemory_human")).ToList();
foreach (var list in lists)
Console.WriteLine($"==\t {list.ToString()}");
}
if (info.Key.Equals("Keyspace"))
{
Console.WriteLine($"==\t# {info.Key}");
foreach (var list in info.ToList())
{
long dbindex, dbkeys = 0;
long.TryParse(Regex.Match(list.Key, @"\d+\.*\d*").Value, out dbindex);
long.TryParse(list.Value.Split(new char[] { ',' })[0].Split(new char[] { '=' })[1], out dbkeys);
dictdbIdxKeysNum[dbindex] = dbkeys;
totalKeysSource += dbkeys;
Console.WriteLine($"==\t {list.ToString()}");
}
}
}

第二阶段:复制
- 循环执行复制Redis Keys的子任务,SCAN列出所有Keys。
- 创建更多子任务以使用 StackExchange.Redis bacth 操作进行 TTL,验证Key是否过期,DUMP出Key的byte[]信息
- 使用批量操作将Key恢复到目标Redis
- 如果遇到异常,则将Key信息添加到失败队列中。
- 检查移动的keys的进度,同时检查失败的队列,如果不为空,将重新运行移动任务
var allkeys = sourcecon.BasicRetryInfo((conn) => conn.GetServer(conn.GetEndPoints()[0]).Keys(dbindex).Skip(skipKeys).Take(takeKeys)).ToArray();
var sourcedb = sourcecon.GetConection().GetDatabase(dbindex);
var destdb = destcon.GetConection().GetDatabase(dbindex); foreach (var keys in SplitKeys(allkeys))
{
var rbatch = sourcedb.CreateBatch();
var ttltask = new List<Task<TimeSpan?>>();
var dumptask = new List<Task<byte[]?>>();
foreach (var key in keys)
{
ttltask.Add(rbatch.KeyTimeToLiveAsync(key)); dumptask.Add(rbatch.KeyDumpAsync(key));
}
rbatch.Execute(); var ttlResults = Task.WhenAll(ttltask).Result;
var dumpkResults = Task.WhenAll(dumptask).Result; //Restore the key to destation DB.
var destBatch = destdb.CreateBatch(); var i = 0;
foreach (var key in keys)
{
destBatch.KeyRestoreAsync(key, dumpkResults[i], ttlResults[i]);
i++;
}
destBatch.Execute(); //Random select one key to verify in Phase 3.
if (keys.Count() > 0)
{
int index = RandomNumberGenerator.GetInt32(keys.Count());
verifiedKeys.Add((dbindex, keys.ElementAt<RedisKey>(index).ToString()));
} lock (lockObject)
{
totalKeysCopied += keys.Count();
}
}
第三阶段:验证
- 随机选取某个key, 一个一个的检查他们的值在两个Redis服务器之间是否相同
foreach (var key in verifiedKeys)
{
try
{
var sourdump = await sourcecon.BasicRetryInfo(async (sc) => sc.GetDatabase(key.Item1).KeyDumpAsync(key.Item2));
var destdump = await destcon.BasicRetryInfo(async (sc) => sc.GetDatabase(key.Item1).KeyDumpAsync(key.Item2)); if (!sourdump.Result.SequenceEqual(destdump.Result))
{
Console.Write($"\n");
Console.WriteLine($"== {key} Verify Failed");
}
else
{
Console.Write($"{key}, ");
}
}
catch (Exception ex)
{
Console.BackgroundColor = ConsoleColor.Red;
Console.WriteLine($"=={DateTime.Now.ToLocalTime()} Verify {key} failed ({ex.Message})");
Console.BackgroundColor = ConsoleColor.Black;
}
}
测试结果
Copied 369886 keys(812MB) from Redis1 to Redis2 in 233 seconds
【Azure Developer】一个复制Redis Key到另一个Redis服务的工具(redis_copy_net8)的更多相关文章
- Spring boot实现监听Redis key失效事件实现和其它方式
需求: 处理订单过期自动取消,比如下单30分钟未支付自动更改订单状态 用户绑定隐私号码当订单结束取消绑定等 解决方案1: 可以利用redis自带的key自动过期机制,下单时将订单id写入redis,过 ...
- Redis Key过期事件
解决方案1: 可以利用redis天然的key自动过期机制,下单时将订单id写入redis,过期时间30分钟,30分钟后检查订单状态,如果未支付,则进行处理但是key过期了redis有通知吗?答案是肯定 ...
- 利用python脚本统计和删除redis key
该脚本扫描redis中所有的key,用于分析redis内存数据的key构成,扫描并保存文件,需要python支持redis模块. #!/usr/bin/env python # -*- coding: ...
- SpringBoot实现监听redis key失效事件
需求: 处理订单过期自动取消,比如下单30分钟未支付自动更改订单状态 解决方案1: 可以利用redis天然的key自动过期机制,下单时将订单id写入redis,过期时间30分钟,30分钟后检查订单状态 ...
- 【Azure Developer】Python代码通过AAD认证访问微软Azure密钥保管库(Azure Key Vault)中机密信息(Secret)
关键字说明 什么是 Azure Active Directory?Azure Active Directory(Azure AD, AAD) 是 Microsoft 的基于云的标识和访问管理服务,可帮 ...
- 【Azure Developer】解决Azure Key Vault管理Storage的示例代码在中国区Azure遇见的各种认证/授权问题 - C# Example Code
问题描述 使用Azure密钥保管库(Key Vault)来托管存储账号(Storage Account)密钥的示例中,从Github中下载的示例代码在中国区Azure运行时候会遇见各种认证和授权问题, ...
- 【Azure Developer】记录一次使用Java Azure Key Vault Secret示例代码生成的Jar包,单独运行出现 no main manifest attribute, in target/demo-1.0-SNAPSHOT.jar 错误消息
问题描述 创建一个Java Console程序,用于使用Azure Key Vault Secret.在VS Code中能正常Debug,但是通过mvn clean package打包为jar文件后, ...
- 分享一个Python脚本--统计redis key类型数据大小分布
概述 今天主要介绍怎么统计redis key类型数据大小分布. 原理:使用redis命令: scan.pipline.type 和 debug object 来得到 redis key 信息. 脚本 ...
- 【Azure Developer】使用Microsoft Graph API 批量创建用户,先后遇见的三个错误及解决办法
问题描述 在先前的一篇博文中,介绍了如何使用Microsoft Graph API来创建Azure AD用户(博文参考:[Azure Developer]使用Microsoft Graph API 如 ...
- Redis Key 命令
Redis Key 命令 del key1 key2 - keyn 删除键为key1,key2-keyn,空格分隔. persist key 移除给定 key 的生存时间,将这个 key ...
随机推荐
- Unity Visual Scripting 使用随记
1.Wait Until并不会再执行前面的代码,而是反复执行获取bool变量的代码:需自己拆出来写. 2.yield return null对应Wait For Next Frame,多用这个避免协程 ...
- 基于 OAI 部署私有的 4G EPS
目录 文章目录 目录 前言 硬件设备要求 运行平台 RF 外设 可编程 SIM 卡 UE 终端 高精度参考时钟 操作系统要求 内核要求 CPU Frequency scaling All-In-One ...
- windows 文件夹添加备注
1,选中希望改动的文件夹,然后右键"单击",选择"属性"按钮. 2,打开"自定义"面板,选择"更改图标",将原来的默认文 ...
- VisualStduio如何自定义代码片段
什么是代码片段 代码片段又叫CodeSnippet,可以用来快捷补全代码.其实我们经常使用这个功能. 比如for循环,输入for会弹出这个窗口 我们选择第二个for,再按两次Tab键,编辑器就会自动生 ...
- Java RMI遇到的Connection refused to Host: 127.x.x.x/192.x.x.x/10.x.x.x问题解决方法
问题故障解决记录 -- Java RMI Connection refused to host: x.x.x.x .... 在学习JavaRMI时,我遇到了以下情况 问题原因:可能大家的host是10 ...
- 将大量文件的拓展名中大写字母改为小写:Python实现
本文介绍基于Python语言,基于一个大文件夹,遍历其中的多个子文件夹,对于每一个子文件夹中的大量文件,批量将其文件的名称或后缀名中的字母由大写修改为小写的方法. 本文期望实现的需求为:现有一 ...
- 使用Harbor作为Rainbond默认容器镜像仓库,扩展Rainbond镜像管理能力
Rainbond是一体化的云原生应用管理平台,它提供"以应用为中心"的抽象,使用者不需要学习K8s和容器,平台将K8s和容器封装在内部,这种封装方式能极大提高使用的易用性和安装的便 ...
- MySQL配置主从同步过程记录
今天由于工作需要,配置了一下主从同步,这里记录一下配置过程,以备查阅. 事先度娘了一番,主从同步需要保证主从服务器MySQL版本一致(我的略有差别,主服务器版本5.5.31,从服务器版本5.5.19) ...
- MYSQL 移机重装步骤(windows11)
MYSQL 移机重装步骤(windows11) 目的:已有电脑 A,D盘安装有mysql(安装方式为免安装) , 准备在另一台电脑B上,复制安装电脑A上的mysql(8.0.23版本) . 要 ...
- Vue第三方库与插件实战手册
title: Vue第三方库与插件实战手册 date: 2024/6/8 updated: 2024/6/8 excerpt: 这篇文章介绍了如何在Vue框架中实现数据的高效验证与处理,以及如何集成E ...