【问题标题】:Converting data from Mongo to MySQL (110M docs, 60Gigs) - Tips and Suggestions?将数据从 Mongodb 转换为 MySQL(110M 文档,60 Gigs) - 提示和建议?
【发布时间】:2012-07-20 12:44:45
【问题描述】:

我的任务是将数据从 MongoDB 数据库移植到 MySQL 数据库。 (移植有充分的理由 - 所以它必须完成)。

MongoDB 集合:

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

我们尝试过的设置:

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

我们一次从 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 条记录后重新启动。

我们使用了这个代码sn-p:

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。

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

【问题讨论】:

  • 索引呢,没事吧?
  • 我认为将应用程序和 mysql 移动到不同的服务器可能会有所帮助。 Mongo 喜欢独处,因此它可以消耗所有可用的 RAM。如果迁移中未使用索引,您可能会考虑删除它们。或者,您可以尝试将 mysql 配置为具有非常低的最大 RAM,并确保 C# 应用程序没有增加其内存使用量。
  • 你为什么要切换到MySql?只是好奇....想知道 MongoDB 的推理/问题...谢谢--S
  • 我没有使用过 MongoDB,而且我已经有好几年没有使用过 MySQL 了,但是,我将竭尽全力将矛头指向您的控制台应用程序。我之前制作过 C# 控制台应用程序来做同样的事情,但记录的数量较少(数千,而不是数百万)。我一直看到控制台应用程序在获取数据时会增长[在内存中]。我不在乎,因为无论如何它很快就完成了,但是您可能想投资重写控制台应用程序,并且绝对确保您正在清理它的内存使用量,因为它正在执行它的任务。
  • @scarpacci:这是一个分析数据库,早期的开发人员选择在 Mongo 上做,因为当时数据不是很重要。一种快速火和肮脏的方法。突然间,我们的应用程序(它是一个 iPhone 应用程序)起飞了,我们拥有了难以查询的海量数据。索引不再有太大帮助,并且 map-reducers 需要花费大量时间来获取我们需要的报告。因此,我们正在尝试将数据移动到一个完全非规范化(无外键)的 MySQL 实例。

标签: c# mysql mongodb windows-server-2008 mongodb-.net-driver


【解决方案1】:

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

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

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

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

【讨论】:

  • 是的,我有一种感觉,如果应用程序或 mysql 被杀死,它可能也会让它运行一段时间。有关不同进程的内存配置文件的更多信息会很好。
  • 我同意,使用托管代码执行这样的迁移可能(很可能是)消耗比实际需要更多的资源。 C++ 绝对是更好的选择。
  • 感谢您的见解。不久前,我在同一个配置 Linux 系统上编写了一些 PHP 代码 - Mongo 表现出类似的行为。当我获取数据时——对于最初的 300K 左右的记录,我每秒(大约)在它开始以指数方式减速之前做 1000 条记录。在 Windows 上,我选择重新启动 Mongo,因为 mongod 进程在 6 小时内从使用 350 Megs 的 RAM 增长到 6.5 Gigs。 (.Net 应用程序当前使用 400 Megs)。当我尝试新东西时会发布更多更新......会尝试给 C++ 选项一个旋转。
  • @saurabhj : 6.5 gig 的 RAM,就可以了 :) 现在,我知道 MongoDB 在许多领域都有使用,你会认为如果它在几千次读取后停止,有人会拥有注意到......所以我现在怀疑你的应用程序,它是否在 Mongo 中保留了应该发布的东西?也许您应该将此问题发送给 10gen,显然他们的支持是一流的。
  • Mongo 会这样做,如果它不竞争资源,由于内存映射文件的性质。当它不竞争资源时(根据我的经验),问题就来了,然后突然之间就出现了——释放该文件缓存以便其他进程可以使用它是操作系统的工作。你在 mongo 中的索引有多大?
【解决方案2】:

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

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

我所做的是为每个部分产生较小的交易 并在每次解决工作项时关闭它们。

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

毕竟:

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

注意:在写入时不要在目标数据库中有索引 它会给你一个终极的性能提升。设置索引 当你有所有的数据时。

【讨论】:

    【解决方案3】:

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

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

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

    【讨论】:

    • 更好的是,结合两个答案:使用 mongoexport 从 mongo 转储数据,对 mySQL 使用某种加载,只编写一个将 JSON 文件转换为 SQL 插入语句文件的程序。跨度>
    • 是的。执行 Mongo -> json text files -> MySQL 是我的最后一个也是最后一个选项,我很确定它会起作用。但我认为这需要很多时间。如果没有其他办法,我肯定会走那条路。感谢您验证我的思考过程。 :)
    • 这就是你误会的地方。它会更快。随着 MySQL 和 Mongo 争夺资源(尤其是 IO),实际性能将大大降低。如果您同时运行两者,请不要期望每个都以它们单独运行的速度的约 50% 运行。 5-10% 更现实。通过首先在 MySQL 上运行操作,然后在 Mongo 上运行,您实际上可能会快 2-3 倍。我学得很辛苦。
    【解决方案4】:

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

    【讨论】:

    • MySQL 在这个阶段表现非常好,仅消耗 450 Megs 的 RAM(运行 6 小时)。 Mongo 实际上占用了 6.78 Gigs 的 RAM。我猜想在 Windows 上运行 Mongo 可能是个坏主意,我的下一步可能是在单独的机器上的 Linux 机器上实际运行它。感谢您的反馈!
    • 重启MongoDB之前可以先看看内存和交换情况。膨胀的内存使用和磁盘交换将是资源泄漏的症状。
    【解决方案5】:

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

    【讨论】:

    • 感谢您的评论。我的最后一个选择是导出到 json 并尝试通过读取 json 文件来推送到 MySQL。但是,获取 60 gig 的文本数据并处理这么多文件有其自身的后勤挑战。所以我把它作为最后的资源。
    • 这终于对我们奏效了——我们尝试的其他事情要么太麻烦,要么花费了很多时间。我们终于做了一个 mongoexport 并编写了一个应用程序来读取文件并更新 MySQL,这确实有效——而且速度也很快!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-25
    • 2012-07-16
    • 2021-02-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多