apache2三種模式及參數調優

問題來源

如果訪問量比較小,其實什麼配置都沒問題。在一些特殊場景下,例如促銷活動,訪問量會比較集中。峯值差不多能達到每秒1000到2000次的訪問,而且還在繼續增長中。

我們一直判斷是數據庫卡死的問題,後來發現,原來了服務器掛了。進一步定位,發現是apache接收了太多了請求,起了無數進程,內存用爆,機器卡死了。

如何配置apache,最大程度的發揮系統性能呢?

apache2三種模式

從2.0開始,apache引入了MPM(Multi-Processing Module,多進程處理模塊)。MPM有prefork, worker和event(在2.4版本中穩定發佈)模式,三種模式擁有不同的特點和性能。

prefork MPM

prefork是比較古老而又穩定的apache模式,特點是每個進程都是單線程,在一個時間點只能處理一個連接,需要啓動大量的進程來處理高併發的請求。由於是單線程進程,因而無須考慮線程安全的問題,可以使用非線程安全的庫,例如mod_php。

優點是成熟穩定,缺點是比較消耗內存,而且併發支持受限於進程數量,對高併發支持稍差。

worker MPM

worker同樣使用多個進程,但每個進程又擁有多個線程,每個線程處理一個連接。由於線程是輕量級的,因而具有較高的併發性,同時,多個進程又獲得了一定的穩定性。

worker模式特點是佔用內存少,併發性比較高,缺點是必須考慮線程安全。如果使用了keep-alive方式,一個線程可能會被一直保持一個連接,但中間沒有請求,直到超時。如果有多個線程被這樣佔據,在高併發場景下同樣會出現無線程可用的情形。

event MPM

event模式是在2.4版本中才穩定發佈的模式,它在worker的基礎上,解決了keep-alive連接不能釋放的問題。event MPM中,會有一個專門的線程來管理這些keep-alive類型的線程,當有真實請求過來的時候,將請求傳遞給服務線程,執行完畢後,又允許它釋放。這樣增強了高併發場景下的請求處理能力。

apache2 配置

apache服務器的性能,在很大程度上取決於參數配置。

首先,我們如何查看當前apache所採用的模式呢?可以通過下面的命令:

apachectl -V | grep -i mpm

接下來,針對相應的模式,進行配置。apache2的默認配置文件位於/etc/apache2/apache2.conf,不同模式對應的配置文件在/etc/apache2/mods-available/下,有mpm_prefork.conf, mpm_worker.conf和mpm_event.conf。

prefork MPM

mpm_prefork.conf文件內容如下:

<IfModule mpm_prefork_module>
    StartServers         10         # 啓動時進程數
    MinSpareServers      5          # 最小空閒進程數
    MaxSpareServers      10         # 最大空閒進程數
    MaxRequestWorkers    100        # 最大併發進程數
    MaxConnectionsPerChild   10000  # 最大連接數限制
</IfModule>

各個指令的含義:

StartServers : apache2啓動時創建的服務進程數量。

MinSpareServers:最小空閒進程數量,空閒進程指的是沒有處理請求的進程

MaxSpareServers : 最大空閒進程數量。

MaxRequestWorkers : 最大同時處理請求的進程數量,也是最大的同時連接數,表示了apache的最大請求併發能力,超過該數目後的請求,將排隊。

MaxConnectionsPerChild : 進程生命週期內,處理的最大請求數目。達到該數目後,進程將死掉。如果設置爲0,表示沒有限制。該參數的意義在於,避免了可能存在的內存泄露帶來的系統問題。

通過上面的介紹可以發現,prefork模式下,影響併發性能最重要的參數就是MaxRequestWorkers,它決定了apache的併發處理能力。但是這個參數不是越大越好,因爲如果超出了系統硬件能力,機器會卡死。

如果確定合適的MaxRequestWorkers呢?

首先,通過top命令查看apache進程佔用的資源,主要看%CPU和%MEM這兩個指標,例如,每個進程的CPU佔用率不超過1%,每個進程的內存佔用率不超過2%,考慮內存限制,比較合適的apache進程數量爲50個。

然後,逐步測試最大值。通過觀測得來的CPU和內存的指標有一定的誤差,一般可以適當調節這個數值,例如調到1.5或者2倍,再通過峯值場景下的機器是否卡頓來判斷是繼續上調還是下調。

調整完參數後,一般需要重啓apache。

service apache2 restart

worker MPM

mpm_worker.conf文件內容如下:

<IfModule mpm_worker_module>
    StartServers         2        # 啓動時進程數
    MinSpareThreads      25       # 最小空閒線程數
    MaxSpareThreads      75       # 最大空閒線程數
    ThreadLimit          64       # 每個進程可以啓動的線程數量上限值
    ThreadsPerChild      25       # 每個進程可以啓動的線程數量
    MaxRequestWorkers    400      # 線程數量最大值
    MaxConnectionsPerChild   0    # 最大連接數限制
</IfModule>

配置文件和前面的prefork有一些變動,但是基本的概念差不多。原來以進程爲單位的概念轉變成了以線程爲單位的概念,例如MinSpareServers轉變爲MinSpareThreads,多了一個ThreadsPerChild,表示每個進程可以有的線程數量,其上限值爲ThreadLimit。

注意,修改了ThreadsPerChild後可以通過apache2 restart來生效,但是修改了ThreadLimit只能先stop,然後start。

