如何将 MySQL 表高效地传输到另一台服务器?

116 阅读3分钟

我有一个系统运行在“主服务器”上,该系统会定期将大量信息从 MySQL 数据库传输到 Web 中的另一台服务器。两台服务器都运行着 MySQL 服务器和 Apache。我希望找到一个易于使用的解决方案来完成此操作。

目前我正在考虑以下方法:

  • XMLRPC
  • RestFul 服务
  • 简单地将数据 POST 到处理脚本
  • 套接字传输

我的主服务器上的应用程序是 TurboGears 应用程序,因此我更喜欢“pythonic”的解决方案,也就是不太丑陋的解决方案。通过 FTP/SCP 或类似的方式将转储的表复制到另一台服务器可能很快,但在我看来这也是非常(快速且)粗糙的,而我希望能找到一个更好的解决方案。

是否有谁能简要描述一下你将如何以“最佳实践”的方式来完成此操作?

这个解决方案并不一定要涉及到数据库。将数据表转储到服务器 1 上,然后以结构化的方式传输原始数据,以便服务器 2 能够在不进行太多解析的情况下对其进行处理,这样的解决方案也同样好。

不过,有一个要求:数据一旦到达服务器 2,我就希望对其进行处理,因此当传输完成后必须有某种形式的通知。当然,我可以直接编写一个完整的服务器,让其位于第二台机器上的套接字上,并使用自己的代码接收和处理文件,等等,但这只是一套非常大的系统中非常小的一部分,因此我不想花半天的时间来实现这一点。

感谢, 汤姆

2、解决方案

答案 1:

  • 服务器 1:将行转换为 JSON,使用 JSON 数据调用第二个服务器的 RESTful API。
  • 服务器 2:监听一个 URI,例如 POST /data,获取 JSON 数据,将其转换回字典或 ORM 对象,并插入到数据库中。
  • 你需要使用 sqlalchemy/sqlobject 和 simplejson。

答案 2:

  • 如果表很小,你可以发送整个表,然后删除旧数据,再在远程服务器上插入新数据,那么可以有一个简单通用的解决方案:你可以创建一个包含表格数据的长字符串,并通过网络服务将其发送出去。你可以参考此方法进行实现。请注意,这并不是一个完美的解决方案,只是一个例子,说明我如何通过网站来传输简单的表格:
function DumpTableIntoString($tableName, $includeFieldsHeader = true)
{
  global $adoConn;

  $recordSet = $adoConn->Execute("SELECT * FROM $tableName");
  if(!$recordSet) return false;

  $data = "";

  if($includeFieldsHeader)
  {
    // fetching fields
    $numFields = $recordSet->FieldCount();
    for($i = 0; $i < $numFields; $i++)
      $data .= $recordSet->FetchField($i)->name . ",";
    $data = substr($data, 0, -1) . "\n";
  }

  while(!$recordSet->EOF)
  {
    $row = $recordSet->GetRowAssoc();
    foreach ($row as &$value)
    {
      $value = str_replace("\r\n", "", $value);
      $value = str_replace('"', '\"', $value);
      if($value == null) $value = "\N";
      $value = """ . $value . """;
    }
    $data .= join(',', $row);

    $recordSet->MoveNext();

    if(!$recordSet->EOF)
      $data .= "\n";
  }

  return $data;
}

// NOTE: CURRENTLY FUNCTION DOESN'T SUPPORT HANDLING FIELDS HEADER, SO NOW IT JUST SKIPS IT
// IF NECESSARRY
function FillTableFromDumpString($tableName, $dumpString, $truncateTable = true, $fieldsHeaderIncluded = true)
{
  global $adoConn;

  if($truncateTable)
    if($adoConn->Execute("TRUNCATE TABLE $tableName") === false)
      return false;


  $rows = explode("\n", $dumpString);
  $startRowIndex = $fieldsHeaderIncluded ? 1 : 0;

  $query = "INSERT INTO $tableName VALUES ";
  $numRows = count($rows);

  for($i = $startRowIndex; $i < $numRows; $i++)
  {
    $row = explode(",", $rows[$i]);

    foreach($row as &$value)
    {
      if($value == ""\N"")
        $value = "NULL";
    }

    $query .= "(". implode(",", $row) .")";
    if($i != $numRows - 1)
      $query .= ",";
  }

  if($adoConn->Execute($query) === false)
  {
    return false;
  }

  return true;
}
  • 如果你有大量表格,那么我认为你只需要发送新的数据。询问远程服务器的最新时间戳,然后从你的主服务器读取所有更新的数据并发送出去,你可以使用通用方式(如我上面介绍的方式)或非通用方式(在这种情况下,你必须为每个表格编写单独的函数)。