【问题标题】:Handling database going offline for 1 minute to update in query处理数据库离线 1 分钟以更新查询
【发布时间】:2016-09-28 22:24:11
【问题描述】:

供应商提供了一个只读的 MS SQL 数据库,我们使用 PHP 与之交互。

此数据库在我们时间的上午 630 和 1230 更新其数据。这会导致数据库离线不到一分钟,但这对于运行的 cronjobs 来说已经足够了,偶尔也会让最终用户点击离线数据库。

日志显示错误是一个连接错误:

Cannot open user default database. Login failed. (severity 11)
General SQL Server error: Check messages from the SQL Server (severity 11)
Login failed for user 'USER'. (severity 14) 
General SQL Server error: Check messages from the SQL Server (severity 14)
Unable to connect to server: SERVER

如果服务器在操作过程中出现故障,而不是与数据库的连接,则日志会显示以下错误:

The SELECT permission was denied on the object 'TABLE', database 'DATABASE', schema 'dbo'. (severity 14)
General SQL Server error: Check messages from the SQL Server (severity 14)
Query failed

处理此问题的最佳方法是什么?查询和连接与“或死”停止处理配对。最好抛出一个 sleep(60) 以暂停执行一分钟并重试查询/连接?这是当前的示例。该连接来自页面开头的共享 require_once 包含,因此通常在查询之前会发生一些其他操作。

$mslink = mssql_connect('SERVER', 'USER', 'PASS');

if (!$mslink || !mssql_select_db('TABLE', $mslink)) {
    die('Unable to connect or select database!');
}

$strSQL = "SELECT X,Y,Z FROM TABLE WHERE FOO = 'BAR'";
$objQuery = mssql_query($strSQL) or die("Error Query [" . $strSQL . "]");

我考虑过在连接之前检测时间并延迟它(这应该意味着查询会没问题),或者让它失败然后休眠并再次尝试(这似乎是一个更糟糕的主意 - 因为它会导致记录条目)。

这是一个尝试/捕获而不是使用 if true 功能的好地方吗?我之前没有用 try/catch 做过任何事情。

我希望使用连接的解决方案是最简单的,因为这将通过一次更改覆盖代码库,而不是在每次查询时都进行。没有框架或任何东西,这是直接的 PHP(和程序,我知道,请温柔)。计划是将来某个时候从 ext\mssql 迁移到 PDO。

【问题讨论】:

  • 查看时间,停机期间不要查询
  • 听起来你真正应该做的是在本地创建你自己的数据库来存储你需要的信息并基本上镜像他们的信息,然后使用 cron 作业来检查你最旧的条目与源数据,并删除/相应更新
  • 一句话:复制。如果您想要一个基本上 24/7 全天候运行的弹性系统,则需要多个数据库副本。

标签: php sql sql-server database data-warehouse


【解决方案1】:

我想出了一个我满意的答案。知道服务器每六个小时最多离线一分钟,我发现连接失败然后休眠几秒钟,直到重试,等待 60 秒的上限。这很有效,并开始返回更好的数据,说明其他服务器在更新期间不可用的时间。

我还从 MSSQL(在 PHP7 中已弃用)切换到 PDO 和 SQLSRV。下面的代码适用于 SQLSRV,因为它是我最初问题的最接近的替代品。

此代码与连接详细信息一起存储,因此不需要在每次查询尝试中都存储,只需在连接时的主包含中即可。

$mslink = sqlsrv_connect($serverName, $connectionOptions);
if (!$mslink) {

$ms_sql_errors = sqlsrv_errors();

if ($ms_sql_errors[0]['SQLSTATE'] == 42000) { // This is the database update error
    error_log("Cannot open database at $serverName", 0);
} elseif ($ms_sql_errors[0]['SQLSTATE'] == "HYT00") {
    error_log("Timeout - is the address $serverName correct?", 0);
} elseif ($ms_sql_errors[0]['SQLSTATE'] == 28000) {
    error_log("Login Failed!", 0);
} elseif ($ms_sql_errors[0]['SQLSTATE'] == "08001") {
    error_log("Network error connecting to $serverName", 0);
} else {
    error_log($ms_sql_errors[0]['SQLSTATE'], 0);
}
while (!$mslink && $failcount < 6) {
    $failcount++;
    sleep(10); // Attempt to reconnect after $serverName disappears
    $mslink = sqlsrv_connect($serverName, $connectionOptions);
    if (!$mslink) {
        error_log("$serverName retry $failcount failed to connect after a 10 second sleep!, will wait 10 seconds and try again...", 0);
        if ($failcount >= 6) {
            error_log("$serverName connection FAILED AFTER $failcount 10 second sleeps, stopping", 0);
        }
    } else {
        error_log("DW connection worked after $failcount 10 second sleep(s)", 0);
    }
}
}

我希望这可以帮助那些不想做太多跑腿工作以应对已知和预期的短暂访问 SQL 服务的人。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-04
    • 1970-01-01
    • 1970-01-01
    • 2021-12-07
    • 2020-11-20
    相关资源
    最近更新 更多