Maison  >  Article  >  développement back-end  >  Pratique de réglage des performances de concurrence PHP (performances augmentées de 104 %)

Pratique de réglage des performances de concurrence PHP (performances augmentées de 104 %)

步履不停
步履不停original
2019-06-10 10:29:598506parcourir

Pratique de réglage des performances de concurrence PHP (performances augmentées de 104 %)

Contexte en affaires

Cadre et correspondant Environnement

  1. laravel5.7, mysql5.7, redis5, nginx1.15

  2. centos 7.5 bbr

  3. docker, docker-compose

  4. Alibaba Cloud 4C et 8G

Contexte du problème

php a activé opcache, laravel a également exécuté la commande d'optimisation pour l'optimisation et composer a également exécuté la commande dump-autoload.

La première chose à déclarer est qu'il doit y avoir des problèmes mineurs dans le environnement système (il est impossible d'améliorer des performances aussi importantes sans problèmes), mais ces problèmes, si vous n'utilisez pas les outils appropriés, pourraient ne pas être découverts de votre vivant

Cet article se concentre sur la façon de les découvrir. problèmes et comment les trouver. L'idée.

Nous trouvons d'abord une API ou une fonction appropriée dans le système pour amplifier le problème.

Cette API a été conçue à l'origine pour effectuer des contrôles de santé pour la charge nginx. équilibrage. Utilisez ab -n 100000 -c 1000 pour les tests de stress et constatez que les qps ne peuvent atteindre que 140 fois par seconde.

Nous savons que les performances de Laravel sont notoirement mauvaises, mais ce n'est pas le cas dans cette mesure. l'API ne devrait pas être si basse, alors j'ai décidé de le découvrir.

 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);
    }

Manifestations de problèmes et idées de dépannage

top

La commande top a révélé que le processeur du système était occupé à 100 % Parmi eux, le mode utilisateur représente 80 % et le mode noyau 20 %. Il semble qu'il n'y ait pas de gros problème. Il y a un endroit qui semble étrange. Le résultat de l'exécution de la commande top

下载 (2).jpg

