Apache服務器訪問過慢分析及解決


起因:線上的一台服務器,最近總是出現 訪問 很慢的情況發生,點擊一個鏈接要2秒鍾以上才能打開,按照我們對於訪問人數的估計,服務器應該不至於響應這么慢,從而需要針對這個問題進行分析,來解決網站訪問過慢。

分析:

1、首先,在頁面訪問變慢情況發生時,使用 top 命令查看了服務器的負載情況,發現負載並不高,初步估計不是程序的問題。 
2、然后,查看了線程中的 httpd 的數量, ps -aux | grep httpd | wc -l 發現,線程數已經達到了 apache 設置的最大值。由此斷定是網站訪問人數過多造成了訪問過慢。 
3、為了驗證,查看了連接數和當前的連接數,分別是 
    netstat -ant | grep $ip:80 | wc -l 
    netstat -ant | grep $ip:80 | grep EST | wc -l 
    發現果然,連接數特別多,遠遠超過我們的估計值。 
4、剛開始的時候,對於服務器的 MPM 配置方式不是特別的熟悉,認為修改服務器配置可以解決問題。主要的配置部分包括 prefork 模式 或者 work 模式的配置,下面是一些簡單的介紹。

    prefork 模式: 
    以 prefork 模式工作的 apache 的默認配置: 
    <IfModule mpm_prefork_module> 
        ServerLimit             2000    
        StartServers               5    #指定服務器啟動時建立的子進程數量 
        MinSpareServers            5    #指定空閑子進程的最小數量 
        MaxSpareServers           10    #指定空閑子進程的最大數量 
        MaxClients               150    #指定同一時間客戶端最大接入請求的數量(單個進程並發線程數),任何超過該限制的請求都將進入等候隊列,一旦一個連接被釋放,隊列中的請求將得到服務 
        MaxRequestsPerChild        0    #指定每個子進程在其生存周期內允許伺服的最大請求數量,默認為10000,0表示子進程永遠不結束 
    </IfModule> 
    prefork 控制進程在最初建立“StartServers”個子進程后,為了滿足 MinSpareServers 設置的需要創建一個進程,等待一秒鍾,繼續創建兩個,再等待一秒鍾,繼續創建四個……如此按指數級增加創建的進程數,最多達到每秒32個,直到滿足MinSpareServers設置的值為止。這種模式可以不必在請求到來時再產生新的進程,從而減小了系統開銷以增加性能。 
    MaxSpareServers 設置了最大的空閑進程數,如果空閑進程數大於這個值,Apache會自動kill掉一些多余進程。這個值不要設得過大,但如果設的值比 MinSpareServers小,Apache會自動把其調整為 MinSpareServers+1。如果站點負載較大,可考慮同時加大MinSpareServers和MaxSpareServers。 
    MaxClients是這些指令中最為重要的一個,設定的是 Apache可以同時處理的請求,是對Apache性能影響最大的參數。其缺省值150是遠遠不夠的,如果請求總數已達到這個值(可通過ps -ef|grep httpd|wc -l來確認),那么后面的請求就要排隊,直到某個已處理請求完畢。這就是系統資源還剩下很多而HTTP訪問卻很慢的主要原因。雖然理論上這個值越大,可以處理的請求就越多,但Apache默認的限制不能大於256。在 apache2 中通過ServerLimit指令無須重編譯Apache就可以加大MaxClients。 
    雖然通過設置ServerLimit,我們可以把MaxClients加得很大,但是往往會適得其反,系統耗光所有內存。以一台服務器為例:內存2G,每個apache進程消耗大約0.5%(可通過ps aux來確認)的內存,也就是10M,這樣,理論上這台服務器最多跑200個apache進程就會耗光系統所有內存,所以,設置MaxClients要慎重。 
    worker 模式: 
    以 worker 模式工作的 apache 的默認配置為: 
    <IfModule mpm_worker_module> 
        StartServers               2 
        MaxClients               150 
        MinSpareThreads           25 
        MaxSpareThreads           75 
        ThreadsPerChild           25 
        MaxRequestsPerChild        0 
    </IfModule> 
    Worker 由主控制進程生成“StartServers”個子進程,每個子進程中包含固定的ThreadsPerChild線程數,各個線程獨立地處理請求。同樣,為了不在請求到來時再生成線程, 
    MinSpareThreads和MaxSpareThreads設置了最少和最多的空閑線程數;而MaxClients 設置了同時連入的clients最大總數。如果現有子進程中的線程總數不能滿足負載,控制進程將派生新的子進程。 
    MinSpareThreads和 MaxSpareThreads的最大缺省值分別是75和250。這兩個參數對Apache的性能影響並不大,可以按照實際情況相應調節。 
    ThreadsPerChild是worker MPM中與性能相關最密切的指令。 
    ThreadsPerChild的最大缺省值是64,如果負載較大,64也是不夠的。這時要顯式使用 ThreadLimit指令,它的最大缺省值是20000。 
    Worker模式下所能同時處理的請求總數是由子進程總數乘以ThreadsPerChild 值決定的,應該大於等於MaxClients。如果負載很大,現有的子進程數不能滿足時,控制進程會派生新的子進程。默認最大的子進程總數是16,加大時也需要顯式聲明ServerLimit(最大值是20000)。需要注意的是,如果顯式聲明了ServerLimit,那么它乘以 ThreadsPerChild的值必須大於等於MaxClients,而且MaxClients必須是ThreadsPerChild的整數倍,否則 Apache將會自動調節到一個相應值。

    服務器的apache采用的是 prefork 的工作模式,對 MaxClients 進行了相應的調整,發現服務啟動后很短時間,連接數就能夠達到最大。 
