使用 PHP/MS SQL/Task 调度程序测试存储在数据库中的 10,000 多个无效 URL 的有效方法

Efficient way to test dead 10,000+ URLs stored on database using PHP/MS SQL/Task Scheduler

我有一个数据库 table,其中包含 10,000 多个带有 URL 的条目。我正在使用 get_headers() PHP 函数测试 URL 是活动的还是死的,我设置了一个每小时运行一次的任务(条目以大约 500 个块进行测试)

它工作正常,但是超时,因为它必须一次查询很多条目。

有没有更好的方法既可以做到这一点又可以减少服务器负载? 我也试过 CURL,但它有同样的超时问题。

谢谢

根据 this comment on PHP's documentation 使用 cURL 可能更好。

  • 我会在数据库中存储最后一次 URL 检查每个条目的时间戳。
  • 创建一个每分钟或每 x 分钟触发一个 PHP 脚本的 cron 作业。

PHP cron 任务:

  • 我会查询数据库以获取时间戳早于一天(或 x 小时)的所有 links,首先按较早的排序,并且限制为 20 links或更多。
  • 循环这些 link 并用 cURL 检查每个 link:
    • 设置正确的 cURL CURLOPT_CONNECTTIMEOUTCURLOPT_TIMEOUT 超时,以便可以完成检查但也不会超过很长时间。也许 5 到 10 秒?
    • 检查 URL 并在完成后更新时间戳。
    • 看看 getrusage() returns 你是不是很快就会达到 ini_get('max_execution_time') 值。或者使用 microtime() 创建您自己的计时器。但想法是在需要时打破循环以避免脚本突然被杀死。

然后您可以尝试使用 curl_multi_*() 例程来提高速度。我只是没有找到一个很好的解决方案,您可以在其中读取每个完成句柄的结果以更新数据库。如果您必须等待所有请求完成,那么为什么不打包一些 URL 请求并将它们全部 运行 。这是我快速尝试的方法,但通过阅读结果(这不是你的情况):

<?php

define('TIMEOUT', 8);

$urls = [
    'https://www.php.net/manual/fr/function.curl-multi-select.php',
    'https://www.bag.admin.ch/bag/fr/home/krankheiten/ausbrueche-epidemien-pandemien/aktuelle-ausbrueche-epidemien/novel-cov/testen.html',
    'https://ofsp-coronavirus.ch/tester/',
    'https://www.liguepulmonaire.ch/nc/fr/maladies-et-consequences/bpco/test-de-risque-bpco.html',
    'https://www.ge.ch/covid-19-se-faire-tester/faire-test-covid-19',
    'https://www.gsi.be.ch/fr/start/themen/coronavirus/testen/wo-kann-ich-einen-covid-19-test-machen-.html',
    'https://diagnostics.roche.com/ch/fr/products/params/sars-cov-2-rapid-antigen-nasal-test.html',
    'https://www.unispital-basel.ch/fr/patients-proches/votre-sejour/massnahmen-coronavirus/test-coronavirus/',
    'https://www.insel.ch/fr/patients-et-visiteurs/coronavirus/test-du-covid-dans-linsel-gruppe',
    'https://www.bag.admin.ch/bag/en/home/krankheiten/ausbrueche-epidemien-pandemien/aktuelle-ausbrueche-epidemien/novel-cov/testen.html',
    'https://www.fr.ch/sante/covid-19/test-covid-19-liste-des-pharmacies-autorisees',
    'https://www.fr.ch/document/425951',
    'https://www.m3-test.ch/',
    'https://www.ehnv.ch/covid-19',
    'https://covid-19testing.genepredictis.com/',
    'https://www.vd.ch/themes/mobilite/automobile/test-schuhfried/',
    'https://www.hirslanden.ch/fr/corporate/campagne/covid-19-test/tests-repetitifs-preventifs-entreprises-ecoles.html',
];

$multi_handle = curl_multi_init();

$handles = [];

foreach ($urls as $i => $url) {
    $handles[$i] = curl_init();
    curl_setopt_array($handles[$i], [
        CURLOPT_URL => $url,
        CURLOPT_HEADER => false,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_CONNECTTIMEOUT => TIMEOUT,
        CURLOPT_TIMEOUT => TIMEOUT,
    ]);
    curl_multi_add_handle($multi_handle, $handles[$i]);
}

$running = null;

do {
    curl_multi_exec($multi_handle, $running);
    usleep(1000);
} while ($running > 0);

$results = [];

foreach ($handles as $i => $handle) {
    $results[$i] = curl_multi_getcontent($handle);
    curl_multi_remove_handle($multi_handle, $handle);
}

curl_multi_close($multi_handle);

var_export($results);