我有两个 ISP,它们通过 apache / php / mysql 为我提供托管服务。我在它们上运行 drupal。有时 mysql 服务器会停止运行(崩溃),所以我希望找到一种合理的方法来实现故障转移,如果服务器 A SQL 出现故障,则所有流量都会发送到服务器 B。
我知道传统上这是在 DNS 中处理的,如果出现问题或类似情况,则会提供第二个备用 IP。但我无法控制 isp,除了我可以运行 php、perl 和常用的 apache 东西。此外,我在每个 isp 上都有静态 IP,我可以创建 dns 条目(A/CNAME/TXT)。
因此,我希望有一种方法可以让我编写一个脚本来检查 drupal 是否有问题,如果是,则以某种方式修改 dns,或者?
或者,还有其他想法吗?(除了花更多的钱找更好的 ISP 之外)
答案1
循环 DNS 不会解决您的问题 - 它是提供 Web 服务器负载平衡的好方法 - 但是当客户端尝试连接到端口并且没有收到回复时会发生故障转移(然后它会继续尝试主机的下一个 DNS 条目)。显然,如果 MySQL 数据库发生故障,那么这不会对 Web 服务器产生直接影响(即 Web 服务器将响应 TCP 请求)。
尽管原则上可以让 PHP 代码检测数据库故障并关闭网络服务器或阻止传入连接 - 但这是一种相当危险的方法 - 即使您的托管允许它发生。
我能想到的处理这种情况的唯一实用方法是在检测到故障时重定向到特定主机名,因此如果您当前已将两个主机都设置为 www.example.com,则添加 www1.example.com 和 www2.example.com 的记录,然后添加自动添加的包含文件以执行以下操作:
(on www1.example.com)
check_db();
// if check_db returns, then continue with normal processing...
function check_db() {
if (request is for www.example.com) { // avoid loops when both sites fail
if (last check more than 10 secs ago) {
if (database status bad) {
raise a database failed flag on the filesystem
redirect to www2.example.com
end
}
} else {
if (database failed flag set) {
redirect to www2.example.com
end
}
return OK
}
} else { // request is for www1.example.com i.e. we are already in failover mode
if (database failed flag set) && (last check more than 5 secs ago) {
if (database status good) {
remove database failed flag
return OK
} else { // oh no! both hosts down!
print sorry message and exit
}
} else if (last check more than 5 secs ago) {
if (database status bad) {
raise a database failed flag on the filesystem
print sorry message and exit
}
}
}
return OK
}
但是,您仍然需要某种方法来测试数据库是否在不使用阻塞调用的情况下正常工作。
高血压
C。
答案2
我认为,您要求的是故障转移,而不是负载平衡。
故障转移非常难以做好,尤其是对于不在同一基础设施内的设备。最好的情况是在您的 ISP 处获得一个冗余地理负载平衡器,它可以测试您的站点并无缝处理故障转移。由于我猜这超出了您的预算,所以我们采用棍棒和口香糖的方法吧。
既然您的问题显然是 MySQL,而不是 Web 服务器,那么让我们解决手头的问题。
鉴于:
- 主机 A:Web 服务器和 MySQL 数据库
- 主机 B:Web 服务器和冗余 MySQL 数据库
我将使用的方法是:
将数据库连接凭据存储在磁盘上的某个位置(显然不是在 Web 根目录中),并在每次页面连接时加载它们。您可以像这样编辑 sites/default/settings.php:
$db_url = file_get_contents('/some/private/dir/drupal-db.url');
编写一个后台守护程序,每隔 5 秒(或大约)连接一次数据库,并以机器可读的方式在磁盘上记录故障。连接在 30 秒(或大约)后失败,然后将存储在磁盘上的凭据与备份服务器的凭据“交换”。这将导致您的 Web 服务器从备用数据库服务器提供内容。如果恢复,则逆转该过程。在这种情况下,日志记录对于调试等至关重要。
如果您想要更进一步,您可以尝试将所有 INSERT 和 UPDATE 记录到 Web 服务器上的磁盘,这样您就可以在故障转移后重新同步数据库。如果大多数数据库都是“只读”的,那么这可能就没有必要了。
此处的重点是将故障转移与 Web 应用的操作分离开来。它更加模块化,并简化了对 Web 应用的更改。
最后,确保您可以从主服务器连接到备份数据库。您可以在命令行上执行此操作,并使用授权命令:
在主机 B 上:
mysql> GRANT ALL PRIVILEGES ON drupaldb.* TO username@'12.34.56.78' IDENTIFIED BY 'mypassword';
其中 IP 属于主机 A。
别忘了冲洗!
mysql> FLUSH PRIVILEGES:
然后测试:
bash> mysql -u username -pmypassword -h hostb drupaldb
答案3
没办法,考虑到你们的基础设施,没有合适的技术可以实现这一点。
除非您将 DNS 域超时保持在较小范围(秒数范围),否则 DNS 将无法工作,这是有原因的。如果您能做到这一点,您就可以正确地编写脚本(服务器 2 上的脚本无法到达服务器 1,因此会更改 DNS 条目)。这几乎是唯一的方法。
根据您的 DNS 设置,这可以是那里,或者 - 使用类似 dyndns.org 的东西注册主机条目,并用 CNAME 替换您的 IN A 条目。DynDNS.org 有一个不错的 API,您可以通过 HTTP 调用它来更改条目,并且 CNAME 永远不会改变。他们还将他们的域名保持在较短的 TTL 上。
这些基本上都是选项。还有其他选项,但它们需要大量您尚未具备的基础设施。