httpd2.2+mod_proxy+jetty7.2.0
mod_proxy配置相關
===================================================
httpd通過自帶的mod_proxy模塊連接後端服務器(jetty7.2.0)。
<IfModule mod_proxy.c> ProxyRequests Off ProxyPreserveHost On ProxyPassMatch ^/(blog|user|mo)/(.*)$ http://localhost:8080 min=5 smax=16 max=64 ttl=300 timeout=20 </IfModule>
ProxyPassMatch ^/(blog|user|mo)/(.*)$
http://localhost:8080
:
與另外兩種配置比較
1. 所有的apache請求都代理給後端服務器
ProxyPass /
http://localhost:8080/
缺點:後端服務器接受太多非法url,比如用戶訪問/admin/index.htm,apache也會乖乖的把請求代理給後端
,後端服務器消耗一些cpu計算能力後,返回404。另外也不安全,此類探測性的請求在生產環境還是挺多的,這些請求在apache端就應該過濾掉。
2. 和mod_jk的jmount配置類似,每個模塊需要一行
ProxyPass /blog
http://localhost:8080/blog
min=5 smax=16 max=64 ttl=300 timeout=20
ProxyPass /user
http://localhost:8080/user
min=5 smax=16 max=64 ttl=300 timeout=20
ProxyPass /mo http://localhost:8080/mo min=5 smax=16 max=64 ttl=300 timeout=20
缺點:連接池沒有共用,如上面的配置每行都會創建自己的連接池。可以把apache日誌調到debug來查看。
由於我們使用Worker MPM,每個workor都有自己的連接池,連接池最大值同ThreadsPerChild,如配置
<IfModule worker.c>
ServerLimit 16
StartServers 5
MaxClients 1024
MinSpareThreads 25
MaxSpareThreads 75
ThreadsPerChild 64
</IfModule>
理論上最多有16個連接池,如果用第2種配置方式,連接池數就是16*3=48, 每個池最大64,就是最多有48*64=4096個連接到後端服務器。
而採用ProxyPassMatch,不會出現同一個workor創建多個連接池的問題,最多有16*64=1024 連接到後端服務器。
timeout=20: 連接超時時間,apache等待backend server接收/發送數據時間,默認和ProxyTimeout設置的時間相同。 該參數和mod_jk的 worker.localnode.socket_timeout 含義一致 , 指一個請求轉發給backend server後,最長等待的時間(以秒爲單位), 如果backend server對這個請求的響應時間超過了{timeout}秒,則apache返回502給用戶,並且關閉和backend server的連接,所以timeout不能設置的過小,否則用戶會看到502錯誤。
min=5 smax=16 max=64 ttl=300 : 連接池範圍[min-max],超過16(smax)後按需創建連接。當連接數超過16(smax),非活動連接且空閒時間超過300(ttl)秒的會被apache關閉。如果是worker模式,max的默認值和ThreadsPerChild一致。
注意ttl和timeout區別
jetty配置相關
====================================================
<Set name="ThreadPool"> <New class="org.eclipse.jetty.util.thread.QueuedThreadPool"> <Set name="minThreads">10</Set> <Set name="maxThreads">200</Set> </New> </Set> <Call name="addConnector"> <Arg> <New class="org.eclipse.jetty.server.nio.SelectChannelConnector"> <Set name="host"><Property name="jetty.host" /></Set> <Set name="port"><Property name="jetty.port" default="8080"/></Set> <Set name="maxIdleTime">300000</Set> <Set name="Acceptors">2</Set> <Set name="acceptQueueSize">256</Set> <Set name="statsOn">false</Set> <Set name="confidentialPort">8443</Set> <Set name="lowResourcesConnections">20000</Set> <Set name="lowResourcesMaxIdleTime">5000</Set> </New> </Arg> </Call>
線程池:
線程池初始大小minThreads爲10,最大maxThreads爲200,
而任務隊列初始大小爲10, 如果任務隊列大小不夠,每次增加10(同minThreads)
maxIdleTime=300000: 單位毫秒,maxIdleTime值要和ttl的值一致,否則連接的關閉時間以min(maxIdleTime,ttl)爲準
Accpetors=2: 從線程池劃分2個線程用於監聽連接端口
lowResourcesConnections=20000 lowResourcesMaxIdleTime=5000: 當連接數大於20000,表示jetty運行在低資源狀態,此時的lowResourcesMaxIdleTime作爲連接最長的空閒時間,目的在加快連接的回收。20000非精確值,jetty拿“selector.keys.size()“,既當selector的keys大小超過20000時,用lowResourcesMaxIdleTime的值作爲maxIdleTime。
apache worker配置
===========================================================
# 服務器在斷定請求失敗前等待的秒數
# TimeOut指令用於設置Apache等待以下三種事件的時間長度:
# 1. 接受一個GET請求耗費的總時間。
# 2. POST或PUT請求時,接受兩個TCP包之間的時間。
# 3. 應答時TCP包傳輸中兩個ACK包之間的時間。
# default 300
Timeout 15
KeepAlive On
# 一個持久鏈接中允許的最大請求數量
# default 100
MaxKeepAliveRequests 200
# 持久鏈接中服務器在兩次請求之間等待的秒數
# Apache在關閉持久連接前等待下一個請求的秒數。一旦收到一個請求,超時值將會被設置爲Timeout指令指定的秒數。
# default 5
KeepAliveTimeout 10
# 每個子進程在其生存期內允許伺服的最大請求數量,到達MaxRequestsPerChild的限制後,子進程將會結束
# 對於KeepAlive鏈接,只有第一個請求會被計數。事實上,它改變了每個子進程限制最大鏈接數量的行爲。
MaxRequestsPerChild 20000
<IfModule worker.c>
# ServerLimit & ThreadLimit 需要配置其它worker指令前面
# default 16
ServerLimit 16
# 每個子進程可配置的線程數上限, ThreadsPerChild的配值不能超過ThreadLimit,否則啓動報警告並自動調整ThreadPerChild
# default 64
ThreadLimit 64
# 服務器啓動時建立的子進程數, 子進程在啓動時建立這些線程後就不再建立新的線程了
# default 3
StartServers 5
# MaxClients指令設置了允許同時伺服的最大接入請求數量
# 對於混合型的MPM默認值是16(ServerLimit)乘以64(ThreadsPerChild)的結果
MaxClients 1024
# worker的默認值是"75"。這個MPM將基於整個服務器監視空閒線程數。如果服務器中總的空閒線程數太少,子進程將產生新的空閒線程。
# default 75
MinSpareThreads 25
# Apache將按照"其大於等於MinSpareThreads加上ThreadsPerChild的和"自動修正你設置的值
# 75<64+25,所以MaxSpareThreads被重新設置爲64+25=89
# default 250
MaxSpareThreads 75
# 每個子進程建立的線程數,要設在超過64,需求相應配置ThreadLimit
# default 25
ThreadsPerChild 64
</IfModule>
ThreadLimit實際是用來限制 ThreadsPerChild的取值,即 ThreadsPerChild必須不能大於 ThreadLimit。ThreadLimit的默認值是64,所以如果你的ThreadsPerChild=128,啓動apache就給你一個“WARNING: ThreadsPerChild of 128 exceeds ThreadLimit value of 64 threads, lowering ThreadsPerChild to 64. To increase, please see the ThreadLimit directive.“ ,自動把 ThreadsPerChild降級爲64。如果你非要 ThreadsPerChild=128,必須添加 ThreadLimit=N(N大於等於128),ThreadLimit還必須配在其他指令前面,否則無效。
另外MaxClient的值必須<= ThreadsPerChild *ServerLimit,且能被 ThreadsPerChild 整除,默認值是 ThreadsPerChild *ServerLimit ( ThreadsPerChild 表示實際使用值,可能被 lowering了 )
MPM混合模式下,每個子進程根據實際ThreadsPerChild值一次性創建好所有線程,且在子進程活動期間不會再創建或銷燬線程,線程要麼工作要麼空閒。
如果線程數不夠,apache創建一個子進程批量增加可用線程。
上面配置MaxSpareThreads=75是有問題的,因爲MinSpareThreads=25, ThreadsPerChild=64,當一個進程下的 64線程中,有超過ThreadsPerChild-MinSpareThreads=64-25=39已經投入工作,此時空閒線程數小於 MinSpareThreads,是必要創建更多的空閒線程以保持空閒線程在[MinSpareThreads, MaxSpareThreads]範圍內。新進程會創建ThreadsPerChild個線程 。 那麼此時就有 MinSpareThreads+ThreadsPerChild = 25+64 = 89 個空閒線程,如果MaxSpareThreads < 89,就需要銷燬空閒線程,剛創建又銷燬顯然是不合理的。 所以apache啓動時會把MaxSpareThreads調整爲>= MinSpareThreads+ThreadsPerChild的值 。
另外StartServers被設置爲5,啓動初始創建6個進程,1個主進程(控制進程)和5個子進程,每個子進程初始化64個線程,5*64=320空閒線程,大於MaxSpareThreads(89),所以有4個子進程很快被殺掉,啓動apache時可以用“ps -ux“觀察到,
比較合理的worker配置
<IfModule worker.c>
# 配置都採用默認值,可以去掉
ServerLimit 16
ThreadLimit 64
StartServers 3
MinSpareThreads 25
MaxSpareThreads 250
# 應用特殊配置值
MaxClients 1024
ThreadsPerChild 64
</IfModule>
worker MPM:混合的多線程多進程
由於使用線程來處理請求,可以處理海量請求,而系統資源的開銷小於基於進程的MPM。但是,它也使用了多進程,每個進程又有多個線程,以獲得基於進程的MPM的穩定性。