カスタムビルドのCMSのようなアプリケーションを管理しています。
ドキュメントが送信されるたびに、いくつかのタスクが実行されます。これらのタスクは、大まかに次のカテゴリに分類できます。
カテゴリ1には、ドキュメントのコンテンツに関連するさまざまなMySQLテーブルの更新が含まれます。
カテゴリ2には、いくつかの自動アンカータグ変換を実行するためのMySQL LONGTEXTフィールドに格納されたHTMLコンテンツの解析が含まれます。このタスクにはかなりの計算時間が費やされていると思います。
カテゴリ3には、ドキュメントに対応する少数のフィールドのみを使用した、単純なMySQLベースの検索インデックスの更新が含まれます。
ドキュメントの提出が完了したと見なされるには、これらのタスクをすべて完了する必要があります。
このアプリケーションをホストするマシンには、デュアルクアッドコアXeonプロセッサ(合計8コア)が搭載されています。ただし、ドキュメントが送信されるたびに、実行されるすべてのPHPコードは、コアの1つで実行される単一のプロセスに制限されます。
私の質問:
PHP/MySQL Webアプリケーションの処理負荷を複数のCPUコアに分割するために使用したスキームはありますか?私の理想的なソリューションは、基本的にいくつかのプロセスを生成し、それらをいくつかのコアで並列に実行し、すべてのプロセスが完了するまでブロックします。
関連する質問:
お気に入りのPHP=パフォーマンスプロファイリングツール?
PHPはマルチスレッド向けではありません。既にお気づきのように、各ページは1つのPHPプロセスによって処理されます。クエリはデータベースサーバーで実行されます。
残念ながら、それに対してできることはあまりありません。それはPHPが機能する方法です。
それでも、いくつかの考えがあります。
したがって、実際には、サーバーの8コアが使用されることになります;-)
そして、ページの生成に時間がかかりすぎると思われる場合、考えられる解決策は、計算を2つのグループに分けることです。
私の2番目のポイントのような状況では、あなたはそれらのことをすぐに行う必要はありません...まあ、ただすぐにそれらをしないでください;-)
私がよく使用する解決策は、キューイングメカニズムです。
また、他のいくつかの操作については、X分ごとに実行したいだけです。ここでも、cronjobは完璧なツールです。
PHPには完全な マルチスレッド がサポートされており、さまざまな方法で最大限に活用できます。さまざまな例でこのマルチスレッド機能を実証できました。
クイック検索 は追加のリソースを提供します。
MySQLは完全にマルチスレッド であり、オペレーティングシステムがそれらをサポートしている場合、複数のCPUを使用します。パフォーマンス用に適切に構成されていれば、システムリソースを最大化します。
スレッドのパフォーマンスに影響するmy.ini
の典型的な設定は次のとおりです。
thread_cache_size = 8
thread_cache_size は、多くの新しい接続がある場合にパフォーマンスを向上させるために増やすことができます。通常、これは、適切なスレッド実装がある場合、顕著なパフォーマンスの改善を提供しません。ただし、サーバーが毎秒数百の接続を認識している場合、通常、thread_cache_sizeを十分に高く設定して、ほとんどの新しい接続がキャッシュされたスレッドを使用するようにします。
Solaris を使用している場合は、次を使用できます。
thread_concurrency = 8
thread_concurrency を使用すると、アプリケーションはスレッドシステムに、同時に実行する必要のあるスレッドの数に関するヒントを与えることができます。
この変数はMySQL 5.6.1で廃止され、MySQL 5.7で削除されました。 Solaris 8以前の場合を除いて、MySQL構成ファイルからこれを削除する必要があります。
InnoDB::
Innodb を使用している場合、このような制限はありません
innodb_thread_concurrency // Recommended 2 * CPUs + number of disks
innodb_read_io_threads
とinnodb_write_io_threads
を確認することもできます。デフォルトは4
で、ハードウェアに応じて64
まで増やすことができます
その他:
見るべき他の構成には、key_buffer_size
、table_open_cache
、sort_buffer_size
などがあります。これらはすべて、より良いパフォーマンスをもたらします。
PHP:
Pure PHPでは、各クエリが別々のPHPスレッドで実行されるMySQLワーカーを作成できます
$sql = new SQLWorker($Host, $user, $pass, $db);
$sql->start();
$sql->stack($q1 = new SQLQuery("One long Query"));
$sql->stack($q2 = new SQLQuery("Another long Query"));
$q1->wait();
$q2->wait();
// Do Something Useful
このタスクにはかなりの計算時間が費やされていると思います。
すでに問題を知っている場合は、イベントループ、ジョブキュー、またはスレッドを使用して簡単に解決できます。
1つのドキュメントを1つずつ処理することは、非常に、非常に遅く、痛みを伴うプロセスです。 @ ka ajaxを使用して複数のリクエストを呼び出す方法をハックすると、一部のクリエイティブマインドは pcntl_fork を使用してプロセスを分岐しますが、windows
を使用している場合pcntl
を利用することはできません
ウィンドウとUnixシステムの両方をサポートするpThreads
を使用すると、このような制限はありません。 ..と同じくらい簡単です。100ドキュメントを解析する必要がある場合100スレッドを生成する...シンプル
HTMLスキャン
// Scan my System
$dir = new RecursiveDirectoryIterator($dir, RecursiveDirectoryIterator::SKIP_DOTS);
$dir = new RecursiveIteratorIterator($dir);
// Allowed Extension
$ext = array(
"html",
"htm"
);
// Threads Array
$ts = array();
// Simple Storage
$s = new Sink();
// Start Timer
$time = microtime(true);
$count = 0;
// Parse All HTML
foreach($dir as $html) {
if ($html->isFile() && in_array($html->getExtension(), $ext)) {
$count ++;
$ts[] = new LinkParser("$html", $s);
}
}
// Wait for all Threads to finish
foreach($ts as $t) {
$t->join();
}
// Put The Output
printf("Total Files:\t\t%s \n", number_format($count, 0));
printf("Total Links:\t\t%s \n", number_format($t = count($s), 0));
printf("Finished:\t\t%0.4f sec \n", $tm = microtime(true) - $time);
printf("AvgSpeed:\t\t%0.4f sec per file\n", $tm / $t);
printf("File P/S:\t\t%d file per sec\n", $count / $tm);
printf("Link P/S:\t\t%d links per sec\n", $t / $tm);
出力
Total Files: 8,714
Total Links: 105,109
Finished: 108.3460 sec
AvgSpeed: 0.0010 sec per file
File P/S: 80 file per sec
Link P/S: 907 links per sec
使用クラス
Sink
class Sink extends Stackable {
public function run() {
}
}
LinkParser
class LinkParser extends Thread {
public function __construct($file, $sink) {
$this->file = $file;
$this->sink = $sink;
$this->start();
}
public function run() {
$dom = new DOMDocument();
@$dom->loadHTML(file_get_contents($this->file));
foreach($dom->getElementsByTagName('a') as $links) {
$this->sink[] = $links->getAttribute('href');
}
}
}
実験
スレッドのない8,714
リンクを持つ105,109
ファイルを解析して、どれくらい時間がかかるかを確認してください。
より良いアーキテクチャ
あまりにも多くのスレッドを生成することは、実稼働環境で行うのは賢明なことではありません。より良いアプローチは、 Pooling を使用することです。定義のプールを持っている Workers then stack with Task
パフォーマンスの改善
結構です、上の例はまだ改善できます。システムが単一のスレッドですべてのファイルをスキャンするのを待つ代わりに、複数のスレッドを使用してシステムでファイルをスキャンし、データを処理のためにワーカーにスタックすることができます
これは最初の回答でほぼ回答されていますが、パフォーマンスを改善する方法は非常に多くあります。イベントベースのアプローチを検討したことがありますか?
@ rdlowrey 引用1:
よくこのように考えてください。 Webアプリケーションで同時に接続された10,000のクライアントにサービスを提供する必要があると想像してください。従来の要求ごとのスレッドまたは要求ごとのプロセスサーバーarenスレッドがどれほど軽量であっても、一度に10,000個のスレッドを開いたままにできないので、オプションではありません。
@ rdlowrey 引用2:
一方、すべてのソケットを単一のプロセスに保持し、それらのソケットが読み取り可能または書き込み可能になるのをリッスンする場合、サーバー全体を単一のイベントループ内に配置し、読み取り/書き込みが必要な場合にのみ各ソケットを操作できます。
問題に対するevent-driven
、non-blocking I/O
アプローチを試してみませんか。 PHP has libevent は、アプリケーションを過給します。
この質問はすべてMulti-Threading
ですが、時間があれば、これを見ることができます Nuclear Reactor written in PHP by @ igorw
いくつかのタスクでCache
とJob Queue
の使用を検討すべきだと思います。あなたは簡単に言うメッセージを持つことができます
Document uploaded for processing ..... 5% - Done
その後、バックグラウンドですべての時間を無駄にします。同様のケーススタディについては、 大きな処理ジョブを小さくする をご覧ください。
プロファイリングツール? Xdebug から Yslow までのWebアプリケーション用の単一のプロファイルツールはありません。これらはすべて非常に便利です。例えば。 Xdebugはサポートされていないため、スレッドに関しては役に立ちません。
お気に入りがありません
Webサーバーのスケールアウトは、マルチコアCPUへのアクセスに関して、MySQLを1インチ動かしません。どうして?まず、MySQLの2つの主要なストレージエンジンを検討します。
このストレージエンジンは、複数のコアにアクセスしません。それは決して持っていないし、決してしません。 INSERT、UPDATE、およびDELETEごとにテーブル全体をロックします。 MyISAMで何かをするために複数のWebサーバーからクエリを送信すると、ボトルネックになります。
MySQL 5.1.38より前では、このストレージエンジンは1つのCPUのみにアクセスしていました。 1台のマシンでMySQLを複数回実行して、コアを強制してMySQLの異なるインスタンスを処理する のような奇妙なことをしなければなりませんでした。次に、WebサーバーのDB接続を複数のインスタンス間で負荷分散します。これは古い学校です(特に、MySQl 5.1.38より前のバージョンのMySQLを使用している場合)。
MySQL 5.1.38以降では、新しいInnoDBプラグインをインストールします。 InnoDBが複数のCPUにアクセスするために調整する必要がある機能があります。これについてはDBA StackExchangeで書きました。
Sep 20, 2011
: マルチコアとMySQLパフォーマンスSep 12, 2011
: MySQLに複数のコアを使用させることは可能ですか?May 26, 2011
: シングルスレッドデータベースとマルチスレッドデータベースのパフォーマンスについてこれらの新機能は、MySQL 5.5/5.6およびPercona Serverでも完全に利用可能です。
カスタムCMSがFULLTEXTインデックス作成/検索を使用している場合、InnoDBがFULLTEXTインデックス作成/検索をサポートするようになったため、MySQL 5.6にアップグレードする必要があります。
MySQL 5.6にインストールしても、CPUは自動的に動作しません。構成を変更しないと、古いバージョンのMySQLが新しいバージョンを実行し、新しいバージョンをアウトアウトする可能性があるため、調整する必要があります。
Nov 24, 2011
: mysql 5.5が5.1より遅い(linux、mysqlslapを使用)Oct 05, 2011
: 一部の新しいMySQLバージョンではクエリが長時間実行されますJun 19, 2011
: MySQLベイクオフを適切に実行するにはどうすればよいですか?これはあなたが探している質問への答えではないかもしれませんが、あなたが求める解決策はスレッド化を扱っています。スレッド化はマルチコアプログラミングに必要であり、スレッド化はnotPHPで実装されています。
しかし、ある意味では、オペレーティングシステムのマルチタスク機能に依存することで、PHPのスレッドを偽造することができます。 PHP のマルチスレッド戦略により、必要なものを達成するための戦略を開発できます。
デッドリンク: PHPのマルチスレッド化戦略
考えているときに皆さんに知らせる: "poor PHPにはマルチスレッドがありません"
まあ... Pythonには実際のマルチスレッドもありません 。 NodeJSはマルチスレッドをサポートしていません 。 Javaにはマルチスレッドのようなものがありますが、それでも コードによってはマシン全体が停止する 。
しかし、1つの事柄を大々的にプログラミングしない限り、それは無関係です。多くのリクエストがページにヒットし、各リクエストは独自の単一スレッドで独自のプロセスを生成するため、すべてのコアが使用されます。