10

我的任务是将数据从 MongoDB 数据库移植到 MySQL 数据库。(移植有充分的理由——所以必须这样做)。

MongoDB 集合:

  • 拥有大约 1.1 亿份文档
  • 大小为 60 GB
  • 具有重要属性的索引
  • 正在运行不为任何生产流量提供服务的 Windows 2008 独立独立服务器

我们尝试过的设置:

  • 具有 7.5 Gigs RAM / 8 Gigs 页面文件的大型 Amazon EC2 Win2008 服务器实例
  • AC# 控制台应用程序,将 MongoDB 数据转换为本地 MySQL 数据库

我们一次从 MongoDB 的内存中提取 1K 个文档,进行必要的处理,然后将它们保存到 MySQL db,一次批量写入 500 个。

我们面临的问题是,每 250 万个文档,服务器就会阻塞,Mongo 响应非常缓慢 - 应用程序的数据获取操作超时(在处理 100 万个文档时,可用 RAM 已经结束)

我们通过杀死 mongod 进程并在每 250 万条记录崩溃时重新启动它来缓慢前进——但我敢打赌我们做错了什么。

问题:

我是否应该为此将 Mongo 服务器移动到基于 Linux 的大型实例并将 MySQL 移动到 Amazon RDS 并用 PHP 重写转换应用程序?会有帮助吗?

我们决定将它全部放在一个盒子上的原因是在不同的盒子上拥有不同的服务器的延迟问题 - 但我想如果盒子窒息,那是没有实际意义的。

我还可以尝试哪些其他事情/可以使用的技巧?

感谢您阅读到这里!

-- 更新 01 --

自从我重新启动我的应用程序并进行了以下更改以来,已经过去了大约 6 个小时:

  1. 一次将 Mongo 读取计数从 1,000 条增加到 10,000 条。.skip(10K).limit(10K)
  2. 从 MySQL 目标数据库中删除了所有索引。
  3. 将 Windows 页面大小从 4 Gigs 增加到 8 Gigs

我的内存消耗为 100%,但应用程序仍在运行。(上次它在 52 分钟内发出呱呱叫声)。Mongo 吃 6.8 Gigs 的 RAM,MySQL - 450 Megs 和转换器应用程序 - 400 Megs(大约值)。

到目前为止处理了 1100 万条记录 - 但速度已经从大约 500 条记录/秒下降到 370 条记录/秒。

接下来的步骤将是将 Mongo 和 MySQL 服务器隔离到单独的盒子中,并将它们都放在同一个 Amazon 可用区中,以最大限度地减少延迟。

-- 更新 02 --

我们对代码进行了一些更改以使用 Mongo 光标并让它自动递增,而不是自己执行 .skip().limt()。这大大加快了这个过程,我们每秒可以处理 1250 条记录,而之前的记录是 300 多条。但是,应用程序开始消耗过多的内存,并且会耗尽 RAM 并崩溃,并且需要在每 2M 记录后重新启动。

我们使用了这个代码片段:

var docs = db[collectionName].Find(query);
docs.SetBatchSize(numOfResultsToFetchAtATime);
foreach (var d in docs) {
  // do processing
}

因此,它的作用是一次获取“numOfResultsToFetchAtATime”记录,然后在循环中自动进行并获取下一组记录。Mongo 使用 Cursor 来处理这个进程,因此它要快得多。

但是,我们仍然无法成功移植它。当这种情况发生时,我会用代码发布我的回复。

-- 更新 03:成功 --

我们最终使用了@scarpacci 的建议做一个 mongoexport。请记住,mongodb 必须位于 linux 机器上而不是 windows 机器上。

我们首先尝试在本地 MongoDB 上从 Windows 执行 mongoexport,无论我们尝试什么,对于一个大型集合(13Gigs+),它都会在不同的地方失败

最后,我在 Linux 机器上恢复了数据库,mongoexport 就像一个魅力一样工作。