est que certains processus php-fpm sont en état de veille, mais l'utilisation du processeur atteint toujours près de 30 %. Lorsqu'un processus est en état de veille, il occupe encore beaucoup de CPU. Ne doutez pas qu'il s'agisse d'un problème avec le processus. Jetons un coup d'œil à la page de manuel de la commande Ttop. Cela signifie à peu près que cette occupation est la dernière fois que l'occupation du processeur du processus est lorsque l'écran est actualisé. Parce que lorsque la commande top collecte des informations, Linux peut planifier de force le processus (par exemple, il est utilisé pour collecter des informations sur le processus avec top), donc. à ce moment (au moment où l'écran est rafraîchi), certains processus php-fpm sont en état de veille, ce qui est compréhensible, cela ne devrait donc pas être un problème avec php-fpm

pidstat.

Sélectionnez d'abord un processus php-fpm, puis utilisez pidstat pour afficher l'état d'exécution détaillé du processus

Rien d'inhabituel n'a été trouvé pendant le processus, et l'exécution les résultats de la commande supérieure sont fondamentalement les mêmes.

下载 (3).jpg

vmstat

Conservez la mesure de pression et exécutez vmstate pour vérifier à l'exception du commutateur de contexte (commutateur de contexte) qui est. un peu élevé, je ne vois pas beaucoup d'anomalies. Étant donné que Docker, Redis et MySQL que nous utilisons fonctionnent tous sur la même machine, un CS d'environ 7 000 est toujours une plage raisonnable, mais l'IN (interruption) est un peu trop élevé, atteignant environ 14 000. Il doit y avoir quelque chose qui le déclenche.

下载 (4).jpgNous savons que les interruptions incluent les interruptions matérielles et les interruptions logicielles. Les interruptions matérielles sont des signaux d'interruption envoyés par du matériel tel que les cartes réseau et les souris, et le processeur arrête immédiatement ce qu'il fait. . Les signaux d'interruption de processus. Les interruptions logicielles sont émises par le système d'exploitation et sont souvent utilisées pour la planification forcée des processus

Vmstat et pidstat ne sont que de nouveaux outils de détection. Nous lisons les informations sur les interruptions du système à partir du fichier en lecture seule /proc/interrupts pour déterminer exactement la cause de l'augmentation des interruptions. Utilisez la commande watch -d pour déterminer les interruptions qui changent le plus fréquemment.

%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.

.

下载 (5).jpgNous avons constaté que les interruptions de reprogrammation changent le plus rapidement. Il s'agit de l'interruption de reprogrammation (RES). Ce type d'interruption consiste à réveiller le processeur inactif pour planifier l'exécution de nouvelles tâches. Il s'agit du mécanisme utilisé par le planificateur pour répartir les tâches entre différents processeurs dans les systèmes multiprocesseurs (SMP). Il est également communément appelé interruptions inter-processeurs (IPI). En combinant les commandes dans vmstat, nous pouvons déterminer que l'une des raisons du faible qps est due à un trop grand nombre de processus en compétition pour le processeur. Nous ne savons pas encore de quoi il s'agit, une enquête plus approfondie est donc nécessaire

<.>strace

strace peut afficher les appels système. Nous savons que lors de l'utilisation des appels système, le système passe en mode noyau. En affichant l'appel système php-fpm, vérifiez. notre conjecture

下载 (6).jpg果然, 发现大量的stat系统调用, 我们猜想, 是opcache在检查文件是否过期导致的. 我们通过修改opcache的配置, 让opcache更少的检查文件timestamp, 减少这种系统调用

 opcache.validate_timestamps="60"
    opcache.revalidate_freq="0"

再次执行ab命令进行压测

下载 (7).jpg果然qps直接涨到了205, 提升非常明显, 有接近 46% 的提升

perf

现在任然不满足这个性能, 希望在更多地方找到突破口. 通过

perf record -g
perf report -g

看到系统的分析报告

下载 (8).jpg

我们看到, 好像这里面有太多tcp建立相关的系统调用(具体是不是我还不清楚, 请大神指正, 但是看到send, ip, tcp啥的我就怀疑可能是tcp/ip相关的问题).

我们怀疑两种情况

  1. 与mysql, redis重复大量的建立TCP连接, 消耗资源

  2. 大量请求带来的tcp连接

先说第一个, 经过检查, 发现数据库连接使用了php-fpm的连接池, 但是redis连接没有, redis用的predis, 这个是一个纯PHP实现, 性能不高, 换成了phpredis:

打开laravel的config/database.php文件, 修改redis的driver为phpredis, 确保本机已安装php的redis扩展. 另外由于Laravel自己封装了一个Redis门面, 而恰好redis扩展带来的对象名也叫Redis. 所以需要修改Laravel的Redis门面为其他名字, 如RedisL5.

再次进行压测

下载 (9).jpg

达到了喜人的286qps, 虽然和其他主打高性能的框架或者原生php比, 还有很高的提升空间(比如Swoole), 但是最终达到了104%的提升, 还是很有意义的

总结

  1. 我们通过top, 发现系统CPU占用高, 且发现确实是php-fpm进程占用了CPU资源, 判断系统瓶颈来自于PHP.

  2. 接着我们通过pidstat, vmstat发现压测过程中, 出现了大量的系统中断, 并通过 watch -d cat /proc/interrupts 发现主要的中断来自于重调度中断(RES)

  3. 通过strace查看具体的系统调用, 发现大量的系统调用来自于stat, 猜测可能是opcache频繁的检查时间戳, 判断文件修改. 通过修改配置项, 达到了46%的性能提升

  4. 最后再通过perf, 查看函数调用栈, 分析得到, 可能是大量的与redis的TCP连接带来不必要的资源消耗. 通过安装redis扩展, 以及使用phpredis来驱动Laravel的redis缓存, 提升性能, 达到了又一次近50%的性能提升.

  5. 最终我们完成了我们的性能提升104%的目标

推荐教程:网站高并发架设基础教程

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Article précédent:Dockerfile crée une image PHPArticle suivant:Dockerfile crée une image PHP