一簡介
每個Tomcat worker是一個服務於web server等待執行servlet的Tomcat實例例如我們經常使用像Apache之類的web server轉發sevlet請求給位於其後面的一個Tomcat進程(也就是前面所說的worker)本文詳細介紹了如何配置各種類型worker和 loadbalance並說明了各種類型worker的特性和loadbalance配置的原理
二為什麼使用Tomcat workers
上文描述了一個非常簡單的結構事實上能夠配置多個Tomcat workers來處理web server轉發的servlet請求而這樣配置的理由不外乎以下幾種假想環境
* 我們在開發環境中發布不同的Tomcat workers為各自不同的應用服務當然在開發環境中的開發者共享同一個web server但是每個Tomcat worke服務於擁有它的開發者
* 我們在不同的Tomcat進程上定義各自的虛擬主機這樣不同的公司可以使用各自的web site從而使他們的web site得到了合理的分割
* 我們提供負載平衡的web site也就意味著同時使用多個Tomcat workers而每個Tomcat worker具有獨立的主機並且在workers之間要分配通過web server轉發來的請求
當然這些假想情況也許並不能涵蓋使用多個workers的所有狀況
三workersproperties配置說明
定義Tomcat workers的方法是在apache的conf目錄下編寫一個名為workersproperties的屬性文件本文將詳細解釋如何進行配置的
定義Workers列表
定義workers的方法就是在apache的conf目錄下編寫一個workersproperties文件使其作為apache的插件來發揮作用
定義workers列表的格式
workerlist =<使用分割的worker 名字列表>
例如
workerlist= worker worker
當apache啟動時workersproperties作為插件將初始化出現在workerlist列表中的workers
定義Workers的類型
每個被命名的worker都應有一些關於其自身的附加信息這些信息包括了worker的類型和其它相關信息這裡討論的是JK中定義的workers類型
定義worker類型的格式
worker worker名字 type =<worker類型>
worker名字的命名最好遵循java的命名規范
worker類型取值於下面的表格
定義一個名為local的worker其使用ajpv協議與Tomcat 進程通訊
workerlocaltype=ajp
定義一個名為remote的worker其使用ajpv協議與Tomcat 進程通訊
workerremotetype=ajp
定義一個名為fast的worker其使用JNI的方式與Tomcat 進程通訊
workerfasttype=jni
定義一個名為loadbalancer的worker其作為對多個Tomcat 進程的負載平衡使用
workerloadbalancertype=lb
各個類型具有不同的行為我們在下文中會詳細解釋
設置Worker屬性
在定義worker之後還需要提供各個worker的屬性這些屬性的定義使用下面的方式
worker<worker名字><屬性>=<屬性值>
ajp類型的Worker屬性
ajp類型的worker工作時使用基於TCP/IP socket的ajpv協議轉發請求給進程外Tomcat worker
ajp worker屬性如下
host
偵聽ajp請求的Tomcat worker主機
port
Tomcat worker主機的偵聽端口
lbfactor
當此Tomcat worker被用於一個負載平衡worker使用時此屬性將被使用它定義了此worker的負載平衡權值
例如下面的worker定義了一個位於主機上的Tomcat它使用端口偵聽apache發來的請求並具有的負載權值
workerworkerhost=
workerworkerport=
workerworkerlbfactor=
注意在ajpv協議中針對每個請求都要一個連接建立使用關閉其默認偵聽端口為
ajp類型的Worker屬性
ajp類型的worker工作時使用基於TCP/IP socket的ajpv協議轉發請求給進程外Tomcat worker
ajpv協議與ajpv協議的主要不同
* ajpv具有更豐富的二進制協議它使用將頻繁使用的字符串編碼為小整數的方式對請求數據進行壓縮
* ajpv重用打開的socket並保留這些打開的socket以處理將來的請求這在apache與Tomcat之間具有防火牆的網絡環境下是必要的
* ajpv具有對SSL信息的處理能力以致容器能夠實現SSL的相關方法(如isSecure())
注意ajp當前只能用於支持進程外協議的Tomcat x x and
下表描述了ajpworker接受的屬性
host
偵聽ajp請求的Tomcat worker主機
port
Tomcat worker主機的偵聽端口
lbfactor
當此Tomcat worker被用於一個負載平衡worker使用時此屬性將被使用它定義了此worker的負載平衡權值
cachesize
當在多線程的web server(例如apacheIIS Netscape)中使用JK時此屬性是有效的如果將cachesize的值設置為較高的值這些支持多線程的web server將獲得很好的處理能力如果此屬性不被設置則連接cache特性將失效
cache_timeout
本屬性用於聲明JK在cache中保留一個打開的socket的時間它對減少web serer的線程數有所幫助
使用cache_timeout的原因
周所周知一個身背重負的web server(例如apache)建立childs/threads來處理負載而當負載減少時它將銷毀無用的childs/threads每個 child在轉發請求給Tomcat時要打開一個ajp連接而在Tomcat那一端也將建立一個ajp線程與之通訊但是問題出現在一個 ajp連接建立完成後child沒有及時的釋放那個ajp連接由於web server將保持它的childs/threads運行已處理高負載即使childs/threads處理快速的靜態內容在Tomcat端也將積累很多的無用ajp線程
socket_keepalive
當防火牆位於web server與Tomcat之間時防火牆將嘗試斷開未激活的網絡連接此屬性將告訴操作系統在未激活的連接中發送KEEP_ALIVE信息(發送間隔時間依賴於操作系統的設置一般為秒)這樣將防止防火牆切斷未激活的網絡連接
但此設置並不是萬能鑰匙它對於某些防火牆也無能為力
socket_timeout
此屬性說明連接在未激活的狀況下持續多久web server將主動切斷之這是一個使Tomcat端的陳舊線程不致過多的好方法但是也帶來了在下一次請求到來時需要重新打開socket的開銷此屬性與cache_timeout有類似的功效但是它工作在noncache模式
connect_timeout
web server在連接建立後將一個PING請求發送到ajp協議的連接上 此屬性說明了web server等待PONG回應的時間(以ms為單位)此屬性在jk 版本被增加進來以求避免Tomcat的死機Tomcat + + and +實現了對使用ajp的 ping/pong的支持此屬性默認為失效的
prepost_timeout
web server在轉發一個請求後將一個PING請求發送到ajp協議的連接上此屬性說明了web server等待PONG回應的時間(以ms為單位)此屬性在jk 版本被增加進來以求避免Tomcat的死機Tomcat + + and +實現了對使用ajp的 ping/pong的支持此屬性默認為失效的
reply_timeout
此屬性告訴web server在接到遠端的Tomcat已死並實時的切換到集群中的另外一個Tomcat的回應之前等待一段時間默認情況下web server將永遠等待屬性值為web server要等待回應的時間(以ms為單位)所以如果具有運行時間較長的servlet時設置其值要小心此屬性在jk 版本被增加進來以求避免Tomcat的死機和在支持ajp的servlet引擎上發生的問題此屬性默認為失效的
recovery_options
此屬性說明了web server在檢測到Tomcat失敗後如何進行恢復工作默認情況下web server將轉發請求給處於負載平衡模式中的另一個Tomcat屬性值為說明全部恢復屬性值為說明如果在Tomcat接到請求後出現失敗狀況則不進行恢復屬性值為說明如果在Tomcat發送http頭給客戶端後出現失敗狀況則不進行恢復屬性值為說明如果在Tomcat接到請求後出現失敗狀況或者在Tomcat發送http頭給客戶端後出現失敗狀況則不進行恢復此屬性在jk 版本被增加進來以求避免Tomcat的死機和在支持ajp的servlet引擎上發生的問題此屬性默認為全部恢復
例如一個名為worker的worker的配置
workerworkerhost=
workerworkerport=
workerworkerlbfactor=
workerworkercachesize=
workerworkercache_timeout=
workerworkersocket_keepalive=
worker worker want ajp connection to be dropped after mn (timeout)
workerworkersocket_timeout=
說明上例中的worker要求操作系統在連接上發送KEEPALIVE信號
注意在ajpv協議中默認端口為
設置lb Worker屬性
負載平衡類型的worker並不與Tomcat worker通訊它負責管理這些Tomcat worker
其管理范圍如下
* 初始化在web server的worker列表中定義的worker
* 使用worker的負載平衡權值執行基於權值的負載平衡將數量多的請求發送到負載平衡權值高(在web server看來就是更加健壯的)的worker
* 維護在同一個Tomcat worker上的同一個session的請求使其發送到同一個Tomcat worker上以達到Tomcat worker上的session一致性持續性
* 標識已經失敗的Tomcat workers懸空發向它們的請求在被lb worker管理的其它workers上尋找可以失敗恢復的worker
被同一個lb worker管理多個worker之間的負載平衡的(基於它們的lbfactor和當前用戶session)也可以盡量避免由於單一的Tomcat進程死掉而造成這個網站被殺的不良反應
下表說明了lb worker接受的屬性
* balanced_workers一個由分割的worker列表用來聲明lb worker需要被管理的workers這些workers不應出現在workerlist屬性中
* sticky_session表述是否將對SESSION ID的請求路由回到相同的Tomcat worker如果屬性值不為它將被設置為JK_TRUEsession將是粘性的即SESSION ID的請求路由回到相同的Tomcat worker當Tomcat正使用能夠跨越多個Tomcat實例持久化session數據的Session Manager時它將被設置為JK_FALSE屬性默認值為JK_TRUE
例如worker balance管理著兩個workersworkerworker
worker
balance
balanced_workers=worker
worker
高級lb Worker屬性
JK x版本通過增加兩個新的屬性local_worker_only 和 local_worker 為lb worker增添了新的負載平衡和容錯支持
下面讓我們舉一個實際的環境作為example
一個集群具有兩個節點(worker+worker)一個web server與tomcat workers一前一後一個負載平衡器(lb Worker)位於節點的前面web server的後面
配置如下
workerlist=router
# Define a local_worker worker using ajp
workerworkerport=
workerworkerhost=
workerworkertype=ajp
workerworkerlbfactor=
workerworkerlocal_worker=
# Define another local_worker worker using ajp
workerworkerport=
workerworkerhost=
workerworkertype=ajp
workerworkerlbfactor=
workerworkerlocal_worker=
# Define the LB worker
workerroutertype=lb
workerrouterbalanced_workers=workerworker
workerrouterlocal_worker_only=
在worker和worker上的local_worker標志告訴lb_worker哪個連接屬於本地worker
如果 local_worker值為非則它將被設置為JK_TRUE用來標記local worker而JK_FALSE的情況則相反如果至少一個worker被標記為local worker則lb_worker將工作於local worker模式這種模式下所有的local workers將被移到在lb_worker中的內部worker列表的頭部
這意味著一個帶有session id的請求到達lb_worker時相應的worker(根據權值排序權值最大的那個worker)將被確定作為此請求的接受/處理者如果這個 worker死掉/當機請求將被發送到處於非錯誤狀態的第一個local worker如果一個沒有session id的請求到達lb_worker時此請求將被路由到第一個local worker如果所有的local worker均處於錯誤狀態則這時local_worker_only標志顯得尤其重要如果local_worker_only的屬性值為非則它被設置為 JK_TRUE否則被設置為 JK_FALSE當它被設置為 JK_TRUE時這個沒有session id的請求將得到一個錯誤作為回應否則lb_worker將嘗試將請求路由到其它的被管理的worker上如果其中的一個worker處於錯誤狀態並且恢復會話的工作並沒有任何改變local worker將查找這個沒有session id的請求(因為在local worker中保存有這個請求的session)而其它的worker只能查找帶有session id的請求
注意local_worker默認值是local_worker_only默認值也是
為什麼需要這麼復雜的過程嗎?
因為我們對於一個關閉的節點需要一個具有靈性的維護
在節點前面的平衡器周期性的對每個節點的特定端口進行查詢如果我們從集群中移走一個節點我們就會隱性的關閉掉這個特定的端口由於負載平衡器不能連接它這個節點將被標記為down但是我們沒有移動在那個關閉的節點上的session到其它的節點上在這個環境下如果平衡器發送一個沒有 session id的請求到一個端口被關掉的節點那麼一個錯誤將發生如果平衡器測試到一個節點被標記為down的狀態而沒有其它的節點允許發送沒有session id的請求這樣這些陳舊的session請求就只有路由到那個被關閉的節點才能被接受在一段時間後這些陳舊的session將超時由於所有的陳舊的session過期那個不可達(被關閉)的節點將失去這個請求同時也會導致我們的servlet系統發送一個沒有session id的重定向回應給浏覽器
但是可能被關閉的節點將會up重新加入到集群中來在它上面仍將保留著陳舊的session所以在最後一個 session超時後更新節點能夠為陳舊的session的恢復帶來希望而不是殺掉sessions或者把它們移到其它節點上而且有時如果那些陳舊的session中有許多big的對象那麼移動它們也將花費許多時間
jni類型的Worker屬性
jni worker會在web server進程中打開一個JVM並在其中執行Tomcat這叫做進程內worker來往於JVM的消息將通過調用JNI方法被傳遞這使jni worker比那些需要使用ajp消息通訊的進程外worker執行的更快
注意由於JVM是多線程的jni worker應該只被用於在支持對線程的web server(AOLServer IIS Netscape and Apache )上同時還應該確認在web server上使用的線程方案是否與被使用的JK web server插件相匹配
由於jni worker 打開了一個JVM它將接受一些屬性(例如classpath等)並將其傳遞給JVM
workerworker名class_path進程內的JVM要使用的classpath它將包括所有的Tomcat的jar文件和class配置文件等
為了獲得JSP編譯器的支持我們需要將Javac添加到classpath中當然對於Java需要添加toolsjar到classpath而對於JDKxx則要添加classeszip到classpath
workerworker名class_path用於以多行的形式聲明多個classpathJK環境將用或者把這些classpath連接起來
例如給名為wrkjni的worker設置classpath
workerwrkjniclass_path=/var/tomcat/lib/tomcatjar
workerwrkjniclass_path=/opt/IBMJava/lib/toolsjar
workerworker名bridge用於標識將通過JNI方式被使用的Tomcat的類型此屬性目前有兩個屬性值tomcat or tomcatTomcat x雖然已經過時但是被提供用於發布在一些類似iSeries系統上此屬性的默認值為tomcat
例如給wrkjni設置bridge類型為tomcat
workerwrkjnibridge=tomcat
workerworker名cmd_line 此屬性提供了在Tomcat啟動代碼執行的命令行使用時將命令行的命令參數分解為多個cmd_line屬性JK環境通過在各個cmd_line屬性值之間添加空格將這些cmd_line連接在一起
例如設置wrkjni的cmd_line屬性
workerwrkjnicmd_line=config
workerwrkjnicmd_line=/etc/tomcat/conf/altserverxml
workerwrkjnicmd_line=home
workerwrkjnicmd_line=/var/tomcat
上面例子中的第一行聲明了config參數名而第二行聲明了與之對應的參數值第三行與第四行同理
workerworker名jvm_lib用於聲明JVM的實現庫的完整路徑Jni worker使用這個路徑動態裝載JVM
例如設置wrkjni的JVM shared lib (IBM SDK on Linux)
workerwrkjnijvm_lib=/opt/IBMJava/jre/bin/classic/libjvmso
例如設置wrkjni的JVM shared lib (Sun SDK on Windows)
workerwrkjnijvm_lib=c:\JDK\\jre\bin\classic
workerworker名stdout設置JVM寫它的Systemout的完整路徑位置
例如將wrkjni的JVM系統輸出路徑設置為/var/log/
workerwrkjnistdout=/var/log/
workerworker名stderr設置JVM寫它的Systemerr的完整路徑位置
例如將wrkjni的JVM系統錯誤輸出路徑設置為/var/log/
workerwrkjnistderr=/var/log/
workerworker名ms設置JVM的初始堆大小
例如設置wrkjni的JVM的初始堆為M
workerwrkjnims=
workerworker名mx設置JVM的最大的堆大小
例如設置wrkjni的JVM堆最大為M
workerwrkjnimx=
workerworker名sysprops設置JVM的系統屬性
例如設置wrkjni的JVM使用法語
workerwrkjnisysprops=Duserregion=FR
workerworker名ld_path設置附加的動態鏈接庫路徑(類似於LD_LIBRARY_PATH)
例如添加一些動態鏈接庫路徑到wrkjni的java環境中
workerwrkjnild_path=/opt/IBMJava/jre/bin/
workerwrkjnild_path=/opt/IBMJava/jre/bin/classic
注意在Linux下上面的ld_path並不能更新LD_LIBRARY_PATH所以需要在執行web server之前手動更新LD_LIBRARY_PATH
屬性文件宏
我們可以在屬性文件中定義宏這些宏讓我們定義屬性並在以後使用它們來構建其它的屬性文件當我們修改Java HomeTomcat Home系統路徑分隔符時這是很有用的
例如定義了屬性workerstomcat_homeworkersjava_home
workerstomcat_home=d:\tomcat
workersjava_home=d:\sdk\jdk
在定義workerinprocessclass_path時就可以使用前面定義的workerstomcat_home
workerinprocessclass_path=$(workerstomcat_home)$(ps)classes
一個簡單而完整的workerproperties
文件中定義了比較完整的結構可以做為參考模版
* 一個位於localhost的使用端口的ajp worker
* 一個位於localhost的使用端口的ajp worker
* 一個jni worker
* 一個lb worker負責ajp workerajp workers的負載平衡
文件內容如下
# Define some properties
workersapache_log=/var/log/httpd/
workerstomcat_home=/var/tomcat
workersjava_home=/opt/IBMJava/
ps=/
# Define workers real workers using ajp ajp jni the last one being a loadbalancing worker
workerlist=worker worker worker worker
# Set properties for worker (ajp)
workerworkertype=ajp
workerworkerhost=locahost
workerworkerport=
workerworkerlbfactor=
# Set properties for worker (ajp)
workerworkertype=ajp
workerworkerhost=locahost
workerworkerport=
workerworkerlbfactor=
workerworkercachesize=
workerworkercache_timeout=
workerworkersocket_keepalive=
workerworkersocket_timeout=
# Set properties for worker (jni)
workerworkertype=jni
# Set worker bridge type here Tomcat
workerworkerbridge=tomcat
# Set worker classpath
workerworkerclass_path=$(workerstomcat_home)$(ps)classes
workerworkerclass_path=$(workerstomcat_home)$(ps)lib$(ps)tomcatjar
# Set worker tomcat command line
workerworkercmd_line=home
workerworkercmd_line=$(workerstomcat_home)
# Set worker Tomcat/JVM settings
workerworkerjvm_lib=$(workersjava_home)$(ps)jre$(ps)bin$(ps)classic$(ps)libjvmso
workerworkerstdout=$(workersapache_log)$(ps)inprocessstdout
workerworkerstderr=$(workersapache_log)$(ps)inprocessstderr
workerworkersysprops=tomcathome=$(workerstomcat_home)
# Set properties for worker (lb) which use worker and worker
workerworkerbalanced_workers=workerworker
From:http://tw.wingwit.com/Article/program/Java/ky/201311/28541.html