最近のプロジェクトでは、タスクを処理するためにデーモンがバックグラウンドで実行されました。以前は問題はありませんでしたが、タスクの処理時間やその他の監視レポートが増加した後、デーモンのマシンに平均 20 を超える高負荷が発生し、タスクのバックログが発生しました。
最初のステップは、strace を使用してシステムコールをチェックすることです:
strace -tt -T -c -p 31420
strace -c は、システム時間が主にシステムのシグナルである rt_sigprocmask に費やされていることを発見しました。シールド関数。信号処理プログラムが中断されないように信号をシールドするために信号処理プログラムで一般的に使用されます。 rt_sigprocmask は Linux のシステム コール関数であり、外部から直接呼び出されるのではなく、glibc を使用してカプセル化されます: sigprocmask.
さらなる starce 呼び出しの実際の状況:
rt_singprocmask 呼び出しにはマスク ワードの設定という特徴があります。そしてマスクワードを復元するということは、PHPの信号処理関数で呼び出されるのではないかと考えられます。
PHP ソース コードで sigprocmask を検索すると、PHP ソース コードで singprocmask が呼び出される場所は主に pnctl 拡張機能内にあることがわかります。pnctl 拡張機能は、子プロセスを作成および管理するためにデーモン プログラムで使用されます。まず信号をブロックしてから信号特性を復元することにより、PHP 信号処理関数 pcntl_signal_dispatch() を見つけます。
次に、ログを追加して関数が実際に頻繁に呼び出されていることを確認することで、アイデアを検証します。これは、PHP の信号処理メカニズムの解析につながります。
スペースの制限のため、具体的な分析プロセスは省略します。 分析の結果は次のとおりです:
phpmanulによるティックの説明は次のとおりです:
ティックは、のために発生するイベントです。宣言ブロック内のパーサーによって実行される N 個の低レベルのティック可能なステートメント。 N の値は、宣言ブロックのディレクティブ セクション内で Ticks=N を使用して指定されます。
通常、すべてのステートメントがティック可能であるわけではありません。
各ティックで発生するイベントは register_tick_function() を使用して指定されます。詳細については、各ティックに対して複数のイベントが発生する可能性があることに注意してください。
おそらく次のことを意味します。協力、tick=n を持つ n 個の基礎となる命令が実行されるたびに、register_tick_function によって登録されたイベントがトリガーされます。
2. PHP のシグナルの処理:
PHP のプロセスとシグナルの管理と制御は、pcntl 拡張機能を介して実装されます。pcntl は、コールバックが発生する場所でのコールバックの発生を許可するために、declare を使用します。 PHP では許可されています。
pcntl ソースコードを分析すると、pcntl の信号処理メカニズムは次のようになります:
1)、信号登録
2)、信号処理:
これを分析すると、次のことができます。参照: PHP では、declare で宣言された Tick 値に従って定期的に呼び出されます。Tick 値が低く設定されている場合 (このプログラムでは Ticks=1 が定義されています)、この中で rt_sigprocmask を呼び出すと、多数のシグナル ハンドラーがトリガーされます。プログラムは多くの CPU とマシンを浪費し、負荷が高くなります。
それでは、なぜ PHP はこの信号処理メカニズムを使用するのでしょうか?
PHP マニュアルをチェックしているときに、次の紹介を見つけました:
PCNTL は、シグナル ハンドル コールバック メカニズムとしてティックを使用するようになりました。これは、以前のメカニズムよりもはるかに高速です。この変更は、「ユーザー ティック」を使用する場合と同じセマンティクスに従います。 declare() ステートメントを使用して、プログラム内でコールバックの発生を許可する場所を指定すると、非同期イベントを処理するオーバーヘッドを最小限に抑えることができます。これまでは、pcntl を有効にして PHP をコンパイルすると、常にこのオーバーヘッドが発生していました。スクリプトが実際に pcntl を使用したわけではありません。
注目してください。declare() ステートメントを使用して、プログラム内でコールバックの発生を許可する場所を指定します。これは、信号をキャプチャする必要があるコード領域を指定できることを意味します。エリア外では信号処理は行われません。
上記から、問題を修正する方法を要約できます:
1)、宣言を使用してアプリケーションが信号をキャプチャする領域を指定します。
2) シグナル処理を必要としないプログラムの場合は、シグナル ハンドラーの呼び出しをトリガーしない declear (ticks=n) を宣言しないでください。処理が必要なプログラムは、PHP のタイミング検出の代わりにシグナル ハンドラー pcntl_signal_dispatch を手動で呼び出すことができます。 。
上記のいずれかの方法で問題を解決できることが確認されています。マシンの負荷が通常の値に低下します。
概要:
1)、PHP は同様の Linux カーネル割り込み処理メカニズム (ハード割り込み + ソフトターミナル) を使用して信号を処理し、CPU パフォーマンスの無駄を避けるために信号検出の頻度に注意を払う必要があります。
2)、PCNTL拡張機能を使用してCGIの作成プロセスを管理することをお勧めしないため、このメカニズムはWebサーバーのCGIに影響を与えません。