記錄一次線上服務器內存持續增高問題梳理及總結

1、問題現象

11.png

2、項目背景

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

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

3、內存持續增高緣由分析

  1. 查看了php-fpm相關配置後,發現系統是靜態機制,而且沒有配置max_requests項,沒有退出機制
  2. php進程長期存在致使內存積壓沒法釋放,因此內存消耗持續升高
  3. nginx+php-fpm運行原理?【https://juejin.im/post/58db7d...html

    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參數理解:mysql

    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掉該進程重啓,進程一直存活容易發生內存泄漏

4、解決方案

  1. 經過如今php-fpm的配置能夠得知,php-fpm沒有設置max_requests,表明進程一直不會退出,每一個請求完成後php-cgi會回收內存,可是不會釋放給操做系統,因此大量內存被php-cgi佔用。
  2. 官方的解決辦法就是下降PHP_FCGI_MAX_REQUESTS的值,對應php-fpm配置中的max_requests
  3. 因此,只要從新設置 max_requests 的值,讓進程達到這個值後自動重啓釋放內存便可nginx

    # 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進行重啓web

    //查詢當前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...