事業背景
フレームワークと対応環境
#php は opcache を有効にし、laravel は最適化のために optimize コマンドも実行し、composer は dump-autoload コマンドも実行しました。
最初に宣言することは、システム環境に小さな問題があるに違いないということです。 (これほど大きなパフォーマンスを問題なく改善することは不可能です) しかし、これらの問題は、適切なツールを使用しないと一生発見できない可能性があります。この記事では、これらの問題を発見する方法に焦点を当てます。アイデアとその見つけ方。まず、問題を拡大するためにシステム内で適切な API または関数を見つけます。この API は、もともと nginx ロード バランシングのヘルス チェックを行うために設計されました。 ストレス テストに ab -n 100000 -c 1000 を使用すると、qps が 1 秒あたり 140 回までしか到達できないことがわかります。Laravel のパフォーマンスが悪いことで有名であることはわかっていますが、そこまでではないようです。 API はそれほど低くないはずです。そこで、調べることにしました。public function getActivateStatus() { try { $result = \DB::select('select 1'); $key = 1; if ($result[0]->$key !== 1) { throw new \Exception("mysql 检查失败"); } } catch (\Exception $exception) { \Log::critical("数据库连接失败: {$exception->getMessage()}", $exception->getTrace()); return \response(null, 500); } try { Cache::getRedis()->connection()->exists("1"); } catch (\Exception $exception) { \Log::critical("缓存连接失败: {$exception->getMessage()}", $exception->getTrace()); return \response(null, 500); } return \response(null, 204); }
# を実行した結果、php-fpm プロセスの一部はスリープ状態になりますが、CPU 使用率は依然として 30% 近くに達します。 プロセスがスリープ状態であっても、多くの CPU を占有します。プロセスに問題があるかどうかは疑わないでください。Ttop コマンドのマニュアル ページを見てみましょう。
%CPU -- CPU usage The task's share of the elapsed CPU time since the last screen update, expressed as a percentage of total CPU time.
プロセス中に異常なものは何も見つかりませんでした。実行結果
vmstatストレス テストの圧力を維持し、vmstate を実行して確認します。コンテキスト スイッチ (コンテキスト スイッチ) を除いて、少し高いですが、あまり異常は見られません。 使用している docker、redis、mysql はすべて同じマシン上で実行されているため、CS は約 7,000 がまだ妥当な範囲ですが、IN (中断) は約 14,000 に達しており、少し高すぎます。何かトリガーがあるはずです。割り込み.
割り込みにはハード割り込みとソフト割り込みがあることがわかっています。ハード割り込みは、ネットワーク カードやマウスなどのハードウェアによって送信される割り込み信号であり、CPU はその割り込みを即座に停止します。プロセス割り込み信号。ソフト割り込みはオペレーティング システムによって発行され、プロセスの強制スケジューリングによく使用されます。
vmstat と pidstat は両方とも新しいパフォーマンス検出ツールにすぎません。特定の割り込みを誰が発行したかはわかりません。 . . 読み取り専用ファイル /proc/interrupts からシステムの割り込み情報を読み取り、割り込み増加の正確な原因を取得します。watch -d コマンドを使用して、最も頻繁に変化する割り込みを特定します。
watch -d cat /proc/interrupts
その中で、再スケジュール割り込みが最も速く変化することがわかりました。これは再スケジュール割り込み (RES) です。この割り込みタイプは、アイドル状態の CPU をウェイクアップして、新しいタスクの実行をスケジュールすることを意味します。これは、マルチプロセッサ システム (SMP) 内の異なる CPU にタスクを分散するためにスケジューラによって使用されるメカニズムであり、一般にプロセッサ間割り込み (IPI) とも呼ばれます。 vmstat のコマンドを組み合わせると、QPS が低い原因の 1 つは、CPU を獲得しようと競合するプロセスが多すぎることが原因であると判断できます。それが何であるかはまだわかりません。したがって、さらなる調査が必要です。
stracestrace はシステム コールを表示できます。システム コールを使用すると、システムがカーネル モードになることがわかっています。このプロセスはソフト割り込みを生成します。php-fpm システム コールを表示することで、検証します。私たちの推測
果然, 发现大量的stat系统调用, 我们猜想, 是opcache在检查文件是否过期导致的. 我们通过修改opcache的配置, 让opcache更少的检查文件timestamp, 减少这种系统调用
opcache.validate_timestamps="60" opcache.revalidate_freq="0"
再次执行ab命令进行压测
果然qps直接涨到了205, 提升非常明显, 有接近 46% 的提升
perf
现在任然不满足这个性能, 希望在更多地方找到突破口. 通过
perf record -g perf report -g
看到系统的分析报告
我们看到, 好像这里面有太多tcp建立相关的系统调用(具体是不是我还不清楚, 请大神指正, 但是看到send, ip, tcp啥的我就怀疑可能是tcp/ip相关的问题).
我们怀疑两种情况
与mysql, redis重复大量的建立TCP连接, 消耗资源
大量请求带来的tcp连接
先说第一个, 经过检查, 发现数据库连接使用了php-fpm的连接池, 但是redis连接没有, redis用的predis, 这个是一个纯PHP实现, 性能不高, 换成了phpredis:
打开laravel的config/database.php文件, 修改redis的driver为phpredis, 确保本机已安装php的redis扩展. 另外由于Laravel自己封装了一个Redis门面, 而恰好redis扩展带来的对象名也叫Redis. 所以需要修改Laravel的Redis门面为其他名字, 如RedisL5.
再次进行压测
达到了喜人的286qps, 虽然和其他主打高性能的框架或者原生php比, 还有很高的提升空间(比如Swoole), 但是最终达到了104%的提升, 还是很有意义的
总结
我们通过top, 发现系统CPU占用高, 且发现确实是php-fpm进程占用了CPU资源, 判断系统瓶颈来自于PHP.
接着我们通过pidstat, vmstat发现压测过程中, 出现了大量的系统中断, 并通过 watch -d cat /proc/interrupts 发现主要的中断来自于重调度中断(RES)
通过strace查看具体的系统调用, 发现大量的系统调用来自于stat, 猜测可能是opcache频繁的检查时间戳, 判断文件修改. 通过修改配置项, 达到了46%的性能提升
最后再通过perf, 查看函数调用栈, 分析得到, 可能是大量的与redis的TCP连接带来不必要的资源消耗. 通过安装redis扩展, 以及使用phpredis来驱动Laravel的redis缓存, 提升性能, 达到了又一次近50%的性能提升.
最终我们完成了我们的性能提升104%的目标
推荐教程:网站高并发架设基础教程
以上がPHP 同時実行パフォーマンスのチューニングの実践 (パフォーマンスが 104% 向上)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。