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

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

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

遇到問題

單臺(tái)服務(wù)并發(fā)20,平均響應(yīng)時(shí)間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)時(shí)長(zhǎ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 的一個(gè)擴(kuò)展,用于加速 PHP 腳本的執(zhí)行。它通過將 PHP 腳本的編譯結(jié)果(即opcode)緩存起來(lái),從而避免每次請(qǐng)求都重新編譯腳本,提高性能。在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í)行情況動(dòng)態(tài)編譯熱點(diǎn)代碼
opcache.jit_buffer_size=256M ; 為 JIT 編譯保留的內(nèi)存大小
opcache.memory_consumption=512M ; OPCache 可使用的內(nèi)存大小
opcache.interned_strings_buffer=64M ; 用于存儲(chǔ)內(nèi)部字符串的緩沖區(qū)大小
opcache.max_accelerated_files=10000 ; 緩存的最大文件數(shù)量
opcache.revalidate_freq=60 ; OPcache 每隔 60 秒會(huì)檢查一次腳本文件是否有修改。默認(rèn)值通常為 2 秒  0則認(rèn)為是每次啟動(dòng)都檢查文件是否修改,會(huì)增加IO操作,影響性能夠 ,這個(gè)參數(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)存使用率很少,說(shuō)明內(nèi)存并不是laravel的瓶頸,考慮增加php-fmp的工作池

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

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

重啟php-fmp

sudo systemctl restart php-fpm

phpredis

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

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

在php-fmp的進(jìn)程里面,running的進(jìn)程不超過30個(gè),而sleep的有時(shí)候可以達(dá)到300多。于是考慮是發(fā)生了系統(tǒng)調(diào)用導(dǎo)致部分子進(jìn)程sleep。找到一個(gè)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)有對(duì)session的寫操作,打開laravel,發(fā)現(xiàn)session的驅(qū)動(dòng)是通過file驅(qū)動(dòng)的,因?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òng)時(shí)也會(huì)被加載,導(dǎo)致項(xiàng)目啟動(dòng)慢,我刪除了debug相關(guān)的組件。

關(guān)閉debug

在env文件中,有的會(huì)開啟APP_DEBUG=true,

利用laravel的緩存提升效率

我們可以把配置信息,路由信息等緩存起來(lái),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目錄下,會(huì)生成對(duì)應(yīng)的緩存文件從并發(fā)20到并發(fā)120之laravel性能優(yōu)化-圖片2

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

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

踩坑

php artisan route:clear

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

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

或者也可以注冊(cè)路由到路由服務(wù)提供者里面,在mapi/app/Providers/RouteServiceProvider里面注冊(cè)

 /**
     * 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'));
    }
  • 另外一個(gè)點(diǎn)是路由緩存是不支持閉包的,也就是說(shuō)每個(gè)路由都必須指定到某個(gè)controller的action。否則會(huì)緩存失敗。

更深層次的思考

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

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

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

 perf top

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

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

    #利用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
    #對(duì)本地的靜態(tài)樣本進(jìn)行分析
    [root@localhost ~]# perf report         #會(huì)自動(dòng)打開當(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

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

 
  • 本文由 米粒在線 發(fā)表于 2024年11月15日12:12:29
  • 轉(zhuǎn)載請(qǐng)務(wù)必保留本文鏈接:http://m.bjmhhq.com/129209.html
百科知道

徹底解決AMD顯卡win10開機(jī)黑屏問題

遇上個(gè)AMD R7 350 顯卡 偶爾開機(jī)到了logo之后黑屏,找了各種法子沒解決,看到了這個(gè)辦法。試試看。來(lái)自小櫻看科技的公眾號(hào)。這邊做一下記錄避免丟了。謝謝。小櫻的辦公用電...
網(wǎng)站建設(shè)

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

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

/var/log/maillog日志太大占滿/var空間如何清理

一、情景描述 節(jié)點(diǎn)磁盤空間告警,使用df -h查看發(fā)現(xiàn)是/var盤滿了,cd進(jìn)入/var目錄下,du -sch log/ 發(fā)現(xiàn)是log目錄占用空間大,cd切換到log目錄下,du -dh *查看是因...