在worker模式中,MaxRequestWorkers轉變爲了線程數量,比起prefork模式下可以有比較大的增長,通常可以有好幾倍的差別。這是worker模式相比於prefork的優勢,worker擁有比較多的處理線程,可以同時保持大量的連接,峯值應對能力比較強。儘管出於CPU或者數據庫的原因,這些連接不能在第一時間內被處理,可能產生較大延遲。

如果確定worker模式的參數呢?

有兩個參數比較重要是,一是ThreadsPerChild,這個表示每個進程的線程數目,一般採用默認值即可,如果是併發量比較大,可以考慮加大這個值。另外一個就是MaxRequestWorkers了,在workers模式下,任務處理的負載會分發給php-fpm來處理,所以apache主要承擔了建立和保持連接的任務,並不消耗太多資源,因而在理論上,MaxRequestWorkers可以非常大。

但是從實用體驗來看,如果MaxRequestWorkers遠超系統的請求處理能力,會有大量的請求排隊,因而產生比較大的延遲,這個時候的體驗並不好。所以這個參數一開始可以稍大,例如可以設置爲prefork模式下的幾倍,然後根據線上峯值延遲不斷調整這個數值。

MaxRequestWorkers必須是ThreadsPerChild的整數倍,否則apache會提示調整到一個相近的值。MaxRequestWorkers也有最大值限制,即ServerLimit乘以ThreadsPerChild。默認ServerLimit值是16,必要時可以顯式聲明加大這個值。

調整php-fpm

worker模式下的PHP一般運行在fastcgi環境下,所以決定系統性能的其實是PHP的處理能力。默認的php-fpm配置文件位於/etc/php5/fpm/pool.d/www.conf。通常有以下選項可以配置:

pm = dynamic                # PHP進程管理方式,動態
pm.max_children = 32        # 最大PHP處理進程數
pm.start_servers = 2        # 啓動時PHP進程數目
pm.min_spare_servers = 4    # 最小的空閒PHP進程數
pm.max_spare_servers = 8    # 最大的空閒PHP進程數
pm.max_requests = 5000      # 進程生命週期處理的最大請求數,避免內存泄露

同理,這裏比較關鍵的是max_children參數,它直接決定了PHP處理請求的能力。這個參數的選取,也需要根據每個php-fpm所佔用的CPU和內存來決定,同樣通過top命令查看php-fpm進程消耗的資源,然後計算一個大概值。在調整的過程中,可以結合top命令查看CPU和內存消耗的總量,只要有足夠剩餘,是可以加大這個數值的。調整完參數後,需要重啓php-fpm。

service php5-fpm restart

event MPM

event模式下的參數意義和worker模式完全一樣,按照上面的策略來調整即可。

event相比於worker的優勢是,它解決了worker模式下長連接線程的阻塞問題。

值得一提的是,worker/event模式的請求處理模式,已經和nginx的libevent模式相同了。在mod_php模式下,每個apache進程都需要直接執行php,所以很容易達到系統資源限制。但是在php-fpm模式下,apache只負責建立連接,然後把請求傳遞給php-fpm來處理。這樣,apache可以保持大量的連接,請求處理能力取決於php服務器的性能。

由於event是明顯優於worker的,所以在apache2.4及後續版本中,一般優先選擇event模式。

常見問題

查看apache的error日誌,可以發現許多系統運行中的問題。

server reached MaxRequestWorkers setting

[mpm_prefork:error] [pid 1134] AH00161: server reached MaxRequestWorkers setting, consider raising the MaxRequestWorkers setting

進程或者線程數目達到了MaxRequestWorkers,可以考慮增加這個值,當然,先考慮增加硬件。

scoreboard is full

[mpm_event:error] [pid 7555:tid 140058436118400] AH00485: scoreboard is full, not at MaxRequestWorkers

這個問題好像是apache2自帶的bug,我們無力解決。好在這個問題一般只會影響單個線程,所以暫時可以忍。

一些系統狀態指標

top命令

這裏寫圖片描述

第一行裏面的load average可以查看系統負載情況。第三行可以查看CPU使用問題。第四行可以查看內存佔用及剩餘內存。

進程列表裏面,%CPU和%MEM顯示了每個進程所佔用的資源百分比。

apache日誌

訪問日誌默認位置/var/log/apache2/access.log,可以通過日誌文件查看每個請求處理結果及所用時間。

error日誌一般位於/var/log/apache2/error.log,可以查看apache運行中的一些error報告 。

ps命令

查看當前系統apache和php進程、線程數目,下面的命令適用於ubuntu系統。

查看apache進程。

ps aux | grep apache

查看apache進程數目

加上wc -l 命令即可。

ps aux | grep apache | wc -l

worker/event模式下,查看線程數目。

ps -eLf | grep apache | wc -l

查看php-fpm進程數。

ps aux | grep php-fpm | wc -l



apache性能調試是一個比較複雜的問題。除了apache本身配置、PHP配置,還會涉及到數據庫。後臺的難點就在於如何應對高併發、大流量的請求,這往往不是單個點可以解決的,需要系統各個模塊來協調。

參考

Apache MPM Common Directives

How do I select which Apache MPM to use?

PERFORMANCE OF APACHE 2.4 WITH THE EVENT MPM COMPARED TO NGINX

Determining the correct number of child processes for PHP-FPM on NGinx

CGI、FastCGI和PHP-FPM關係圖解

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章