从并发20到并发120之laravel性能优化

news2024/9/24 19:27:33

调优成果

遇到问题

单台服务并发20,平均响应时间1124ms,通过htop观察,发现cpu占用率达到100%(包括sleep的进程),内存几乎没怎么用。
在这里插入图片描述

调优后

单机最大吞吐量达到120 响应时长不超过1000ms
在这里插入图片描述

硬件信息

操作系统: Linux 系统版本为 CentOS 8
CPU:4核 3.20GHz
内存:8GB

[work@test-mapi ~]$ uname -a
Linux test-mapi 4.18.0-305.10.2.el8_4.x86_64 #1 SMP Tue Jul 20 17:25:16 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux
[work@test-mapi ~]$ 
[work@test-mapi ~]$ lscpu
Architecture:        x86_64
CPU op-mode(s):      32-bit, 64-bit
Byte Order:          Little Endian
CPU(s):              4
On-line CPU(s) list: 0-3
Thread(s) per core:  2
Core(s) per socket:  2
Socket(s):           1
NUMA node(s):        1
Vendor ID:           GenuineIntel
CPU family:          6
Model:               106
Model name:          Intel(R) Xeon(R) Platinum 8372C CPU @ 3.20GHz

[work@test-mapi ~]$ free -h
              total        used        free      shared  buff/cache   available
Mem:          7.5Gi       1.5Gi       1.7Gi        33Mi       4.2Gi       5.6Gi
Swap:            0B          0B          0B

应用环境

PHP:7.3

[work@test-mapi mapi]$ php artisan 
Laravel Framework 6.20.44
[work@test-mapi ~]$ php -v
PHP 7.3.30 (cli) (built: Sep 23 2021 16:03:45) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.3.30, Copyright (c) 1998-2018 Zend Technologies

探索方案

开启opcache

OPcache 是 PHP 的一个扩展,用于加速 PHP 脚本的执行。它通过将 PHP 脚本的编译结果(即opcode)缓存起来,从而避免每次请求都重新编译脚本,提高性能。
在php.ini内开启opcache,相关参数如下:

[dba]
;dba.default_handler=

[opcache]

opcache.enable=1 ; 启用 OPCache
opcache.enable_cli=1 ; 在命令行模式下也启用 OPCache
opcache.jit=tracing ; 启用 JIT 跟踪模式,根据执行情况动态编译热点代码
opcache.jit_buffer_size=256M ;JIT 编译保留的内存大小
opcache.memory_consumption=512M ; OPCache 可使用的内存大小
opcache.interned_strings_buffer=64M ; 用于存储内部字符串的缓冲区大小
opcache.max_accelerated_files=10000 ; 缓存的最大文件数量
opcache.revalidate_freq=60 ; OPcache 每隔 60 秒会检查一次脚本文件是否有修改。默认值通常为 20则认为是每次启动都检查文件是否修改,会增加IO操作,影响性能够 ,这个参数只有在 opcache.validate_timestamps=1 的情况下才有效
opcache.validate_timestamps=1;启用文件变更检查  0禁用文件变更检查
opcache.fast_shutdown=1 ; 快速关闭,提高性能
opcache.save_comments=1 ; 保存注释,某些框架或应用可能依赖注释

开启了opcache之后,每秒的吞吐量达到了70。

php-fmp 静态模式

通过htop观察发现,内存使用率很少,说明内存并不是laravel的瓶颈,考虑增加php-fmp的工作池

emergency_restart_threshold = 30;60s内超过 30PHP-FPM 进程因出现异常(如段错误)而退出,那么 PHP-FPM 主进程会自动重启
emergency_restart_interval = 60s;配合第一个选项使用
process_control_timeout = 5s;停止php-fmp的时候,如果子进程超过5s未响应,则强制终止
daemonize = yes;后台运行
process.max = 500;限制 PHP-FPM 可以生成的最大进程数。这个配置项定义了整个 PHP-FPM 服务的上限,而不是单个工作池的限制。
;;;;;;;;;;;;;;;;;;;;
; Pool Definitions ;
;;;;;;;;;;;;;;;;;;;;

