Python 将MySQL表传输到另一台服务器的最佳实践?

Python 将MySQL表传输到另一台服务器的最佳实践?,python,web-services,database-design,Python,Web Services,Database Design,我有一个位于“主服务器”上的系统,它定期将大量信息从MySQL数据库传输到web上的另一台服务器 这两台服务器都有一个MySQL服务器和一个运行Apache的服务器。我想要一个易于使用的解决方案 目前我正在调查: XMLRPC 宁静服务 处理脚本的简单POST 套接字传输 我主人的应用程序是TurboGears应用程序,所以我更喜欢“pythonic”即不那么难看的解决方案。通过FTP/SCP或类似的方式将转储的表复制到另一台服务器可能很快,但在我看来,这也是非常(快速)和肮脏的,我希望有一

我有一个位于“主服务器”上的系统,它定期将大量信息从MySQL数据库传输到web上的另一台服务器

这两台服务器都有一个MySQL服务器和一个运行Apache的服务器。我想要一个易于使用的解决方案

目前我正在调查:

  • XMLRPC
  • 宁静服务
  • 处理脚本的简单POST
  • 套接字传输
我主人的应用程序是TurboGears应用程序,所以我更喜欢“pythonic”即不那么难看的解决方案。通过FTP/SCP或类似的方式将转储的表复制到另一台服务器可能很快,但在我看来,这也是非常(快速)和肮脏的,我希望有一个更好的解决方案

有谁能简单地描述一下你是如何以“最佳实践”的方式做到这一点的

这不一定需要涉及数据库。在Server1上转储表并以结构化的方式传输原始数据,这样server2就可以在不解析太多的情况下处理它,这同样好。不过有一个要求:数据一到达server2,我就希望它得到处理,因此在传输完成时必须有某种通知。当然,我可以在第二台机器上的套接字上编写我自己的服务器,用自己的代码接受文件并进行处理等等,但是这只是一个非常大的系统中非常非常小的一部分,所以我不想花半天的时间来实现它

谢谢


Tom

假设您的情况允许这种安全性,您忘记了一种传输机制:只需打开从一台服务器到另一台服务器的mysql连接

在我看来,我首先要考虑一个脚本,它定期在写服务器上运行,并打开到读服务器的只读db连接(增加了一点安全性)和到它自己的数据库服务器的完整连接

然后如何继续取决于数据(是否只是要处理的插入?是否必须镜像删除?插入与更新的数量?等等),但基本上,您可以编写一个脚本,从读取服务器提取数据并立即将其处理到写入服务器


另外,mysql服务器复制是否可以工作,或者作为一种解决方案,它是否会过度膨胀?

如果您可以访问mysql的数据端口,并且不介意不断的网络流量,您可以使用。

如果表很小,您可以发送整个表,只需删除旧数据,然后在远程服务器上插入新数据,那么有一个简单的通用解决方案:您可以使用表数据创建一个长字符串,并通过webservice发送。下面是它的实现方式。请注意,这远不是完美的解决方案,只是我如何在网站之间传输小型简单表格的一个示例:

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;
}
函数dumptabletintostring($tableName,$includefeldsheader=true)
{
全球$adoConn;
$recordSet=$adoConn->Execute(“从$tableName中选择*);
如果(!$recordSet)返回false;
$data=“”;
如果($includefeldsheader)
{
//获取字段
$numFields=$recordSet->FieldCount();
对于($i=0;$i<$numFields;$i++)
$data.=$recordSet->FetchField($i)->name.,”;
$data=substr($data,0,-1)。“\n”;
}
而(!$recordSet->EOF)
{
$row=$recordSet->GetRowAssoc();
foreach($row as&$value)
{
$value=str\u replace(“\r\n”,”,$value);
$value=str\u replace(“,“\\”,$value);
如果($value==null)$value=“\\N”;
$value=“\”.$value。“\”;
}
$data.=联接(“,”,$row);
$recordSet->MoveNext();
如果(!$recordSet->EOF)
$data.=“\n”;
}
返回$data;
}
//注意:当前函数不支持处理字段头,所以现在它只是跳过它
//必要时
函数FillTableFromDumpString($tableName,$dumpString,$truncateTable=true,$fieldsHeaderIncluded=true)
{
全球$adoConn;
如果($truncateTable)
if($adoConn->Execute(“截断表$tableName”)==false)
返回false;
$rows=分解(“\n”,$dumpString);
$startRowIndex=$fieldsHeaderIncluded?1:0;
$query=“插入到$tableName值中”;
$numRows=计数($rows);
对于($i=$startRowIndex;$i<$numRows;$i++)
{
$row=分解(“,”,$rows[$i]);
foreach($row as&$value)
{
如果($value==“\\\N\”)
$value=“NULL”;
}
$query.=“(“.inpode(“,”,$row)。”)”;
如果($i!=$numRows-1)
$query.=“,”;
}
如果($adoConn->Execute($query)==false)
{
返回false;
}
返回true;
}

如果您有大型表,那么我认为您只需要发送新数据。向远程服务器请求最新的时间戳,然后从主服务器读取所有较新的数据,并以通用方式(如上所示)或非通用方式(在这种情况下,您必须为每个表编写单独的函数)发送数据。

服务器1:将行转换为JSON,使用JSON数据调用second的RESTful api

服务器2:监听URI,例如POST/data,将json数据转换回字典或ORM对象,插入数据库


sqlalchemy/sqlobject和simplejson是您所需要的。

如果您使用的是MyISAM或归档表,那么我强烈推荐