1、簡介:
每一個Tomcat worker是一個服務於web server、等待執行servlet的Tomcat實例。例如咱們常用像Apache之類的web server轉發sevlet請求給位於其後面的一個Tomcat進程(也就是前面所說的worker)。本文詳細介紹瞭如何配置各類類型worker和loadbalance,並說明了各類類型worker的特性和loadbalance配置的原理。
2、爲何使用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的全部情況。
3、workers.properties配置說明:
定義Tomcat workers的方法是在apache的conf目錄下編寫一個名爲「workers.properties」的屬性文件。本文將詳細解釋如何進行配置的:
1.定義Workers列表:
定義workers的方法就是在apache的conf目錄下編寫一個workers.properties文件,使其做爲apache的插件來發揮做用。
定義workers列表的格式:
worker.list = <使用「,」分割的worker 名字列表> 例如:
worker.list= worker1, worker2 當apache啓動時,workers.properties做爲插件將初始化出如今worker.list列表中的workers。
2.定義Workers的類型:
每一個被命名的worker都應有一些關於其自身的附加信息。這些信息包括了worker的類型和其它相關信息。這裏討論的是JK1.2.5中定義的workers類型。
定義worker類型的格式:
worker . worker名字. type = worker名字的命名最好遵循java的命名規範。
worker類型取值於下面的表格:
定義一個名爲「local」的worker,其使用ajpv12協議與Tomcat 進程通信:
worker.local.type=ajp12 定義一個名爲「remote」的worker,其使用ajpv13協議與Tomcat 進程通信:
worker.remote.type=ajp13 定義一個名爲「fast」的worker,其使用JNI的方式與Tomcat 進程通信:
worker.fast.type=jni 定義一個名爲「loadbalancer」的worker,其做爲對多個Tomcat 進程的負載平衡使用:
worker.loadbalancer.type=lb 各個類型具備不一樣的行爲,咱們在下文中會詳細解釋。
3.設置Worker屬性:
在定義worker以後,還須要提供各個worker的屬性,這些屬性的定義使用下面的方式:
worker.. <屬性> = <屬性值> 3-1 ajp12類型的Worker屬性:. ajp12類型的worker工做時使用基於TCP/IP socket的ajpv12協議轉發請求給「進程外」Tomcat worker。
ajp12 worker屬性以下:
host:
偵聽ajp12請求的Tomcat worker主機。
port:
Tomcat worker主機的偵聽端口。
lbfactor:
當此Tomcat worker被用於一個負載平衡worker使用時,此屬性將被使用。它定義了此worker的負載平衡權值。
例如:下面的「worker1」定義了一個位於www.x.com主機上的Tomcat,它使用8007端口偵聽apache發來的請求,並具備2.5的負載權值
worker.worker1.host=www.x.comworker.worker1.port=8007worker.worker1.lbfactor=2.5 注意:在ajpv12協議中,針對每一個請求都要一個鏈接創建、使用、關閉。其默認偵聽端口爲8007。
3-2 ajp13類型的Worker屬性:
ajp13類型的worker工做時使用基於TCP/IP socket的ajpv13協議轉發請求給「進程外」Tomcat worker。
ajpv13協議與ajpv12協議的主要不一樣:
* ajpv13具備更豐富的二進制協議,它使用將頻繁使用的字符串編碼爲小整數的方式對請求數據進行壓縮。
* ajpv13重用打開的socket並保留這些打開的socket以處理未來的請求。這在apache與Tomcat之間具備防火牆的網絡環境下是必要的。
* ajpv13具備對SSL信息的處理能力,以至容器可以實現SSL的相關方法(如isSecure)。
注意:ajp13當前只能用於支持「進程外」協議的Tomcat 4.0.x, 4.1.x and 5。
下表描述了ajp13worker接受的屬性:
host:
偵聽ajp13請求的Tomcat worker主機。
port:
Tomcat worker主機的偵聽端口。
lbfactor:
當此Tomcat worker被用於一個負載平衡worker使用時,此屬性將被使用。它定義了此worker的負載平衡權值。
cachesize:
當在多線程的web server(例如apache2.0、IIS 、Netscape)中使用JK時,此屬性是有效的。若是將cachesize的值設置爲較高的值,這些支持多線程的web server將得到很好的處理能力。若是此屬性不被設置,則鏈接cache特性將失效。
cache_timeout:
本屬性用於聲明JK在cache中保留一個打開的socket的時間,它對減小web serer的線程數有所幫助。
使用cache_timeout的緣由:
周所周知,一個身背重負的web server(例如apache)創建childs/threads來處理負載,而當負載減小時它將銷燬無用的childs/threads。每一個child在轉發請求給Tomcat時要打開一個ajp13鏈接,而在Tomcat那一端也將創建一個ajp13線程與之通信。可是問題出如今一個ajp13鏈接創建完成後,child沒有及時的釋放那個ajp13鏈接,因爲web server1將保持它的childs/threads運行已處理高負載,即便childs/threads處理快速的靜態內容,在Tomcat端也將積累不少的無用ajp13線程。
socket_keepalive:
當防火牆位於web server與Tomcat之間時,防火牆將嘗試斷開未激活的網絡鏈接。此屬性將告訴操做系統在未激活的鏈接中發送KEEP_ALIVE信息(發送間隔時間依賴於操做系統的設置,通常爲120秒),這樣將防止防火牆切斷未激活的網絡鏈接。
但此設置並非萬能鑰匙,它對於某些防火牆也無能爲力。
socket_timeout:
此屬性說明鏈接在未激活的情況下持續多久,web server將主動切斷之。這是一個使Tomcat端的陳舊線程不致過多的好方法,可是也帶來了在下一次請求到來時須要從新打開socket的開銷。此屬性與cache_timeout有相似的功效,可是它工做在non-cache模式。
connect_timeout:
web server在鏈接創建後將一個PING請求發送到ajp13協議的鏈接上。 此屬性說明了web server等待PONG迴應的時間(以ms爲單位)。此屬性在jk 1.2.6版本被增長進來,以求避免Tomcat的死機,Tomcat 3.3.2+, 4.1.28+ and 5.0.13+實現了對使用ajp13的 ping/pong的支持。此屬性默認爲失效的。
prepost_timeout:
web server在轉發一個請求後將一個PING請求發送到ajp13協議的鏈接上。此屬性說明了web server等待PONG迴應的時間(以ms爲單位)。此屬性在jk 1.2.6版本被增長進來,以求避免Tomcat的死機,Tomcat 3.3.2+, 4.1.28+ and 5.0.13+實現了對使用ajp13的 ping/pong的支持。此屬性默認爲失效的。
reply_timeout:
此屬性告訴web server在接到遠端的Tomcat已死並實時的切換到集羣中的另一個Tomcat的迴應以前等待一段時間。默認狀況下web server將永遠等待。屬性值爲web server要等待迴應的時間(以ms爲單位),因此若是具備運行時間較長的servlet時設置其值要當心。此屬性在jk 1.2.6版本被增長進來,以求避免Tomcat的死機和在支持ajp13的servlet引擎上發生的問題。此屬性默認爲失效的。
recovery_options:
此屬性說明了web server在檢測到Tomcat失敗後如何進行恢復工做。默認狀況下,web server將轉發請求給處於負載平衡模式中的另外一個Tomcat。屬性值爲0,說明所有恢復;屬性值爲1,說明若是在Tomcat接到請求後出現失敗情況,則不進行恢復;屬性值爲2,說明若是在Tomcat發送http頭給客戶端後出現失敗情況,則不進行恢復;屬性值爲3,說明若是在Tomcat接到請求後出現失敗情況或者在Tomcat發送http頭給客戶端後出現失敗情況,則不進行恢復。此屬性在jk 1.2.6版本被增長進來,以求避免Tomcat的死機和在支持ajp13的servlet引擎上發生的問題。此屬性默認爲所有恢復。
例如:一個名爲「worker2」的worker的配置:
java
worker.worker2.host=www2.x.com worker.worker2.port=8009 worker.worker2.lbfactor=3.5 worker.worker2.cachesize=10 worker.worker2.cache_timeout=600 worker.worker2.socket_keepalive=1 worker "worker2" want ajp13 connection to be dropped after 5mn (timeout) worker.worker2.socket_timeout=300
說明:上例中的worker要求操做系統在鏈接上發送KEEP-ALIVE信號。
注意:在ajpv13協議中默認端口爲8009。
4.設置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不該出如今worker.list屬性中。
* sticky_session:表述是否將對SESSION ID的請求路由回到相同的Tomcat worker。若是屬性值不爲0,它將被設置爲JK_TRUE,session將是粘性的,即SESSION ID的請求路由回到相同的Tomcat worker;當Tomcat正使用可以跨越多個Tomcat實例持久化session數據的Session Manager時,它將被設置爲JK_FALSE。屬性默認值爲JK_TRUE。
例如:worker balance1管理着兩個workers:worker一、worker2:
worker.balance1.balanced_workers=worker1, worker2 5.高級lb Worker屬性:
JK 1.2.x版本經過增長兩個新的屬性:local_worker_only 和 local_worker 爲lb worker增添了新的負載平衡和容錯支持。
下面讓咱們舉一個實際的環境做爲example:
一個集羣具備兩個節點(worker1+worker2),一個web server與tomcat workers一前一後,一個負載平衡器(lb Worker)位於節點的前面、web server的後面。
配置以下:node
worker.list=router # Define a 'local_worker' worker using ajp13 worker.worker1.port=8009 worker.worker1.host=node1.domain.org worker.worker1.type=ajp13 worker.worker1.lbfactor=1 worker.worker1.local_worker=1 # Define another 'local_worker' worker using ajp13 worker.worker2.port=8009 worker.worker2.host=node2.domain.org worker.worker2.type=ajp13 worker.worker2.lbfactor=1 worker.worker2.local_worker=0 # Define the LB workerworker.router.type=lb worker.router.balanced_workers=worker1,worker2 worker.router.local_worker_only=1
在worker1和worker2上的local_worker標誌告訴lb_worker哪一個鏈接屬於本地worker。
若是local_worker值爲非0,則它將被設置爲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的屬性值爲非0,則它被設置爲 JK_TRUE,不然被設置爲 JK_FALSE。當它被設置爲 JK_TRUE時,這個沒有session id的請求將獲得一個錯誤做爲迴應,不然lb_worker將嘗試將請求路由到其它的被管理的worker上。若是其中的一個worker處於錯誤狀態,而且恢復會話的工做並無任何改變,local worker將查找這個沒有session id的請求(由於在local worker中保存有這個請求的session),而其它的worker只能查找帶有session id的請求。
注意:local_worker默認值是0,local_worker_only默認值也是0。
6.爲何須要這麼複雜的過程嗎?
由於咱們對於一個關閉的節點須要一個具備靈性的維護。
在節點前面的平衡器週期性的對每一個節點的特定端口進行查詢。若是咱們從集羣中移走一個節點,咱們就會隱性的關閉掉這個特定的端口。因爲負載平衡器不能鏈接它,這個節點將被標記爲down。可是咱們沒有移動在那個關閉的節點上的session到其它的節點上。在這個環境下,若是平衡器發送一個沒有session id的請求到一個端口被關掉的節點,那麼一個錯誤將發生。若是平衡器測試到一個節點被標記爲down的狀態,而沒有其它的節點容許發送沒有session id的請求。這樣這些陳舊的session請求就只有路由到那個被關閉的節點才能被接受。在一段時間後,這些陳舊的session將超時。因爲全部的陳舊的session過時,那個不可達(被關閉)的節點將失去這個請求。同時也會致使咱們的servlet系統發送一個沒有session id的重定向迴應給瀏覽器。
可是可能被關閉的節點將會up,從新加入到集羣中來,在它上面仍將保留着陳舊的session。因此在最後一個session超時後,更新節點可以爲陳舊的session的恢復帶來但願,而不是殺掉sessions或者把它們移到其它節點上。並且有時若是那些陳舊的session中有許多big的對象,那麼移動它們也將花費許多時間。
7.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 2.0)上。同時還應該確認在web server上使用的線程方案是否與被使用的JK web server插件相匹配。
因爲jni worker 打開了一個JVM,它將接受一些屬性(例如classpath等)並將其傳遞給JVM:
worker.worker名.class_path:「進程內」的JVM要使用的classpath。它將包括全部的Tomcat的jar文件和class、配置文件等。
爲了得到JSP編譯器的支持,咱們須要將Javac添加到classpath中。固然對於Java2須要添加tools.jar到classpath,而對於JDK1.xx則要添加classes.zip到classpath。
worker.worker名.class_path:用於以多行的形式聲明多個classpath。JK環境將用「:」或者「;」把這些classpath;鏈接起來。
例如:給名爲「wrkjni」的worker設置classpath。
worker.wrkjni.class_path=/var/tomcat3/lib/tomcat.jarworker.wrkjni.class_path=/opt/IBMJava2-131/lib/tools.jar worker.worker名.bridge:用於標識將經過JNI方式被使用的Tomcat的類型。此屬性目前有兩個屬性值:tomcat32 or tomcat33。Tomcat 3.2.x雖然已通過時,可是被提供用於發佈在一些相似iSeries系統上。此屬性的默認值爲tomcat33。
例如:給「wrkjni」設置bridge類型爲tomcat3.3。
worker.wrkjni.bridge=tomcat33 worker.worker名.cmd_line: 此屬性提供了在Tomcat啓動代碼執行的命令行。使用時將命令行的命令、參數分解爲多個cmd_line屬性。JK環境經過在各個cmd_line屬性值之間添加空格將這些cmd_line鏈接在一塊兒。
例如:設置「wrkjni」的cmd_line屬性。
worker.wrkjni.cmd_line=-configworker.wrkjni.cmd_line=/etc/tomcat3/conf/alt-server.xmlworker.wrkjni.cmd_line=-homeworker.wrkjni.cmd_line=/var/tomcat3 上面例子中的第一行聲明瞭-config參數名,而第二行聲明瞭與之對應的參數值。第三行與第四行同理。
worker.worker名.jvm_lib:用於聲明JVM的實現庫的完整路徑。Jni worker使用這個路徑動態裝載JVM。
例如:設置「wrkjni」的JVM shared lib (IBM SDK on Linux)。
worker.wrkjni.jvm_lib=/opt/IBMJava2-131/jre/bin/classic/libjvm.so 例如:設置「wrkjni」的JVM shared lib (Sun SDK on Windows)。
worker.wrkjni.jvm_lib=c:\JDK\1.3.1\jre\bin\classic worker.worker名.stdout:設置JVM寫它的System.out的完整路徑位置。
例如:將「wrkjni」的JVM系統輸出路徑設置爲/var/log/http/jk-jvm-out.log。
worker.wrkjni.stdout=/var/log/http/jk-jvm-out.log worker.worker名.stderr:設置JVM寫它的System.err的完整路徑位置。
例如:將「wrkjni」的JVM系統錯誤輸出路徑設置爲/var/log/http/jk-jvm-err.log worker.wrkjni.stderr=/var/log/http/jk-jvm-out.log worker.worker名.ms:設置JVM的初始堆大小。
例如:設置「wrkjni」的JVM的初始堆爲64M。
worker.wrkjni.ms=64 worker.worker名.mx:設置JVM的最大的堆大小。
例如:設置「wrkjni」的JVM堆最大爲128M worker.wrkjni.mx=128 worker.worker名.sysprops:設置JVM的系統屬性。
例如:設置「wrkjni」的JVM使用法語。
worker.wrkjni.sysprops=-Duser.region=FR worker.worker名.ld_path:設置附加的動態連接庫路徑(相似於LD_LIBRARY_PATH) 例如:添加一些動態連接庫路徑到「wrkjni」的java環境中。 程序員
worker.wrkjni.ld_path=/opt/IBMJava2-131/jre/bin/ worker.wrkjni.ld_path=/opt/IBMJava2-131/jre/bin/classic
注意:在Linux下,上面的ld_path並不能更新LD_LIBRARY_PATH,因此須要在執行web server以前手動更新LD_LIBRARY_PATH,。
8.屬性文件宏:
咱們能夠在屬性文件中定義「宏」。這些宏讓咱們定義屬性,並在之後使用它們來構建其它的屬性文件。當咱們修改Java Home、Tomcat Home、系統路徑分隔符時這是頗有用的。
例如:定義了屬性workers.tomcat_home、workers.java_home。
workers.tomcat_home=d:\tomcatworkers.java_home=d:\sdk\jdk1.2.2 在定義worker.inprocess.class_path時就可使用前面定義的workers.tomcat_home。
worker.inprocess.class_path=$(workers.tomcat_home)$(ps)classes 9.一個簡單而完整的worker.properties:
文件中定義了比較完整的結構,能夠作爲參考模版:
* 一個位於localhost的使用8007端口的ajp12 worker;
* 一個位於localhost的使用8008端口的ajp13 worker;
* 一個jni worker;
* 一個lb worker:負責ajp12 worker、ajp13 workers的負載平衡。
文件內容以下:web
# Define some properties workers.apache_log=/var/log/httpd/ workers.tomcat_home =/var/tomcat3 workers.java_home=/opt/IBMJava2-131/ps =/ # Define 4 workers, 3 real workers using ajp12, ajp13, jni, the last one being a loadbalancing workerworker.list =worker1, worker2, worker3, worker4# Set properties for worker1 (ajp12) worker.worker1.type=ajp12worker.worker1.host =locahostworker.worker1.port=8007worker.worker1.lbfactor =5# Set properties for worker2 (ajp13)worker.worker2.type =ajp13worker.worker2.host =locahostworker.worker2.port=8009worker.worker2.lbfactor =50worker.worker2.cachesize=10worker.worker2.cache_timeout =600worker.worker2.socket_keepalive=1worker.worker2.socket_timeout =300# Set properties for worker3 (jni)worker.worker3.type =jni# Set worker3 bridge type, here Tomcat 3.3worker.worker3.bridge =tomcat33# Set worker3 classpathworker.worker3.class_path =$(workers.tomcat_home)$(ps)classesworker.worker3.class_path =$(workers.tomcat_home)$(ps)lib$(ps)tomcat.jar# Set worker3 tomcat command lineworker.worker3.cmd_line =-homeworker.worker3.cmd_line =$(workers.tomcat_home)# Set worker3 Tomcat/JVM settingsworker.worker3.jvm_lib=$(workers.java_home)$(ps) jre$(ps)bin$(ps)classic$(ps)libjvm.soworker.worker3.stdout =$(workers.apache_log)$(ps)inprocess.stdoutworker.worker3.stderr =$(workers.apache_log)$(ps)inprocess.stderrworker.worker3.sysprops =tomcat.home=$(workers.tomcat_home)# Set properties for worker4 (lb) which use worker1 and worker2worker.worker4.balanced_workers=worker1,worker2