在分片之间迁移数据

本文关键字:迁移 数据 之间 | 更新日期: 2023-09-27 18:37:24

对于我正在从事的项目,我们需要客户附近的数据库中的客户数据。出于这个原因,我们采用了 Microsoft 年新的弹性缩放解决方案。这消除了分片的复杂性,并且仍然使您能够在全球范围内扩展。

目前,我面临着一个相当重要的问题。我需要将数据从一个分片迁移到另一个分片。有一个示例应用程序(合并/拆分)可以执行某些操作,但它适用于范围(1..100,101..400等)。我正在处理的数据库使用 Guids,因此我们不能使用示例代码。

我自己创建了一个移动/合并管理工具,但在这里面临一个问题。起初,我想用ORM插入所有对象和依赖项。由于一些圆形键,我无法轻松做到这一点。因此,我现在正在创建一个 SQL 脚本。SQL 脚本大约为 130MB,仅包含INSERT命令。

所有这些都必须在 1 个事务内完成,因为您不希望迁移半途而废。如果出现错误,则应回滚所有内容。

运行这个 130MB 的脚本会给我一些错误。我的本地开发计算机和 SQL Azure 内存不足。SQL Azure:

缓冲池中可用内存不足

和本地:

资源池"默认"中的系统内存不足,无法运行此查询。

我尝试禁用索引,因此这不会在每个INSERT都重建。这并没有解决任何问题。

关于如何进行的任何建议?我无法真正拆分脚本,因为必须一次INSERT所有数据。我认为 SSIS 包也不是一种选择。

创建我自己的数据库事务系统似乎有很多矫枉过正和容易出错的事情。

除了INSERT脚本之外,我还需要在"旧"分片/数据库上执行DELETE脚本,所以我想解决方案也必须适用于此脚本。我很想在 1 个事务中执行INSERTDELETE脚本,但这在 SQL Azure(分布式事务)上(尚)是不可能的。

在分片之间迁移数据

Azure SQL DB 弹性缩放的当前预览版中的拆分/合并版本具有已知限制,即它仅适用于范围分片映射。我假设您当前正在使用列表分片映射作为您的 GUID。虽然我们目前正在努力在 Elastic Scale 预览版的更新中提供对列表分片映射和拆分/合并的支持,但我鼓励您尝试一下解决方法。这种解决方法可能比为分片之间的数据移动编写自己的基础设施更简单,并且可以为您节省大量工作(希望如此)。

这是我的建议:

  • 将列表分片映射替换为类型 guid 上的范围分片映射。
  • 将数据中的每个 GUID 设置为单一实例范围:使用 GUID 值本身作为左边界和使用二进制表示形式中递增 1 的 GUID 值作为其右边界(请记住,右边界是排除的,而左边界是包含的)。可以使用 ShardKey 类的 RawKey 属性轻松检索左边界点的二进制表示形式。
  • 将拆分/合并服务指向新的范围分片地图。
  • 使用范围分片映射上拆分/合并的 shardlet 移动操作将给定的 guid 从一个分片移动到另一个分片。

让我知道这是如何工作的。如果你遇到麻烦 - 特别是增加GUID - 给我一个大喊大叫 torsteng(at)microsoft(dot)com。

最好托斯滕

下面是一段代码,可帮助您递增 guid 值。

    static void CreateMappings()
    {
        ShardKey guid1 = new ShardKey(new Guid("<yourgui1d>"));
        ShardKey guid2 = new ShardKey(new Guid("<yourguid2>"));
        ShardKey guid1_next = NextShardKeyForGuid(guid1);
        ShardKey guid2_next = NextShardKeyForGuid(guid2);
        _map.CreateRangeMapping(new Range<Guid>(guid1.GetValue<Guid>(), guid1_next.GetValue<Guid>()), _shard1);
        _map.CreateRangeMapping(new Range<Guid>(guid2.GetValue<Guid>(), guid2_next.GetValue<Guid>()), _shard2);
    }
    static ShardKey NextShardKeyForGuid(ShardKey shardkey)
    {
        int len = 16;
        byte[] b = new byte[len];
        shardkey.RawValue.CopyTo(b, 0);
        while (--len >= 0 && ++b[len] == 0) ;
        // Treat overflow if the current key's value is the maximum in the domain
        if (len < 0)
        {
            return new ShardKey(ShardKeyType.Guid, null);
        }
        else
        {
            return ShardKey.FromRawValue(ShardKeyType.Guid, b);
        }
    }
}