質問
スクリプトを定期的に (1 時間ごとに) 実行するスケジュールされたタスクがあります。このスクリプトはデータベースおよびファイルシステムとの大量の対話を実行するため、実行には通常数分かかります。問題は、スクリプトの実行中にサーバーの CPU 使用率が急増し、通常の操作が遅くなることです。このプロセスを調整して、時間はかかりますが、リソースの消費を少なくする方法はありますか?
PHP のさまざまな構成オプションを調べましたが、私のニーズに合うものはないようです。
php.ini でmemory_limit を低い値に設定すると、データ オブジェクトが簡単にオーバーフローしてしまいます。
スクリプト内の特定の時点で sleep() を使用することを提案している同様の投稿を見たことがありますが、それでもスクリプトによるサーバーの負荷の急増は防止されません。
最適な解決策は、ランプ (この場合は Wamp) スタックに最大 CPU 使用率の 10% のみを使用するように指示する方法です。私は実行時間についてはまったく心配していませんが、1 秒あたりの CPU サイクルを節約するという意味であれば、実行時間は長くなることを好みます。私の別の解決策は、データベース レプリケーションを備えた別のサーバーをセットアップして、他のすべての速度を低下させることなく cron を実行できるようにすることです。
環境:Windows Server 2k3、Apache 2.2.11、PHP 5.2.9、MySQL 5.1
この状況についての洞察をいただければ幸いです。
編集: *nix 固有のものであっても、すべての回答に感謝します。私の状況では、ホスティング環境を変更するにはまだ十分早いです。この質問が OS に関係なく他の人に役立つことを願っています。
解決
これは難しい問題です。コマンドライン経由で PHP スクリプトを実行している場合は、プロセスのスケジュール優先度を低く設定できます (start /low php.exe myscript.php
私は信じている)。PHP スクリプト自体が実際に CPU を消費する処理のほとんどを実行している場合、これは機能する可能性があります。ただし、データベースとファイルシステムの大量の相互作用を行っているため、このソリューションでは役に立たないとおっしゃいました。INSERT クエリと UPDATE クエリに役立つ MySQL ヒント「LOW_PRIORITY」があるようですが、私は試していません。
他のヒント
Windows のプロセスの優先順位を低く設定できます。 プロセスがどのように開始されるかはわかりませんが、プロセスの優先順位を低く設定すると、優先順位を本当に低く設定すると、CPU リソースを必要とするものはすべて取得されます。
で UNIX (LAMP) ループを続ける前にサーバーの負荷を確認することで問題を解決できました
function get_server_load($windows = 0) {
$os = strtolower(PHP_OS);
if(strpos($os, "win") === false) {
if(file_exists("/proc/loadavg")) {
$load = file_get_contents("/proc/loadavg");
$load = explode(' ', $load);
return $load;
}
elseif(function_exists("shell_exec")) {
$load = explode(' ', `uptime`);
return $load;
}
else {
return "";
}
}
}
for(... ... ...){
$data = get_server_load();
if($data[0] < 0.2){
// continue
}else{
sleep(1);
}
}
この機能は Windows でも動作するはずですが、保証はできません。Linux では、過去 1 分、5 分、15 分の負荷を含む配列が返されます。
また、スクリプト (CLI の場合) を低い優先順位 (Linux では「nice」を使用) で開始することを検討してください。
ループを続行する前に、Apache のアクティブなプロセスの数 (httpd.conf で mod_status を有効にしている場合は 127.0.0.1/server_status?auto ページを解析できます) や MySQL の状況 (アクティブな接続) など、他の値を使用することもできます。 ?)
cron エントリを変更して、次を使用してスクリプトを起動できますか? ニース?
良いアイデアではありません クライアントにサービスを提供し、データを分析するためにサーバーを使用します。
したがって、最終的な解決策を探している場合は、アプリケーションをいくつか再設計し、フロントエンドとライブ データベースからのデータ分析をこのタスク専用の別のシステムにオフロードします。
たとえアナライザーを正常に調整できたとしても、貴重なリソースが使い果たされなければ、ユーザーにサービスを提供できなくなります。
これは難しい変更かもしれませんが、データ構造をイテレータにリファクタリングする価値はあるかもしれません。また、コード内に循環参照がある場合は、これらのオブジェクトの設定を解除するclearReferences()のようなメソッドを提供します。ちなみに、この問題はPHP 5.3で解決されています。
したがって、次のものがある場合:
class Row
{
protected $_table;
public function __construct($table)
{
$this->_table = $table;
}
}
class Table
{
protected $_row;
public function __construct()
{
$this->_row = new Row($this);
}
}
ClearReferences() メソッドを Row クラスに追加します。
class Row
{
public function clearReferences()
{
$this->_table = null;
}
}
今のところ思いつくのはこれだけです。
nice を使用して同様の方法で cron から実行するスクリプトがたくさんあります。
0 * * * * 素晴らしい -n19 php myscript.php
これは RAM の使用率を改善しません (スクリプトの記述方法を変更するだけで改善できます)。そうでなければアイドル状態になる CPU を使用するだけです。
編集:質問が Windows 環境に関するものであることがわかりませんでした。申し訳ありません...同じ問題を抱えている *nix ユーザーのためにこれを残しておきます。
おそらく、スクリプトが一度に多くのことを実行しようとしているだけかもしれません。1 時間に 3 回実行した場合、効果は少なくなりますか?
別の解決策は、この種の「バックエンド」処理を実行するためだけに追加のサーバーをセットアップすることです。これは、データベースに過度の負荷をかけておらず、Web サーバーだけに負荷をかけている場合に特に効果的です。
さらに検討すべきもう 1 つのアプローチは、作業を別の方向に分割できるかどうかです。この種のスクリプトには、多くの小さな SQL ステートメントを生成するために使用される結果を生成するいくつかの大きな SQL ステートメントが含まれることがよくあります。後者をどこかに保存できれば、後のステップとしてデータベースに対して実行できます。このようなアプローチでは、バッファなしのクエリを使用して前処理データをフェッチすることもできるため、PHP コードによるメモリ消費を大幅に削減できる可能性があります。
サービス(Apache)がサービスとして実行されている場合は、Win Control Center /Servicesの優先順位設定を変更できます。とにかくCPUの使用は急増しますが、他のプログラムはスケジューラに優先されます。また、データベース/サーバーをアプリケーションとは異なるHDに配置してみてください。