数据库 101:现实世界中数据库之间的迁移是如何进行的?
最近我在 ScyllaDB 的新任务是研究如何在数据库之间迁移数据,正如我之前承诺的那样,我会向大家介绍我的最新研究成果。
如果您刚刚开始接触数据库或数据库基础知识,建议您先阅读我的首篇文章《数据库入门:面向初学者的数据一致性》。那篇文章记录了我对数据库范式的探索,我的视野远远超出了之前只使用 SQL 和 MySQL 的经验。我会持续关注这个数据库入门系列的学习进展。
目录
1. 序言
自从我开始接触这个“数据库环境”以来,我问了自己很多问题,这些问题可能要花几年时间才能解答。但其中一个问题是如何正确地执行数据库迁移,至今我仍未找到答案。
事实上,当我迁移 He4rt Developers(我领导的社区)机器人时,我尽了最大努力使后端和数据库模型尽可能完美。但当我不得不迁移所有内容时,情况真的一团糟。我决定使用“大爆炸”(拉取请求,修改了 532 个文件)迁移方法,作为一名开源维护者,这是我做出的糟糕决定之一。
当时我对数据库迁移这个主题一无所知。但我从中吸取了教训,我将在本文中分享给大家。
2. 数据库迁移:如何开始
如果您考虑过接手这样的任务,调查并研究如何正确地将数据从一个数据库迁移到另一个数据库,那么在进行任何与代码相关的操作之前,您应该了解一些事情。我的意思是,仅仅在数据库之间进行查询并不是您开始调查的起点。
在做任何事之前,我们先问自己几个问题:
- 数据库迁移的动机是什么?
- 我们应该在项目中使用什么迁移方法?
- 我们要从一个范式跳到另一个范式吗?
- 新的数据库是否能满足我们当前使用的所有功能所需的支持?
带着这四个问题,我们可以开始研究,直到回答所有问题,然后着手查询/编写代码。
3.我们为什么要进行这次迁移?
当我们谈论替换正在运行的项目堆栈的任何部分时,需要让计划在产品内部进行这一巨大变动的整个团队清楚其原因。
那么,您希望在替换中得到什么?有几种可能性:
- 降低 I/O 操作的延迟;
- 数据库维护成本更低;
- 可扩展的数据库以跟上产品的发展。
提醒一下,这些只是替换数据库的众多动机清单中的几个,好吗?向你的团队/领导询问所有你需要了解动机的细节,并确保这就是你想要的!
4.概念验证:从哪里开始?
很好!我们已经清楚了为什么要这么做。现在,让我们来弄清楚实现这一点的关键所在。您知道每种数据库范式之间的区别吗?如果您要在两个不同的数据库之间迁移数据,这应该是一个需要持续关注的问题。让我们了解一下您将要运行哪种类型的 PoC。
4.1 PoC:相同范式
想象一下您想要迁移的几个场景:
- CassandraDB 到 ScyllaDB(宽列);
- MySQL 到 PostgreSQL(关系型);
- Memcache 到 Redis(键值);
- MongoDB 到 DynamoDB 或 Firebase(文档)。
所有这些场景都更容易迁移,因为它们共享相同的数据库范例,这意味着它们遵循相同的架构。
所以,它们具有基本相同的功能、索引和数据类型。也许会有一些细微的差异,但这些差异可以通过测试并将一种功能/数据类型迁移到另一种来处理。
即使在 Discord从 CassandraDB 迁移到 ScyllaDB时也有一些问题需要解决,但最终它比在不同范式之间迁移要简单得多。说实话,如果你在 PoC 期间遇到问题,请记住这是工作的一部分。¯\ (ツ) /¯
4.2 PoC:不同的范式
好的,如果我们的问题是从基于文档的数据库转到宽列数据库呢?比如从 MongoDB 转到 ScyllaDB?
听起来像是一项艰巨的任务,而且很可能确实如此,而且这一部分尤其需要精心设计。
当 Discord于 2017 年开始从基于文档的数据库迁移到宽列数据库时,他们遇到了同样的问题。
如何拆分一个无限大的 JSON 对象?你能想象吗?请查看下面的 JSON 示例:
{
"servers": [
{
"218378123781": {
"id": "218378123781",
"server_name": "He4rt Developers",
"channels": [
{
"78931278921723": {
"name": "Test Channel 1",
"messages": [
{
"312783712867": {
"message_id": "312783712867",
"chatter_id": "danielhe4rt",
"content": "oh hi lol",
"created_at": "1691972222",
"updated_at": "1691972222"
}
},
{
"312783712867": {
"message_id": "312783712867",
"chatter_id": "danielhe4rt",
"content": "oh hi lol",
"created_at": "1691972222",
"updated_at": "1691972222"
}
}
]
}
}
]
}
}
],
"users": [
{
"danielhe4rt": {
"chatter_id": "danielhe4rt",
"joined_at": "1691972222"
}
},
{
"dont_forget_to_follow_me_on_socials": {
"chatter_id": "dont_forget_to_follow_me_on_socials",
"joined_at": "1691972222"
}
}
]
}
这就是我之前对 Discord 之类的社交模型的简单设想。我知道,这与现实相去甚远,但我们还是来谈谈这个问题吧。事实上,如果你身边有一位优秀的数据库管理员和架构师,这不会是个问题。
首先,你需要整个团队更多地了解该范式以及如何使用它。使用面向文档的模式,你可以随意推送任何内容,因为根本没有强数据一致性。但是,如果你迁移到 ScyllaDB,你需要对表进行建模,专注于你想要运行的查询,还要了解“一致性级别”和“复制因子”等概念的工作原理。
最后我们应该得到类似这样的结果:
CREATE TABLE servers (
server_id bigint
owner_id text
server_name text,
created_at timestamp,
PRIMARY KEY (server_id, created_at)
);
CREATE TABLE channels (
server_id bigint
channel_id bigint
channel_name text,
created_at timestamp
PRIMARY KEY ((server_id), created_at)
) WITH CLUSTERING ORDER BY (created_at DESC);
CREATE TABLE channel_messages (
message_id bigint
channel_id bigint,
chatter_id text,
content text,
created_at timestamp,
PRIMARY KEY ((message_id, channel_id), created_at)
) WITH CLUSTERING ORDER BY (created_at DESC);
CREATE TABLE users (
user_id text,
user_name text,
created_at timestamp,
PRIMARY KEY (user_id, created_at)
);
是的,CQL(Cassandra 查询语言)与 SQL(结构化查询语言)非常相似。我邀请你尝试一下这门ScyllaDB:NoSQL 101 基础课程。你将学到很多关于宽列范式的酷知识 :D
5. 趁还没太迟,赶紧测试!(认真的)
好的,我们运行了 PoC,并且知道哪个数据库和范例最适合我们的新环境。现在您的团队专注于尽快完成数据建模,对吗?完成后,重点将是准备好所有脚本,以确保迁移成功。
你能做的最好的事情是在临时环境中将测试分别用到数据库的 1% 和 5%。为什么?因为你的“新系统”或“新版本”在 1% 的数据库崩溃时,这反映出数据建模甚至后端存在问题。所以,停止迁移脚本,为你的应用程序编写一些测试。
现在您已经解决了 1% 的迁移错误,让我们对 5% 的数据库执行相同的过程。在此步骤中,您应该仔细测试所有内容,因为这是选择迁移策略并执行之前要做的最后一个测试步骤。
6. 迁移策略
当然,数据库之间的迁移并不是什么“新鲜事”,所以我们已经计划好了几个步骤,让你的工作更轻松。此外,还有一些规则,让你的数据库迁移看起来像是由专业人士完成的。
在这方面,有两种非常流行的策略,分别称为“热迁移”和“冷迁移”。这些策略的名称本身就反映了我们从研究伊始就一直在思考的问题:我应该关闭所有数据库,还是在旧数据库仍在运行时进行迁移?这取决于您的需求。顺便说一句,这个过程本身被称为ETL(提取、转换和加载) 。
6.1 策略:冷迁移
让我们从“最简单”且更安全的迁移策略开始:冷迁移。使用这种迁移方式的原因在于,您可以了解系统是否可以在需要的时间内停止运行而不会出现任何问题。简而言之,了解是否有维护期并告知用户。它也被称为“大爆炸迁移”,因为它将完全迁移到一个之前没有任何内容的新环境中。
这种方法适用于小型/中型系统,通常在黎明时分进行,因为这可能是一天中请求系统的用户较少的时间。
进行冷迁移时,您需要注意以下事项。我们来看看:
- 1. 计划:一天中的什么时间以及谁负责这项任务?
- 2. 提取:我们如何转储所有这些数据?也许目标数据库上已经有可用的特定工具了。
- 3. 转换:数据格式是否适合新数据库?两个数据库的结构是否相同?是否有工具可以帮助我们转换这些数据?
- 4. 加载:我们如何确保新数据库获取了所有数据?查询出错了吗?一切正常吗?
- 5. 验证:好的,我们已加载所有内容。现在我们需要验证数据是否与旧系统匹配。祝您好运!
- 6. 测试:让我们将迁移后的数据库连接到系统中,并运行所有测试套件。快完成了!
- 7. 激活:一切顺利。现在该关闭旧数据库了。恭喜,兄弟!
基本上,这是当您可以关闭所有内容并且知道如何正确执行此操作时的迁移流程。
6.2 策略:热迁移
好吧……如果你想在系统还在运行的时候就迁移东西……那你就麻烦了!等等,我只是开玩笑的 :p
事情变得有点复杂,因为你必须同时写入两个数据库。所以你可以想象,你将需要两个数据库实例,而不是一个,并且取决于
我们还有一个清单来帮助我们完成这项工作。让我们来检查一下流程:
- 1. 规划:一天中的时间不是这里的主要问题,而是支持两个数据库之间转换的适当的基础设施;
- 2. 复制:迁移过程中,两个系统需要同时提供数据
- 3. 测试和验证:在复制期间,您应该验证插入的所有数据以及迁移的数据。
- 4. 最小中断:系统应始终在线,并且如果出现任何问题,用户都不应察觉到。
- 5.切换:当所有重要数据最终迁移完成后,就该将应用程序指向新的数据库了;
- 6. 激活:一切顺利。现在该关闭旧数据库了。恭喜,兄弟!
此迁移策略适用于需要高可用性且拥有不能停止的关键服务的公司。
7. 最后的考虑
我的任务是进一步了解 DynamoDB,并创建一些关于ScyllaDB Alternator的内容。ScyllaDB Alternator是一款迁移工具,可以将任何 DynamoDB I/O 转换为 ScyllaDB 格式。我仍在进行 PoC 工作以加深了解,但在此过程中,我确实学到了一些非常酷的东西,了解了更多与迁移相关的技巧、窍门以及相关知识。
另外,明天(8月22日)还将举办一场免费活动“NoSQL数据库迁移大师班”!我会在聊天室里了解更多关于这个主题的知识,并邀请你一起参加!
希望本教程能帮助你简要了解这个主题!也请在评论区告诉我哪些内容值得学习。
别忘了点赞并分享这篇文章给你的朋友们,快去装满你的水壶吧!让我们保持联系:
Twitter DanielHe4rt PT-BR
Twitter DanielHe4rt EN
Twitch 频道