我有一个系统运行在“主服务器”上,该系统会定期将大量信息从 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;
}
- 如果你有大量表格,那么我认为你只需要发送新的数据。询问远程服务器的最新时间戳,然后从你的主服务器读取所有更新的数据并发送出去,你可以使用通用方式(如我上面介绍的方式)或非通用方式(在这种情况下,你必须为每个表格编写单独的函数)。