[work]
pm = static;设置了 PHP-FPM 的进程管理模式为静态(static),即总是启动固定数量的子进程
pm.max_children = 200; 定义了静态模式下 PHP-FPM 工作池可以生成的最大子进程数,即始终有 200 个子进程等待处理请求。
pm.start_servers = 20;这些参数用于动态模式下,控制 PHP-FPM 启动时的初始子进程数
pm.min_spare_servers = 20;
pm.max_spare_servers = 300
pm.max_requests = 10240;每个子进程在处理完 10240 个请求后会自动重启。这有助于防止内存泄漏问题。
pm.process_idle_timeout = 5s;动态模式下,闲置进程在超过 5 秒没有处理请求后被终止。在静态模式下无效。
request_terminate_timeout = 120;强制终止执行时间超过 120 秒的请求。用于防止超长时间执行的脚本占用系统资源。
request_slowlog_timeout = 2;慢请求的阈值(2 秒)。如果请求执行时间超过这个值,PHP-FPM 会将其记录到慢日志中。
slowlog = /data/logs/php/slow.log
rlimit_files = 51200;设置了 PHP-FPM 子进程可以打开的最大文件描述符数量。这影响 PHP-FPM 可以同时处理的文件数。
rlimit_core = 0;设置 PHP-FPM 子进程可以生成的 core dump 文件的最大大小(以字节为单位)。0 表示禁用 core dump。

重启php-fmp

sudo systemctl restart php-fpm

phpredis

Laravel 自己封装了一个 Redis,叫predis,当我们用laravel自带的Redis Facade,那么每次调用redis都需要编译这个Redis组件,而且是不支持连接池的。但是PHP有一个由c编写的一个PHP扩展比它效率更高,保证服务器安装了php的Redis扩展,我们就可以改写predis,修改驱动为phpredis。

框架内的优化

在php-fmp的进程里面,running的进程不超过30个,而sleep的有时候可以达到300多。
于是考虑是发生了系统调用导致部分子进程sleep。找到一个sleep的进程的pid,执行命令sudo strace -p 487143;相关输出如下

openat(AT_FDCWD, "/data/backend/mapi/vendor/nesbot/carbon/src/Carbon/CarbonTimeZone.php", O_RDONLY) = 11
fstat(11, {st_mode=S_IFREG|0775, st_size=8734, ...}) = 0
fstat(11, {st_mode=S_IFREG|0775, st_size=8734, ...}) = 0
fstat(11, {st_mode=S_IFREG|0775, st_size=8734, ...}) = 0
mmap(NULL, 8734, PROT_READ, MAP_SHARED, 11, 0) = 0x7fe191b5a000
munmap(0x7fe191b5a000, 8734)            = 0
close(11)                               = 0
lstat("/data/backend/mapi/storage/framework/sessions/kIiKqblIWBkWiyyxxCRjHiIEtfr5Q0iId5JYdB3S", 0x7ffc68443b70) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/data/backend/mapi/storage/framework/sessions/kIiKqblIWBkWiyyxxCRjHiIEtfr5Q0iId5JYdB3S", O_WRONLY|O_CREAT, 0666) = 11

关闭session

发现有对session的写操作,打开laravel,发现session的驱动是通过file驱动的,因为我们没有用session ,所以打算关闭session ,设置drive为array,当然,有其他非必要的中间件也可以删除
mapi/config/session.php

//    'driver' => env('SESSION_DRIVER', 'file'),
    'driver' => 'array',

关闭Http/Kernel.php中的session,包括csrftoken等文件

//            \Illuminate\Session\Middleware\StartSession::class,
//            \Illuminate\Session\Middleware\AuthenticateSession::class,
//            \Illuminate\View\Middleware\ShareErrorsFromSession::class,
//            \App\Http\Middleware\VerifyCsrfToken::class,

composer

在composer里面,可能有很多没用到的组件,在项目启动时也会被加载,导致项目启动慢,我删除了debug相关的组件。

关闭debug

在env文件中,有的会开启APP_DEBUG=true,

利用laravel的缓存提升效率

我们可以把配置信息,路由信息等缓存起来,artisan提供了相关的方法

hp artisan config:cache 
配置缓存

php artisan route:cache  
路由缓存

php artisan optimize
缓存优化

composer dumpautoload -o
优化引入文件

执行完毕之后,在api/bootstrap/cache目录下,会生成对应的缓存文件
在这里插入图片描述

注意,如果路由和配置等有改动,需要清理缓存

清理缓存
php artisan config:clear
php artisan route:clear
php artisan clear-compiled

踩坑

php artisan route:clear

php artisan route:clear这个命令会缓存路由信息,但是他只加载一次路由文件,所以当路由文件被分割后,会导致路由缓存失效,访问就会返回404,这种情况下,我们可以通过require命令,把路由文件加载过来,

// 订单相关
require 'OrderRoute.php';
// 交易相关
require 'TradeRoute.php';

或者也可以注册路由到路由服务提供者里面,在mapi/app/Providers/RouteServiceProvider里面注册

    /**
     * Define the "backend" routes for the application.
     *
     * These routes all receive session state, CSRF protection, etc.
     *
     * @return void
     */
    protected function mapBackendRoutes()
    {
        Route::middleware('web')
            ->prefix("backend")
            ->namespace($this->namespace)
            ->group(base_path('routes/backend.php'));
    }
  • 另外一个点是路由缓存是不支持闭包的,也就是说每个路由都必须指定到某个controller的action。否则会缓存失败。

更深层次的思考

我们平时分析CPU的使用率,一般使用top或者ps等,top显示了系统总体的CPU和内存使用情况,ps则只显示了每个进程的资源使用情况。但是top并没有细分进程的用户态CPU和内核态CPU。那要怎么查看每个进程的详细情况呢? pidstat,它正是一个专门分析每个进程CPU使用情况的工具。
在这里插入图片描述
我们找到比较耗CPU的进程之后,可能还想知道是哪个函数展会用CPU,那么我们就可以使用perf来查找

 perf top

在这里插入图片描述

  • zend_execute_data
    zend_execute_data是执行过程中最核心的一个结构,每次函数的调用、include/require、eval等都会生成一个新的结构,它表示当前的作用域、代码的执行位置
  • libc.so
    PHP 是一种用 C 编写的脚本语言解释器,因此它依赖于 C 语言的标准库。在 Linux 系统上,PHP 的执行环境(包括 PHP 解释器和扩展)会间接依赖 libc.so。例如,当 PHP 脚本执行文件操作、网络请求、字符串处理等操作时,底层实际上调用的是 libc.so 中的相关函数。
  • zend_hash_find
    zend_hash_find 是 Zend 引擎中的一个函数,Zend 引擎是 PHP 的核心部分,负责解析、编译和执行 PHP 代码。
    zend_hash_find 的作用
    zend_hash_find 用于在哈希表中查找一个元素。哈希表在 PHP 内部广泛用于各种数据结构的实现,如数组、符号表、对象属性等。
  • 其他命令
#利用perf record采集静态样本,并保存到本地
[root@localhost ~]# perf record         #按Ctrl+C 终止采样
[ perf record: Woken up 23 times to write data ]
[ perf record: Captured and wrote 5.787 MB perf.data (121112 samples) ]
[root@localhost ~]# ls
anaconda-ks.cfg  perf.data  sysstat-12.1.5-1.x86_64.rpm
[root@localhost ~]# du -sh perf.data    #这就是采集到的样本
5.8M    perf.data
#对本地的静态样本进行分析
[root@localhost ~]# perf report         #会自动打开当前目录下的perf.data
Samples: 121K of event 'cpu-clock', Event count (approx.): 30278000000                                                                         
Overhead  Command         Shared Object        Symbol                                                                                          
  99.86%  swapper         [kernel.kallsyms]    [k] native_safe_halt
   0.03%  kworker/1:1     [kernel.kallsyms]    [k] _raw_spin_unlock_irqrestore
   0.01%  bash            [kernel.kallsyms]    [k] _raw_spin_unlock_irqrestore
   0.01%  sshd            [kernel.kallsyms]    [k] e1000_xmit_frame
   0.01%  kworker/u256:3  [kernel.kallsyms]    [k] mpt_put_msg_frame
   0.00%  swapper         [kernel.kallsyms]    [k] __do_softirq
   0.00%  sshd            [kernel.kallsyms]    [k] __memcpy
   0.00%  bash            [kernel.kallsyms]    [k] __x2apic_send_IPI_mask
   0.00%  ps              [kernel.kallsyms]    [k] __memcpy
   0.00%  migration/1     [kernel.kallsyms]    [k] migration_cpu_stop
   0.00%  ps              [kernel.kallsyms]    [k] follow_page_mask
   0.00%  ps              [kernel.kallsyms]    [k] vsnprintf
   0.00%  bash            [kernel.kallsyms]    [k] __do_page_fault
   0.00%  kworker/0:1     [kernel.kallsyms]    [k] _raw_spin_unlock_irqrestore
   0.00%  perf            [kernel.kallsyms]    [k] mem_cgroup_update_page_stat
   0.00%  ps              [kernel.kallsyms]    [k] format_decode

