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

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
简介: 【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

 

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
2月前
|
Shell 网络安全 C#
一款 .NET 开源、功能强大的远程连接管理工具,支持 RDP、VNC、SSH 等多种主流协议!
一款 .NET 开源、功能强大的远程连接管理工具,支持 RDP、VNC、SSH 等多种主流协议!
|
18天前
|
缓存 开发框架 .NET
一个功能丰富的 .NET 工具库 XiHan.Framework.Utils
XiHan.Framework.Utils 是一个功能全面的 .NET 工具库,包含字符串处理、集合扩展、加密解密、分布式 ID、文件操作、缓存、线程、国际化等模块。设计上注重高内聚、低耦合,适用于各类 .NET 应用开发。支持 AES 加密、树形结构转换、分页过滤、日志输出等功能,提供简单易用的 API。可通过 NuGet 快速安装,源码开放,采用 MIT 协议。
117 56
|
2月前
|
JSON 数据格式
【Azure Fabric Service】演示使用PowerShell命令部署SF应用程序(.NET)
本文详细介绍了在中国区微软云Azure上使用Service Fabrics服务时,通过PowerShell命令发布.NET应用的全过程。由于Visual Studio 2022无法直接发布应用,需借助PowerShell脚本完成部署。文章分三步讲解:首先在Visual Studio 2022中打包应用部署包,其次连接SF集群并上传部署包,最后注册应用类型、创建实例并启动服务。过程中涉及关键参数如服务器证书指纹和服务端证书指纹的获取,并附带图文说明,便于操作。参考官方文档,帮助用户成功部署并运行服务。
141 72
|
2月前
|
存储 XML 开发工具
【Azure Storage Account】利用App Service作为反向代理, 并使用.NET Storage Account SDK实现上传/下载操作
本文介绍了如何在Azure上使用App Service作为反向代理,以自定义域名访问Storage Account。主要内容包括: 1. **设置反向代理**:通过配置`applicationhost.xdt`和`web.config`文件,启用IIS代理功能并设置重写规则。 2. **验证访问**:测试原生URL和自定义域名的访问效果,确保两者均可正常访问Storage Account。 3. **.NET SDK连接**:使用共享访问签名(SAS URL)初始化BlobServiceClient对象,实现通过自定义域名访问存储服务。
|
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
107 12
|
5月前
|
XML C# 数据格式
一个.NET开源、免费、功能强大的 PDF 处理工具
一个.NET开源、免费、功能强大的 PDF 处理工具
125 8
|
5月前
|
网络协议 C#
基于.NET WinForm开发的一款硬件及协议通讯工具
基于.NET WinForm开发的一款硬件及协议通讯工具
|
5月前
|
C# UED
一个.NET开源、易于使用的屏幕录制工具
一个.NET开源、易于使用的屏幕录制工具
|
5月前
|
Web App开发 C# Windows
一款.NET开源的Windows资源管理器标签页工具
一款.NET开源的Windows资源管理器标签页工具

热门文章

最新文章