記錄一次線上伺服器記憶體持續增高問題梳理及總結

繁星落眼眶發表於2020-07-17

一、問題現象

11.png

二、專案背景

  1. 線上web服務是nginx+php7+mysql
  2. 線上伺服器配置:8核16G
  3. php-fpm配置:

    pm = static
    pm.max_children = 500
    ;pm.max_requests = 5000 //此配置沒有開啟

三、記憶體持續增高原因分析

  1. 檢視了php-fpm相關配置後,發現系統是靜態機制,並且沒有配置max_requests項,沒有退出機制
  2. php程式長期存在導致記憶體積壓無法釋放,所以記憶體消耗持續升高
  3. nginx+php-fpm執行原理?【https://juejin.im/post/58db7d...

    cgi、fast-cgi、php-fpm之間的關係?
    
    我的理解:
        1.webserver最開始只能處理靜態請求,後來出現了動態請求,比如php程式,然而webserver是無法處理php程式的,這個是時候怎麼辦?
        2.交給php直譯器來處理動態php請求
        3.那麼webserver可以將動態請求交給php直譯器處理,那麼webserver如何與php直譯器進行通訊呢?【webserver就是nginx/apache】
        4.這個時候就出現了cgi,cgi協議就是webserver和php直譯器進行通訊的協議
        5.webserver在每次請求過來都會fork一個cgi程式進行處理,處理完成後返回,如果有10k請求,那麼就fork 10k個程式,顯然對系統資源很浪費
        6.這時對cgi做了優化,出現了fast-cgi,fast-cgi在請求處理完成後不會直接kill掉這個程式,而是繼續保留請求下一次請求,這樣一個程式就能處理多個請求,不用每次都fork程式減少了系統資源浪費
        7.而php-fpm就是fast-cgi的實現,並且提供了程式管理的功能,包含master和worker兩種型別的程式
        8.master程式只負責監聽埠,接收來自webserver的請求,worker程式有多個,每個worker程式內部都嵌入了一個php直譯器,是php程式碼真正執行的地方
    
  4. 一些php-fpm引數理解:

    pm = dynamic # 三種型別選擇,static/dynamic/ondemand
    pm.max_children = 5 # php-fpm的worker程式最大數量
    pm.start_servers = 3 # php-fpm啟動時候,啟動的worker數量
    pm.min_spare_servers = 2 # php-fpm最小空閒程式數量,每時每刻最少也有2個是空閒的程式
    pm.max_spare_servers = 4 # php-fpm最大的空閒程式數量
    pm.max_requests = 200 # 單個程式處理請求數量達到200就會kill掉該程式重啟,程式一直存活容易發生記憶體洩漏
    

四、解決方案

  1. 通過現在php-fpm的配置可以得知,php-fpm沒有設定max_requests,代表程式一直不會退出,每個請求完成後php-cgi會回收記憶體,但是不會釋放給作業系統,所以大量記憶體被php-cgi佔用。
  2. 官方的解決辦法就是降低PHP_FCGI_MAX_REQUESTS的值,對應php-fpm配置中的max_requests
  3. 所以,只要重新設定 max_requests 的值,讓程式達到這個值後自動重啟釋放記憶體即可

    # php-fpm.conf配置
    pm = static
    pm.max_children = 500
    pm.start.servers = 100
    pm.min_spare_servers = 20
    pm.max_spare_servers = 100
    pm.max_requests = 2000
  4. 修改完配置後對php-fpm進行重啟

    //查詢當前fpm的master程式號
    ps aux|grep php-fpm | grep master
    //平滑重啟fpm,42891是master程式號
    kill -USR2 42891
    //立即終止fpm
    kill -QUIT 42891
    //檢視狀態
    ps aux|grep php-fpm
      
      
    //備註:
    php 5.3.3 以後的php-fpm 不再支援 php-fpm 以前具有的 /usr/local/php/sbin/php-fpm (start|stop|reload)等命令,所以不要再看這種老掉牙的命令了,需要使用訊號控制:
     
    master程式可以理解以下訊號
     
    INT, TERM 立刻終止
    QUIT 平滑終止
    USR1 重新開啟日誌檔案
    USR2 平滑過載所有worker程式並重新載入配置和二進位制模組
  5. 參考:https://www.cnblogs.com/cocol...

相關文章