從并發(fā)20到并發(fā)120之laravel性能優(yōu)化

網(wǎng)站建設(shè) SEO相關(guān) 百科知道從并發(fā)20到并發(fā)120之laravel性能優(yōu)化已關(guān)閉評論297閱讀模式

調(diào)優(yōu)成果

遇到問題

單臺服務(wù)并發(fā)20,平均響應(yīng)時間1124ms,通過htop觀察,發(fā)現(xiàn)cpu占用率達(dá)到100%(包括sleep的進(jìn)程),內(nèi)存幾乎沒怎么用。

從并發(fā)20到并發(fā)120之laravel性能優(yōu)化-圖片1

調(diào)優(yōu)后

單機(jī)最大吞吐量達(dá)到120 響應(yīng)時長不超過1000ms

硬件信息

操作系統(tǒng):Linux 系統(tǒng)版本為 CentOS 8 CPU:4核 3.20GHz 內(nèi)存: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

應(yīng)用環(huán)境

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 的一個擴(kuò)展,用于加速 PHP 腳本的執(zhí)行。它通過將 PHP 腳本的編譯結(jié)果(即opcode)緩存起來,從而避免每次請求都重新編譯腳本,提高性能。在php.ini內(nèi)開啟opcache,相關(guān)參數(shù)如下:

[dba]
;dba.default_handler=

[opcache]

opcache.enable=1 ; 啟用 OPCache
opcache.enable_cli=1 ; 在命令行模式下也啟用 OPCache
opcache.jit=tracing ; 啟用 JIT 跟蹤模式,根據(jù)執(zhí)行情況動態(tài)編譯熱點(diǎn)代碼
opcache.jit_buffer_size=256M ; 為 JIT 編譯保留的內(nèi)存大小
opcache.memory_consumption=512M ; OPCache 可使用的內(nèi)存大小
opcache.interned_strings_buffer=64M ; 用于存儲內(nèi)部字符串的緩沖區(qū)大小
opcache.max_accelerated_files=10000 ; 緩存的最大文件數(shù)量
opcache.revalidate_freq=60 ; OPcache 每隔 60 秒會檢查一次腳本文件是否有修改。默認(rèn)值通常為 2 秒  0則認(rèn)為是每次啟動都檢查文件是否修改,會增加IO操作,影響性能夠 ,這個參數(shù)只有在 opcache.validate_timestamps=1 的情況下才有效
opcache.validate_timestamps=1;啟用文件變更檢查  0禁用文件變更檢查
opcache.fast_shutdown=1 ; 快速關(guān)閉,提高性能
opcache.save_comments=1 ; 保存注釋,某些框架或應(yīng)用可能依賴注釋

開啟了opcache之后,每秒的吞吐量達(dá)到了70。

php-fmp 靜態(tài)模式

通過htop觀察發(fā)現(xiàn),內(nèi)存使用率很少,說明內(nèi)存并不是laravel的瓶頸,考慮增加php-fmp的工作池

emergency_restart_threshold = 30;在60s內(nèi)超過 30 個 PHP-FPM 進(jìn)程因出現(xiàn)異常(如段錯誤)而退出,那么 PHP-FPM 主進(jìn)程會自動重啟
emergency_restart_interval = 60s;配合第一個選項(xiàng)使用
process_control_timeout = 5s;停止php-fmp的時候,如果子進(jìn)程超過5s未響應(yīng),則強(qiáng)制終止
daemonize = yes;后臺運(yùn)行
process.max = 500;限制 PHP-FPM 可以生成的最大進(jìn)程數(shù)。這個配置項(xiàng)定義了整個 PHP-FPM 服務(wù)的上限,而不是單個工作池的限制。
;;;;;;;;;;;;;;;;;;;;
; Pool Definitions ;
;;;;;;;;;;;;;;;;;;;;