没有 Json -> MySQL 转换器 - 所以我们必须做很多事情。稍作调整,我们就可以使用我们以前的应用程序并读取文件并直接写入 MySQL。它快速且相对没有错误。

我们在处理大文件时遇到了一些问题,但是将 13GB 文件分解为 500 Meg 长文件有助于解决这个问题,我们能够成功地将所有数据迁移到 MySQL。

非常感谢大家花时间帮助我们。希望这个解释对将来的人有所帮助。

4

5 回答 5

3

我曾经使用 .NET 将数据迁移到 SQLServer 时遇到过问题——尽管我试图让它尽可能轻量级,但速度仍然是不可接受的。最后,我编写了一个快速的 C++ OLEDB 应用程序,事情进展得非常快。我仍在试图找出我在 .NET 应用程序中做错了什么,但问题可能出在 .NET 中。我不会用 PHP 重写转换,而是选择性能选项并使用 C++(从网上获取教程,它并不难,不是一次性应用程序)

因此,这是首先要查看的一件事 - 以及分析您的 C# 应用程序以查看它是否存在内存泄漏错误,该错误会慢慢使系统的其余部分陷入困境。

我发现你停止 MongoDB 应用程序而不是其他任何东西很有趣。是什么让你认为它的 MongoDB 正在消亡,而不是其他系统?如果它的内存使用情况,那么拆分到单独的盒子可能会有所不同,如果它的内存增长缓慢,那么读取更少的块 - Mongo 应该可以很好地读取数据,所以如果不是,那么你可能已经对它做了一些事情让它保持它的内存,无论是在配置中还是在你的应用程序中。

启动 perfmon 并查看 Mongo、您的应用程序和 MySQL 实例的内存、交换、磁盘 IO 和 CPU 使用情况。

于 2012-07-21T15:21:16.353 回答
3

一旦我迁移了一个大数据库(不是 60 GB,但大到足以显示问题),我最终编写了一个小应用程序来完成这项工作。

这样,我使用某种批处理模式从一个数据库读取并写入另一个数据库(我面临数据库崩溃等类似问题)

我所做的是为每个部分生成较小的事务,并在每次解决工作项时关闭它们。

我们在两个数据库中都有表,没有文档,但问题是一样的。

毕竟:

  • 有一个应用程序可以协调迁移,但它自己没有任何数据库连接
  • 从协调应用程序产生多个实例来移动数据,做一个工作项目,然后关闭(在关闭之前有一些报告成功的方式)这样你就可以有多个读取器/写入器并且可以尝试计数,我只有大约 10 个一次并发读取器/写入器实例。如果您的文档足够小,您可以生成更多文档。但无论如何,它们都会很快关闭。

注意:写入目标数据库时不要在目标数据库中创建索引,这将为您带来最终的性能提升。当您拥有所有数据时设置索引。

于 2012-07-21T16:25:31.293 回答
3

您没有理由将数据直接写入 MySQL - 将作业分成 2 个单独的阶段,您将首先运行 MongoDB,然后运行 ​​MySQL,因此它们不会竞争资源 - 看起来不断增长的 MySQL 进程使 Mongo 挨饿在 RAM 或 io 上。

第一阶段:从 MongoDB 获取数据,对其进行处理并将其保存到文本文件(如 SQL)中。停止 Mongo,启动 MySQL

第二阶段:使用第一阶段生成的文件运行常规数据库导入。

于 2012-07-21T17:39:28.510 回答
2

重新启动 MongoDB 解决了性能问题,并且在它突然出现之前您可以处理的记录数量一致,这对我来说听起来像是资源泄漏。我会确保一切都已关闭,等等。确保 MySQL 未配置为使用太多内存,或者更好的是,将其移动到另一台机器上。

于 2012-07-21T17:32:17.543 回答
1

您是否考虑过使用mongoexport然后在 MySQl 中执行某种批量插入?不确定这在 MySql 中是否可用,但我们一直在 SQL Server 中执行类似的操作。可能会使转储/插入更容易分解和优化?只是一个想法....

于 2012-07-21T16:12:21.367 回答