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

azure,developer,redis,key,copy,net8 · 浏览次数 : 27

小编点评

Redis Copy .NET8是一个用于将Redis数据从一个Redis端点复制到另一个Redis端点的简单工具。该工具基于.NET 8开发,可以帮助用户轻松地在不同的Redis服务器之间迁移数据。该工具的主要功能包括: 1. 支持从Redis 1个端点复制到另一个Redis端点。 2. 可以处理大量数据,速度可达每秒迁移数百条记录。 3. 支持SSL/TLS加密,保证数据传输安全。 4. 支持批量操作,如键的生存时间(TTL)设置和键的数据恢复。 5. 支持验证复制的键值是否一致。 使用Redis Copy .NET8工具,用户可以通过配置文件或命令行参数指定源Redis端点和目标Redis端点的信息,如端点地址、端口、密码等。工具会自动处理数据的迁移过程,并在完成后验证数据的完整性和一致性。 总之,Redis Copy .NET8是一个功能强大且易于使用的Redis数据迁移工具,可以帮助用户在不同的Redis服务器之间高效地迁移数据。

正文

介绍一个简单的工具,用于将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)相似的内容:

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

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

【Azure Developer】.Net 简单示例 "文字动图显示" Typing to SVG

问题描述 看见一个有趣的页面,可以把输入的文字信息,直接输出SVG图片,还可以实现动图模式。 示例URL: https://readme-typing-svg.demolab.com/?font=Fira+Code&pause=1000&color=F7F7F7&background=233911F

【Azure Developer】在App Service上放置一个JS页面并引用msal.min.js成功获取AAD用户名示例

问题描述 在App Service上放置一个JS页面并引用msal.min.js,目的是获取AAD用户名并展示。 问题解答 示例代码 Azure Service

【Azure Developer】开发模式下使用AAD账号访问Azure Blob的相关参考

问题描述 开发模式下使用AAD账号访问Azure Blob的流程参考文件 问题解答 第一步:先在AAD中注册一个APP,步骤可参考: 将应用程序注册到 Microsoft 标识平台 :https://docs.azure.cn/zh-cn/active-directory/develop/quick

【Azure Developer】使用 Microsoft Graph API 获取 AAD User 操作示例

问题描述 查看官方文档“ Get a user ” , 产生了一个操作示例的想法,在中国区Azure环境中,演示如何获取AAD User信息。 问题解答 使用Microsoft Graph API,演示如何获取AAD User信息,因参考文档是针对Global Azure,所以文档种的URL为: /

【Azure Developer】使用 Microsoft Graph API查看用户状态和登录记录

问题描述 通过Microsoft Graph的API如何来查看用户信息和登录记录呢? 问题解答 第一步:需要一个授权Token 比如一个拥有查看用户权限的Azure账号,通过Azure CLI 命令获取到一个Access Token az cloud set --name AzureChinaClo

【Azure Developer】如何通过Azure Portal快速获取到对应操作的API并转换为Python代码

问题描述 对于Azure资源进行配置操作,门户上可以正常操作。但是想通过Python代码实现,这样可以批量处理。那么在没有SDK的情况下,是否有快速办法呢? 问题解答 当然可以,Azure Portal上操作的所有资源都是通过REST API来实现的,所以只要找到正确的API,就可以通过浏览器中抓取

【Azure Developer】use @azure/arm-monitor sdk 遇见 ManagedIdentityCredential authentication failed.(status code 500)

@azure/arm-monitor ManagedIdentityCredential authentication failed.(status code 500) CredentialUnavailableError: ERROR: AADSTS500011: The resource principal name https://management.azure.com was not

【Azure Developer】示例: 在中国区调用MSGraph SDK通过User principal name获取到User信息,如Object ID

问题描述 示例调用MSGraph SDK通过User principal name获取到User信息,如Object ID。 参考资料 选择 Microsoft Graph 身份验证提供程序 : https://learn.microsoft.com/zh-cn/graph/sdks/choose-

【Azure Developer】Springboot 集成 中国区的Key Vault 报错 AADSTS90002: Tenant 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx' not found

spring.cloud.azure.keyvault.secret.property-sources[0].profile.cloud-type=AZURE_CHINA