[work]
pm = static;設(shè)置了 PHP-FPM 的進(jìn)程管理模式為靜態(tài)(static),即總是啟動固定數(shù)量的子進(jìn)程
pm.max_children = 200; 定義了靜態(tài)模式下 PHP-FPM 工作池可以生成的最大子進(jìn)程數(shù),即始終有 200 個子進(jìn)程等待處理請求。
pm.start_servers = 20;這些參數(shù)用于動態(tài)模式下,控制 PHP-FPM 啟動時的初始子進(jìn)程數(shù)
pm.min_spare_servers = 20;
pm.max_spare_servers = 300
pm.max_requests = 10240;每個子進(jìn)程在處理完 10240 個請求后會自動重啟。這有助于防止內(nèi)存泄漏問題。
pm.process_idle_timeout = 5s;動態(tài)模式下,閑置進(jìn)程在超過 5 秒沒有處理請求后被終止。在靜態(tài)模式下無效。
request_terminate_timeout = 120;強(qiáng)制終止執(zhí)行時間超過 120 秒的請求。用于防止超長時間執(zhí)行的腳本占用系統(tǒng)資源。
request_slowlog_timeout = 2;慢請求的閾值(2 秒)。如果請求執(zhí)行時間超過這個值,PHP-FPM 會將其記錄到慢日志中。
slowlog = /data/logs/php/slow.log
rlimit_files = 51200;設(shè)置了 PHP-FPM 子進(jìn)程可以打開的最大文件描述符數(shù)量。這影響 PHP-FPM 可以同時處理的文件數(shù)。
rlimit_core = 0;設(shè)置 PHP-FPM 子進(jìn)程可以生成的 core dump 文件的最大大?。ㄒ宰止?jié)為單位)。0 表示禁用 core dump。

重啟php-fmp

sudo systemctl restart php-fpm

phpredis

Laravel 自己封裝了一個 Redis,叫predis,當(dāng)我們用laravel自帶的Redis Facade,那么每次調(diào)用redis都需要編譯這個Redis組件,而且是不支持連接池的。但是PHP有一個由c編寫的一個PHP擴(kuò)展比它效率更高,保證服務(wù)器安裝了php的Redis擴(kuò)展,我們就可以改寫predis,修改驅(qū)動為phpredis。

框架內(nèi)的優(yōu)化

在php-fmp的進(jìn)程里面,running的進(jìn)程不超過30個,而sleep的有時候可以達(dá)到300多。于是考慮是發(fā)生了系統(tǒng)調(diào)用導(dǎo)致部分子進(jìn)程sleep。找到一個sleep的進(jìn)程的pid,執(zhí)行命令sudo strace -p 487143;相關(guān)輸出如下

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

關(guān)閉session

發(fā)現(xiàn)有對session的寫操作,打開laravel,發(fā)現(xiàn)session的驅(qū)動是通過file驅(qū)動的,因?yàn)槲覀儧]有用session ,所以打算關(guān)閉session ,設(shè)置drive為array,當(dāng)然,有其他非必要的中間件也可以刪除 mapi/config/session.php

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

關(guān)閉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里面,可能有很多沒用到的組件,在項(xiàng)目啟動時也會被加載,導(dǎo)致項(xiàng)目啟動慢,我刪除了debug相關(guān)的組件。

關(guān)閉debug

在env文件中,有的會開啟APP_DEBUG=true,

利用laravel的緩存提升效率

我們可以把配置信息,路由信息等緩存起來,artisan提供了相關(guān)的方法

hp artisan config:cache 
配置緩存

php artisan route:cache  
路由緩存

php artisan optimize
緩存優(yōu)化

composer dumpautoload -o
優(yōu)化引入文件

執(zhí)行完畢之后,在api/bootstrap/cache目錄下,會生成對應(yīng)的緩存文件從并發(fā)20到并發(fā)120之laravel性能優(yōu)化-圖片2

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

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

踩坑

php artisan route:clear

php artisan route:clear這個命令會緩存路由信息,但是他只加載一次路由文件,所以當(dāng)路由文件被分割后,會導(dǎo)致路由緩存失效,訪問就會返回404,這種情況下,我們可以通過require命令,把路由文件加載過來,