5、后來想到需要查看用戶都是訪問的那些頁面,將配置中的 access_log 打開,發現85%以上的訪問都是直接訪問的資源文件,由此判定,用戶可能使用了多線程的下載工具,或者這些資源遭受了盜鏈。 
6、找到了問題所在,進行解決也就比較好辦了。想到了兩個方法: 
    A、對單個IP進行連接的線程限制,不允許多線程連接資源。 
        對於IP限制,我采用了 mod_limitipconn 這個模塊。這個模塊的好處是比較簡單,缺點是不能夠針對單獨的文件夾或者文件進行設置,而且不支持虛擬主機。 
        在 apache 中安裝了這個模塊后,在配置文件中添加如下幾段就可以生效了: 
            ExtendedStatus On 
            < IfModule mod_limitipconn.c > 
                < Location / >   # 所有虛擬主機的/目錄 
                    MaxConnPerIP 3     # 每IP只允許3個並發連接 
                    NoIPLimit image/*  # 對圖片不做IP限制 
                < /Location > 
            < Location /mp3 >  # 所有主機的/mp3目錄 
            MaxConnPerIP 1         # 每IP只允許一個連接請求    
            OnlyIPLimit audio/mpeg video    # 該限制只對視頻和音頻格式的文件 
                < /Location > 
            < /IfModule > 
    B、添加URL重寫,防止盜鏈。 
        防止盜鏈,一個重要的方法就是判斷請求的 refer,但是如果使用一些瀏覽器發出請求的時候將 refer 去掉,或者偽裝,這個辦法就無能為力了。但是貌似還有更高級的方法,還是可以實現這個功能。 
        安裝apache的 mod_rewrite 模塊后,在apache配置文件中添加 
        RewriteEngine On 
        RewriteCond %{HTTP_REFERER} !^http://abc.com/.*$ [NC] 
        RewriteCond %{HTTP_REFERER} !^http://abc.com$ [NC] 
        RewriteCond %{HTTP_REFERER} !^http://www.abc.com/.*$ [NC] 
        RewriteCond %{HTTP_REFERER} !^http://www.abc.com$ [NC] 
        RewriteRule .*\.(gif|jpg|swf)$ http://www.abc.com/about/nolink.png [R,NC] 
        這樣盜鏈的請求會被重定向到一個錯誤頁面,從而減少下載帶給服務器的壓力。

參考資料: 
1、部署 Apache 的一些技巧。       

2、Apache Server 負載能力測試    
3、Apache AB                        
4、Apache的參數設置                
5、Ab的用法                        
6、Apache限制連接數和並發數        
7、Apache安裝mod_rewrite模塊        
8、Apache防盜鏈的簡單實現           


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM