机器人以“太多连接”的方式破坏了mysql。 这不是增加最大连接数的问题。

3
我的网站可以同时处理40,000人或更多的访问并且运行速度很快,但是搜索引擎爬虫会导致mysql崩溃。这使我感到非常疯狂,因为一旦爬虫来了,网站就会显示“无法连接:连接过多”,我必须手动重启mysqld才能恢复网站。我已经解决这个问题已经有一年了。我对Apache和MySQL进行了多次调整,但似乎没有什么作用。我将max_connections从300改为1800、10000,但这并不能解决爬虫的问题。
我使用Amazon Linux,并拥有一个巨大的实例/服务器。内存不是问题。我已经做了无数的技术支持,他们从未发现任何问题。所以我必须认为这与我的编程有关。我没有使用WordPress,我是从零开始构建我的网站,但正如我所说,它可以轻松处理40,000人的访问。但是爬虫会导致它崩溃。
我的连接脚本很简单:
$connect=mysql_connect("localhost","user","password"); 
if (!$connect)
  {
  die('Could not connect: ' . mysql_error());
  }
mysql_select_db("db",$connect);

奇怪的是,即使网站上有2000人,当前连接始终是“1”。所以我觉得我在连接数据库方面做错了什么。

有没有人有经验或建议,如何应对大量机器人流量,让网站始终保持运行状态?拜托了!我再次声明,这不是增加max_connections的问题。


两个问题:1)您是否在整个用户会话期间保持连接开放?还是每个会话关闭和打开多次。2)当您有40K人时 - 您指的是同时吗?而且您仍然只看到1个数据库连接?! - carmel
我运行连接脚本,然后在选择查询之后关闭它(即使它会自动关闭)。是的,我可以同时拥有40k个连接,并且在ssh show processlist中只显示1个连接。我知道这很奇怪,所以我觉得我做错了什么。但是数据库可以很好地处理所有这些人!只是不能处理机器人,我真的很累了!! - Chris Filippou
机器人可能会攻击您的网站,而不是直接攻击您的mysqld。有什么特别的东西可以表征您的机器人流量吗?您能从用户代理字符串中判断出它们是机器人吗?如果不能,那么您如何判断?当您检测到机器人时,是否尝试使用503(临时超载)状态进行响应?这样解决问题了吗?您是否尝试将代码从臭名昭著的不可靠和已弃用的“mysql_”接口升级到“PDO”或“mysqli_”? - O. Jones
  1. PHP中已移除mysql_函数。
  2. 你是否尝试过监控你的数据库?MySQL Workbench可以持续地运行“SHOW PROCESSLIST;”并显示正在运行的查询。
  3. 你是否考虑将数据库从服务器上移动?也许移动到一个RDS实例中。
- Machavity
我没有检测机器人并响应503的方法。我可以通过访问日志来识别它们是机器人。我会执行tail命令,看到一堆机器人,然后运行访问日志中的top IP,并执行host命令查看机器人。我认为我也收到了很多垃圾机器人,并在htaccess中阻止了其中许多,但我需要允许Googlebot和其他机器人。我也考虑过使用RDS,只是还没有实施。 - Chris Filippou
你的服务器上有类似于fail2ban的东西吗?你可以将你接受的机器人列入白名单,禁止那些你不想要或不认识的机器人,这会对你的服务器有所帮助。 - Veve
1个回答

1
MySQL正在接受新的连接,但无法处理所有的查询。等待连接的数量将不断增加,直到太多。
问题并不在于MySQL,而是那些行为不当的机器人。您可能不需要每次都让这些机器人扫描您整个网站。幸运的是,您可以对它们进行一些控制。
步骤1:创建一个robots.txt文件,并禁止所有机器人,除了您关心的那些。
User-agent: google
Disallow:

User-agent: yahoo
Disallow:

User-agent: msn
Disallow:

User-agent: *
Disallow: /
步骤2: 创建网站地图。设置每个页面的最后修改时间,这意味着机器人只会访问您网站上更改的页面。您可以使用 PHP 库动态创建网站地图(查询您的数据库):thepixeldeveloper/sitemap
在本示例中,我们假设您拥有一个包含页面表的数据库。该表具有永久链接最后修改时间列。
// sitemap.php

$urlSet = new Thepixeldeveloper\Sitemap\Urlset(); 

// Adding the URL for '/' to the XML map
$homeUrl = (new Thepixeldeveloper\Sitemap\Url('/'))
  ->setChangeFreq('daily')
  ->setPriority(1.0);

$urlSet->addUrl($homeUrl);

// Add URL of each page to sitemap
$result = mysql_query("SELECT permalink, last_modified FROM pages");

while ($page = mysql_fetch_asoc($result)) {
    $url = (new Thepixeldeveloper\Sitemap\Url($page['permalink']))
      ->setLastMod($page['last_modified'])
      ->setChangeFreq('monthly')
      ->setPriority(0.5);

    $urlSet->addUrl($url);
}

header('Content-Type: text/plain');
echo (new Thepixeldeveloper\Sitemap\Output())->getOutput($sitemapIndex);

您可以在Apache中使用重写规则(或在其他HTTP服务器中类似)将sitemap.xml重写为sitemap.php
RewriteEngine On
RewriteRule sitemap.xml sitemap.php [L]

这应该足够了,但可能会有不遵守robots.txt的机器人。在HTTP服务器配置中检测并阻止它们(通过IP和/或用户代理)。

还要考虑以下几点:

最大连接数已经存在,因此您的服务器不会过载。您应该进行基准测试以确定应用程序可以处理的最大并发请求数。然后将该数字减少20%,并将其设置为HTTP Web服务器和MySQL配置中的最大值。

这意味着在过载之前,您的服务器将给出一个漂亮的503 Service Unavailable响应。这将使(行为良好的)机器人放弃并稍后重试,这意味着您的系统将恢复而无需手动操作。

您的脚本还应使用正确的HTTP响应退出。

$connect = mysql_connect("localhost", "user", "password"); 
if (!$connect) {
  header("HTTP/1.1 503 Service Unavailable");
  echo 'Could not connect: ' . mysql_error();
  exit();
}
mysql_select_db("db", $connect);

@ChrisFilippou 我假设你的页面不是静态的,而是来自数据库。你查询数据库来创建网站地图,而不是向数据库写入任何内容。我不知道你的数据库长什么样,但我仍会在答案中添加一些东西。 - Arnold Daniels
@Jansy,我的数据库结构很糟糕,所以它从多个表中提取每个类别的内容,而不是使用[类别行]来排序页面/帖子。因此,我有一个新闻表,一个视频表,一个博客帖子表等等。我该如何以这种方式从它们中提取所有内容?它们都有一个共同的[date_time]行(而不是最后修改时间)。我知道这很麻烦,非常感谢您的帮助。 - Chris Filippou
@ChrisFilippou 这应该很明显。如果您有多个表格,您需要执行多个查询,每次将结果添加到urlset中。 - Arnold Daniels
@ChrisFilippou 如果这个答案有帮助,请点赞并接受它。 - Arnold Daniels
好的,我想我已经理解了表格查询部分。我需要使用ssh安装thepixeldeveloper/sitemap库吗?我在链接中没有看到任何关于安装的内容。类似wget https://github.com/ThePixelDeveloper/Sitemap.git这样的东西? - Chris Filippou
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接