// 訂單相關(guān)
require 'OrderRoute.php';
// 交易相關(guān)
require 'TradeRoute.php';

或者也可以注冊路由到路由服務(wù)提供者里面,在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'));
    }
  • 另外一個點(diǎn)是路由緩存是不支持閉包的,也就是說每個路由都必須指定到某個controller的action。否則會緩存失敗。

更深層次的思考

我們平時分析CPU的使用率,一般使用top或者ps等,top顯示了系統(tǒng)總體的CPU和內(nèi)存使用情況,ps則只顯示了每個進(jìn)程的資源使用情況。但是top并沒有細(xì)分進(jìn)程的用戶態(tài)CPU和內(nèi)核態(tài)CPU。那要怎么查看每個進(jìn)程的詳細(xì)情況呢?pidstat,它正是一個專門分析每個進(jìn)程CPU使用情況的工具。

從并發(fā)20到并發(fā)120之laravel性能優(yōu)化-圖片3

我們找到比較耗CPU的進(jìn)程之后,可能還想知道是哪個函數(shù)展會用CPU,那么我們就可以使用perf來查找

 perf top

從并發(fā)20到并發(fā)120之laravel性能優(yōu)化-圖片4

  • zend_execute_data zend_execute_data是執(zhí)行過程中最核心的一個結(jié)構(gòu),每次函數(shù)的調(diào)用、include/require、eval等都會生成一個新的結(jié)構(gòu),它表示當(dāng)前的作用域、代碼的執(zhí)行位置
  • libc.so PHP 是一種用 C 編寫的腳本語言解釋器,因此它依賴于 C 語言的標(biāo)準(zhǔn)庫。在 Linux 系統(tǒng)上,PHP 的執(zhí)行環(huán)境(包括 PHP 解釋器和擴(kuò)展)會間接依賴 libc.so。例如,當(dāng) PHP 腳本執(zhí)行文件操作、網(wǎng)絡(luò)請求、字符串處理等操作時,底層實(shí)際上調(diào)用的是 libc.so 中的相關(guān)函數(shù)。
  • zend_hash_find zend_hash_find 是 Zend 引擎中的一個函數(shù),Zend 引擎是 PHP 的核心部分,負(fù)責(zé)解析、編譯和執(zhí)行 PHP 代碼。zend_hash_find 的作用 zend_hash_find 用于在哈希表中查找一個元素。哈希表在 PHP 內(nèi)部廣泛用于各種數(shù)據(jù)結(jié)構(gòu)的實(shí)現(xiàn),如數(shù)組、符號表、對象屬性等。
  • 其他命令

    #利用perf record采集靜態(tài)樣本,并保存到本地
    [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
    #對本地的靜態(tài)樣本進(jìn)行分析
    [root@localhost ~]# perf report         #會自動打開當(dāng)前目錄下的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

做個優(yōu)化記錄。感謝老A技術(shù)聯(lián)盟公眾號。

 
  • 本文由 米粒在線 發(fā)表于 2024年11月15日12:12:29
  • 轉(zhuǎn)載請務(wù)必保留本文鏈接:http://m.bjmhhq.com/129209.html
網(wǎng)站建設(shè)

寶塔面板設(shè)置Docker加速站提示錯誤:全局配置文件有誤,請檢查Expecting value:line 1 column 1(char 0)解決方法

寶塔? docker? 修改加速 報(bào)錯:寶塔 設(shè)置失??!讀取配置文件失敗:Expecting value: line 1 column 1 (char 0)解決辦法: 打開文件:/etc/d...
百科知道

華碩路由器的ddns用不了, 還有哪個可以用,備選替代選擇

尊敬的華碩用戶: 為配合網(wǎng)絡(luò)安全法規(guī)及政策的要求,進(jìn)一步提升服務(wù)安全性與質(zhì)量,華碩將對ASUS DDNS服務(wù)進(jìn)行調(diào)整。當(dāng)前的ASUS DDNS服務(wù)將停止。我們?yōu)槟峁┝寺酚善鲀?nèi)嵌的其他第三方DDNS服...