相关参考

记一次 PHP 并发性能调优实战 – 性能提升 104%

记一次 Laravel 应用性能调优经历

某个应用的CPU使用率居然达到100%,我该怎么做?(三)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2070908.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数学建模----线性回归分析(引入热力图的绘制方法)

目录 0.直击重点 1.一元线性回归分析 1.1散点图的绘制 1.2相关性的分类 1.3计算相关系数 1.4模型的检验 1.5模型的预测 2.多重线性回归分析(上) 2.1多重线性的概念 2.2散点图的分类 2.3热力图的绘制 2.4根据结果确定新的变量 3.多重线性…

【开端】 如何判断手机号码属于哪个国家(手机号判断正则)汇总

import org.apache.commons.lang3.StringUtils; /** * 手机号判断正则 */ public enum MobileRegularExp { /** * 国家 正则 */ CN("中国", 86, "^(\\?0?86\\-?)?1[3456789]\\d{9}$"), TW("中国台湾", 886, "…

第七节 循环结构;goto语句

目录 7.1 while循环 7.1.1 if 和 while的对⽐ 7.1.2 while的执行流程 7.1.3 while的练习 7.2 for循环 7.2.1 语法形式 7.2.2 for循环的执⾏流程 7.2.3 for 循环的练习 7.3 while 和 for 循环的对比 7.4 do while 循环 7.4.1 do while 的语法形式 7.4.2 do while循…

Jamba前生今世:1.5开源来袭

AI21服务于企业,为企业构建基础模型和AI系统以加速GenAI在生产中的使用。AI21 成立于2017年,已从NVIDIA、Intel、Google等公司共筹集了3.36亿美元。它是最早将生成式AI推向大众的公司之一,借助AI21平台,企业可以构建自己的生成式A…

菲菲更名宝贝:批量处理,文件命名不再繁琐

你是否有这样的经历?曾几何时,在堆积如山的文件中迷失方向,为了一个个手动重命名文件而加班到深夜?是否渴望有一种魔法,能瞬间让你的文件整理得井井有条,让繁琐的命名工作变得轻松愉快?那么&…

大数据毕业设计开题报告100例

文章目录 🚩 1 前言1.1 选题注意事项1.1.1 难度怎么把控?1.1.2 题目名称怎么取? 1.2 开题选题推荐1.2.1 起因1.2.2 核心- 如何避坑(重中之重)1.2.3 怎么办呢? 🚩2 选题概览🚩 3 项目概览题目1 : 深度学习社…

前端网站优化-Brotli 压缩

杨绛先生说:“岁不声不响,你且不慌不忙。在凡俗的烟火里,愿以素心,阅来日方长。生活总是一地鸡毛,繁杂琐碎的日常,无力掌控的局面,以及猝不及防的变化,让日子多了几分慌张”。 市井长巷&#xf…

ssrf漏洞复现

环境搭建 zhuifengshaonianhanlu/pikachu: 一个好玩的Web安全-漏洞测试平台 (github.com) 直接将其复制到linux环境下拉取docker就行 我这里已经拉去过了,如果拉去速度慢话,可以在/etc/docker下的daemon.json中配置镜像加速 vim /etc/docker/daemon.js…

大模型学习笔记 - LLM 对齐优化算法 DPO

LLM - DPO LLM - DPO DPO 概述DPO 目标函数推导DPO 目标函数梯度的推导 DPO 概述 大模型预训练是从大量语料中进行无监督学习,语料库内容混杂,训练的目标是语言模型损失,任务是next token prediction,生成的token 不可控&…

MyBatis-Plus分页插件使用详解

一、简述 在使用mybatis开发项目的时候我们通常使用pagehelper来进行分页操作, 但是我们在使用MyBatis-Plus 开发时,MyBatis-Plus内置已经有分页功能了,其实不需要在额外引入pagehelper依赖了,而且两者同时引入有时候还会导致分页…

主流商品API接口在电商跨境电商企业应用/项目中的重要作用

618狂欢已经开启,为了获取更大利益,电商商家应使用价格接口系统。价格接口对电商商家有多方面的好处,主要体现在以下几个方面: 1、价格接口系统可以帮助品牌和商家实现更加科学和精准的定价策略。通过实时获取多个主流电商平台&a…

公众号里面的试卷怎么打印

经过我们的观察发现,微信公众号中的试卷通常有两种形式:图片和文档。如果试卷是以图片的形式嵌入在文章中作为配图,您只需点击图片并长按,选择“保存图片”到手机中。之后,您可以选择任何方便的方式完成打印。 不过&am…

ELK企业级日志分析系统(分布式文件系统与企业级应用)

一、ELK 概述 1、ELK简介 ELK平台是一套完整的日志集中处理解决方案,将 ElasticSearch、Logstash 和 Kiabana 三个开源工具配合使用, 完成更强大的用户对日志的查询、排序、统计需求。 ElasticSearch 是基于Lucene(一个全文检索引擎的架构…

笔记整理—uboot启动过程(4)BL2干了什么及内存排布

uboot的第一阶段结束于start_armboot,第二阶段的uboot代码主要负责soc外部硬件(inand、网卡、......)、uboot本身构建(uboot指令、环境变量、......)最后进入命令行,等待命令然后倒数,等待bootc…

Pytest框架环境切换实战教程

测试人员每天都跟不同的环境打交道,比如线上环境,测试环境,预上线环境等等,那么作为自动化测试人员写的代码,我们也要具备能自由切换环境的能力,那么今天小编就给大家聊一下,如何能让我们python…

linux 安装kafaka单体服务

1.下载kafka的linux安装包 前往Apache Kafka官方网站下载页面(Apache Kafkahttps://kafka.apache.org/downloads),选择最新稳定版的Kafka二进制分发文件,通常是以.tgz结尾的文件。 手动下载kafka_2.13-3.8.0.tgz到本地&#xff0…

Spring Boot 与 Spring Security 的集成及 OAuth2 实现

我的主页:2的n次方_ 在现代 Web 应用开发中,安全性是至关重要的。无论是保护用户的敏感数据,还是确保 API 只允许经过授权的请求访问,开发者都需要一个强大且灵活的安全框架来实现这些需求。Spring Security 作为 Spring 框架的…

MATLAB 生成指定范围、角度、厚度的含噪平面点云(77)

模拟生成点云并可视化显示,可以验证算法有效性,尤其是针对验证算法的某方面 MATLAB 生成指定范围、角度、厚度的含噪平面点云(77) 一、算法介绍二、使用步骤1.代码2.效果一、算法介绍 如题,模拟生成一组平面点云,含有噪声点,确定算法稳定性,可以指定生成平面的范围,厚…

混合A*算法

混合A*算法是一种改进版的A*算法,特别针对车辆动力学进行了优化。这种算法在经典A*的基础上引入了新的维度和概念,以生成更加实际可行的路径。 首先,混合A*算法不仅考虑x和y的位置,还引入了θ维度来表示车辆的朝向。这意味着搜索…

Unity视频播放插件-VideoPro(Windows)

Unity视频播放插件-VideoPro-windows 🌮介绍🍤使用方法🥙示例🌳rtsp🌳本地视频🌳网络视频 🌮介绍 1.支持播放格式:rtsp、http、本地视频。 2.exe试用🌈 3.经测试i9 cpu 空…