28

与 Mysql 不同,我发现尝试同步 MongoDB 文件非常具有挑战性——
它们无法通过管道返回,因为它们不会将数据发送到标准输出
(如果我理解正确的话)。

所以,我试图找到另一种方法,它不涉及两个 ssh 调用。
需要做的是这样的:

  • 登录 ssh 服务器
  • 导出所有 MongoDB 文件
  • 将它们压缩为 gzip
  • 将它们发送回本地计算机
  • 提取和导入

不过,这里的关键是不留下任何痕迹——
我不希望压缩文件留在远程机器中,
这通常需要我进行另一个 ssh 登录。 因此,如果以后可以将其无缝地通过管道传输回本地计算机
,那么类似于“将文件移动到存档中”的方法是理想的解决方案。

我意识到 MongoDB 有一种使用 mongodump 连接到服务器凭据的方法,但是端口是关闭的 atm,所以我需要 SSH 方法。顺便说一句,任何其他想法都会受到欢迎。

编辑 - 11.06.14

由于这个问题似乎有点受欢迎,我想分享一个从这个问题的答案和去年其他资源演变而来的脚本(信用是信用到期的地方)。
该脚本基本上管理从/到远程服务器的同步,对于任何一种类型的 db 都可能(暂时可能是 postgres、mysql 和 mongo)。
它确实有一些假设,例如 root 用户没有数据库密码,但可以根据需要进行更改。

该脚本可以在这里找到:https ://github.com/iwfmp/zsh/blob/master/scripts/db/db-sync

4

3 回答 3

63

您可以使用 SSH 隧道来完成此操作,将远程 MongoDB 实例设置为在本地端口之一上运行。默认情况下,MongoDB 在 27017 上运行,因此在下面的示例中,我选择将远程 MongoDB 实例映射到本地 27018 端口。

如果您尝试将数据库从 SERVER1 复制到 LOCALHOST,则可以在 LOCALHOST 上运行此命令:

ssh -L27018:localhost:27017 SERVER1

(显然将 SERVER1 替换为您的实际服务器或 ssh 别名)

这会打开到 SERVER1 的 SSH 连接,但也会将 LOCALHOST 上的端口 27018 映射到 SERVER1 上的远程端口 27017。不要关闭该 SSH 连接,现在尝试使用端口 27018 连接到 localhost 机器上的 MongoDB,如下所示:

mongo --port 27018

您会注意到这现在是 SERVER1 上的数据,除非您是从本地计算机访问它。

正常运行MongoDB:

mongo(或mongo --port 27107

将是您的本地机器。

现在,由于您在技术上拥有(在您的 LOCALHOST 上,您在其中运行 SSH 隧道):

  • 27017 上的 MongoDB(本地主机)
  • 27018 上的 MongoDB (SERVER1)

您可以只使用db.copyDatabase()MongoDB (LOCALHOST) 中的函数来复制数据。

从 27017 端口上的本地主机(实时执行将删除您的数据)

// Use the right DB
use DATABASENAME; 
// Drop the Existing Data on LOCALHOST
db.dropDatabase();
// Copies the entire database from 27018
db.copyDatabase("DATABASENAME", "DATABASENAME", "localhost:27018");

您应该能够将这一切包装到一个 shell 脚本中,该脚本可以为您执行所有这些命令。我自己也有一个,但它实际上有一些额外的步骤,可能会让它更混乱:)

这样做,并使用 MongoDB 的本机 db.copyDatabase() 函数将防止您不得不转储/压缩/恢复。当然,如果你还想走那条路,跑起来也不是什么难事mongodump,导出数据,tar/gzip,然后用scp TARGETSERVER:/path/to/file /local/path/to/file拉下来运行amongorestore就可以了。

只是似乎需要更多的工作!

编辑- 这是一个 SH 和 JS 文件,它们一起构成一个 shell 脚本,您可以使用它来运行它。在你的 LOCALHOST 上运行这些,不要在 live 上运行它们,否则它会在 live 上运行 db.dropDatabase。将这两个文件放在同一个文件夹中,并将YOURSERVERNAME替换pull-db.sh为 domain/ip/ssh 别名,然后pull-db.js将 DBNAMEHERE 更改为您的数据库名称。

我通常在我的项目中创建一个名为的文件夹scripts,并使用 Textmate,我只需⌘+Rpull-db.sh打开编辑时点击即可执行它。

拉db.sh

ssh -L27018:localhost:27017 YOURSERVERNAME '
    echo "Connected on Remote End, sleeping for 10"; 
    sleep 10; 
    exit' &
echo "Waiting 5 sec on local";
sleep 5;
echo "Connecting to Mongo and piping in script";
cat pull-db.js | mongo

拉-db.js

use DBNAMEHERE;
db.dropDatabase();
use DBNAMEHERE;
db.copyDatabase("DBNAMEHERE","DBNAMEHERE","localhost:27018");

我在 shell 脚本中添加了一些额外的代码来回显它在做什么(排序)。脚本中的睡眠计时器只是为了让 SSH 连接有时间在下一行运行之前建立连接。基本上,会发生以下情况:

  1. 代码的第一行在您的机器上创建隧道,并将 ECHO、SLEEP 和 EXIT 发送到远程 SSH 会话。
  2. 然后等待 5 秒,这将允许步骤 1 中的 SSH 会话连接。
  3. 然后我们将 pull-db.js 文件通过管道传输到本地 mongo shell。(第 1 步应在 5 秒内完成……)
  4. pull-db.js 现在应该在 mongo 中运行,并且步骤#1 中的 SSH 终端在连接打开后可能已经运行了 10 秒,并且 EXIT 被发送到它的会话。发出命令,但是,SSH 会话实际上将保持打开状态,直到步骤 #3 中的活动完成。
  5. 一旦你的 pull-db.js 脚本完成从远程服务器中提取所有数据,在远程服务器上的步骤 #1 中发出的 EXIT 命令最终被允许关闭连接,解除本地主机上的 27108 绑定。

您现在应该在本地主机中拥有远程数据库中的所有数据。

于 2013-05-18T04:09:11.677 回答
6

要完成 Jesta 很好的答案,如果你想做相反的事情(从本地数据库复制到远程数据库),你必须以另一种方式绑定端口,使用 -R 命令而不是 -L 命令:

ssh -R27018:localhost:27017 YOURSERVERNAME

现在,登录到远程服务器,您可以从本地数据库复制数据库:

蒙哥

> db.copyDatabase('test','test','localhost:27018')

于 2013-12-08T12:13:06.753 回答
2

我真的不喜欢让一个数据库连接到另一个 - 恕我直言,它打破了环境的分离,并使自动化此类脚本变得复杂。

我的解决方案是使用使用“转储目录”的 mongo 转储/恢复并使用 tar 流式传输文件。一个简单的实现(用于从一个远程复制到另一个远程)可能如下所示:

ssh remote1 'mongodump > /dev/null && tar -zc dump && rm -rf dump' | \
  ssh remote2 'tar -zx && mongorestore dump && rm -rf dump'

笔记:

  1. 两者mongodumpmongorestore都有非常详细的输出,但是mongodump's 都会与 tar 流混淆,并且mongodump如果您在没有伪终端且没有输出重定向的情况下运行,显然也会拒绝工作。
  2. mongodump可以选择转储到标准输出,但我不知道它使用哪种格式,我不明白如何mongorestore加载它。
于 2014-10-17T17:51:11.563 回答