【Azure Developer】一个复制Redis Key到另一个Redis服务的工具(redis_copy_net8)

简介: 【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

 

相关文章
|
11月前
|
缓存 NoSQL Java
Redis应用—6.热key探测设计与实践
热key问题在高并发系统中可能导致数据层和服务层的严重瓶颈,如Redis集群瘫痪和用户体验下降。为解决此问题,京东开发了JdHotkey热key探测框架,具备实时性、准确性、集群一致性和高性能等特点。该框架由etcd集群、Client端jar包、Worker端集群和Dashboard控制台组成,通过分布式计算快速识别热key并推送至应用内存,有效减轻数据层负载,提升服务性能。JdHotkey适用于多种场景,安装部署简便,支持毫秒级热key探测和集群一致性维护。
556 61
Redis应用—6.热key探测设计与实践
|
8月前
|
NoSQL 测试技术 Redis
Redis批量删除Key的三种方式
Redis批量删除Key是优化数据库性能的重要操作,本文介绍三种高效方法:1) 使用通配符匹配(KEYS/SCAN+DEL),适合不同数据规模;2) Lua脚本实现原子化删除,适用于需要事务保障的场景;3) 管道批量处理提升效率。根据实际需求选择合适方案,注意操作不可逆,建议先备份数据,避免内存溢出或阻塞。
|
10月前
|
云安全 NoSQL 安全
【Azure Redis】关于Redis的两个安全漏洞在Azure Redis是否修复问题:CVE-2024-51741 和 CVE-2024-46981
本文探讨了两个 Redis 漏洞(CVE-2024-51741 和 CVE-2024-46981)在 Azure Redis 上是否存在安全风险。CVE-2024-51741 可能因格式错误的 ACL 触发拒绝服务,而 CVE-2024-46981 或因恶意 Lua 脚本导致远程代码执行。目前 Azure Redis 使用版本 6.0,不受上述漏洞影响,且 Azure 云服务会及时修复漏洞以确保安全。文章强调 Azure 遵循严格的安全标准,为用户提供可靠保障。
385 4
|
开发框架 安全 .NET
【Azure Developer】.NET Aspire 项目本地调试遇 Grpc.Core.RpcException 异常( Error starting gRPC call ... )
Error starting gRPC call. HttpRequestException: The SSL connection could not be established, see inner exception. AuthenticationException: The remote certificate is invalid because of errors in the certificate chain: UntrustedRoot
381 12
|
NoSQL API Redis
在C程序中实现类似Redis的SCAN机制的LevelDB大规模key分批扫描
通过上述步骤,可以在C程序中实现类似Redis的SCAN机制的LevelDB大规模key分批扫描。利用LevelDB的迭代器,可以高效地遍历和处理数据库中的大量键值对。该实现方法不仅简单易懂,还具有良好的性能和扩展性,希望能为您的开发工作提供实用的指导和帮助。
221 7
|
监控 NoSQL 网络协议
【Azure Redis】部署在AKS中的应用,连接Redis高频率出现timeout问题
查看Redis状态,没有任何异常,服务没有更新,Service Load, CPU, Memory, Connect等指标均正常。在排除Redis端问题后,转向了AKS中。 开始调查AKS的网络状态。最终发现每次Redis客户端出现超时问题时,几乎都对应了AKS NAT Gateway的更新事件,而Redis服务端没有任何异常。因此,超时问题很可能是由于NAT Gateway更新事件导致TCP连接被重置。
302 7
|
存储 监控 NoSQL
Redis大Key问题如何排查?如何解决?
Redis大Key问题如何排查?如何解决?
650 0
Redis大Key问题如何排查?如何解决?
|
存储 NoSQL 算法
面试官:Redis 大 key 多 key,你要怎么拆分?
本文介绍了在Redis中处理大key和多key的几种策略,包括将大value拆分成多个key-value对、对包含大量元素的数据结构进行分桶处理、通过Hash结构减少key数量,以及如何合理拆分大Bitmap或布隆过滤器以提高效率和减少内存占用。这些方法有助于优化Redis性能,特别是在数据量庞大的场景下。
面试官:Redis 大 key 多 key,你要怎么拆分?
|
9月前
|
缓存 NoSQL 关系型数据库
美团面试:MySQL有1000w数据,redis只存20w的数据,如何做 缓存 设计?
美团面试:MySQL有1000w数据,redis只存20w的数据,如何做 缓存 设计?
美团面试:MySQL有1000w数据,redis只存20w的数据,如何做 缓存 设计?