使用 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_CONNECTTIMEOUT
和 CURLOPT_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);
我有一个数据库 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_CONNECTTIMEOUT
和CURLOPT_TIMEOUT
超时,以便可以完成检查但也不会超过很长时间。也许 5 到 10 秒? - 检查 URL 并在完成后更新时间戳。
- 看看
getrusage()
returns 你是不是很快就会达到ini_get('max_execution_time')
值。或者使用microtime()
创建您自己的计时器。但想法是在需要时打破循环以避免脚本突然被杀死。
- 设置正确的 cURL
然后您可以尝试使用 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);