Part I:html
取經處: http://www.ramkitech.com/2012/10/tomcat-clustering-series-simple-load.htmljava
http://blog.csdn.net/bluishglc/article/details/6867358linux
這部分先弄個簡單的Load Balance的例子。web
對Apache Server和Tomcat兩者之間的關係有必定了解後,應該能夠理解下面盜取的結構圖:數據庫
在實際生產環境中,不會採起單個Tomcat實例的架構,由於沒有任何災備機制。一旦發生自熱災害,硬件損壞或者內存泄漏等嚴重錯誤,都會致使所謂的服務器宕機。apache
爲了不這種狀況的發生,一定採用災備機制。典型的作法就是在多臺server上部署同一個Application,而後各個server之間相互爲backup。編程
但這樣,隨之而來的問題就是如何分佈用戶請求。不可能告訴用戶全部的Tomcat server IP,而後一會訪問這個,過一會又訪問另一個,太不人性化了!centos
這就引出了負載均衡(Load Balance)這個概念。全部用戶請求都由Apache Server接收,以後根據內部邏輯分發請求給各個Tomcat。瀏覽器
簡單的Load Balance:tomcat
環境:CentOS7,Tomcat8.5.4,Apache httpd-2.4.23,tomcat-connectors-1.2.41
1. 安裝Apache Server(略過)
2. 錢不夠,只有一臺筆記本,遂安裝Tomcat並配置多個實例來模擬多個tomcat server(能夠參照以前的blog進行配置)
假設3個tomcat實例命名爲tomcat1,tomcat2,tomcat3
3. 安裝並編譯mod_jk.so(略過),用於以後Apache Server同Tomcat通訊。
4. 以上準備工做完成後,下面就是Load Balance的配置嘍。
1. 經過mod_jk moudle創建Apache Server同Tomcat的通訊
1. 在${ApacheServerPath}/conf下建立workers.properties,內容以下:
worker.list=loadbalancer,stat
worker.loadbalancer.type=lb
worker.loadbalancer.balance_workers=tomcat1,tomcat2,tomcat3
worker.tomcat1.type=ajp13
worker.tomcat1.port=8009
worker.tomcat1.host=localhost
worker.tomcat2.type=ajp13
worker.tomcat2.port=8019
worker.tomcat2.host=localhost
worker.tomcat3.type=ajp13
worker.tomcat3.port=8029
worker.tomcat3.host=localhost
worker.stat.type=status
2. 在${ApacheServerPath}/conf/httpd.conf中添加以下內容:
LoadModule jk_module modules/mod_jk.so
JkWorkersFile conf/workers.properties
JkLogFile logs/mod_jk.log
JkLogLevel emerg
JkLogStampFormat "[%a %b %d %H:%M:%S %Y] "
JkOptions +ForwardKeySize +ForwardURICompat -ForwardDirectories
JkRequestLogFormat "%w %V %T"
JkMount /status stat
JkMount /* loadbalancer
5. 啓動Apache Server,各個tomcat實例進行負載均衡測試。
測試以前先在各個ROOT下建立index.html文件,用來區分哪一個tomcat server被調用。
1. 請求localhost,看整個服務是否可用;
2. 請求localhost/status,看Load Balance狀況。
Part II:
看到一篇稍好的blog,算是補充吧。http://freeloda.blog.51cto.com/2033581/1301888/
接Part I,雖然實現了簡單的負載均衡,可是很明顯存在問題。不少blog都拿購物車舉例,也很通俗易懂:Part I實現的負載均衡基本會將每次的請求均勻轉發到tomcat server上。當咱們在購物車中添加了一項,以後再刷新頁面發送新的請求,這時的Apache Server將會分發該請求到新的tomcat server,再一次建立新的session,致使購物車以前的添加項所有丟失,嚴重影響用戶體驗。
爲解決這個問題,能夠經過Sticky Session(粘性會話),實際上就是讓Apache Server可以識別正確的Tomcat Server。
從Session的簡單原理入手,當用戶第一次請求時,Apache Server轉發到Tomcat Server,相應建立session(位於tomcat server的內存中)。一個Session能夠想象成相似Map的容器,能夠CRUD各類屬性。對應這個session,有一個Session ID(在Tomcat中,又稱爲jsessionid)。該Session ID將附到HTTP Response中返回客戶端,存儲於瀏覽器中。當用戶再次發送相似的請求時,會將Session ID封裝到HTTP Request中,經Apache Server轉發到Tomcat Server。
因此,對Session ID改進,達到Sticky Session的目的。
因爲Session ID是Tomcat Server生成的,因此理所應當修改各個Tomcat的配置文件。
1. 修改每一個tomcat實例的server.xml - 在Engine標籤中添加jvmRoute屬性(和workers.properties中的balance_workers各項相對應)
OK!
2. 測試,啓動Apache Server和Tomcat。
在瀏覽器發出的HTTP Request中,會發現
Cookie:JSESSIONID=40025608F7B50E42DFA2785329079227.tomcat1
實現Sticky Session。
Part III:
實現Sticky Session還不足以解決某個Tomcat宕掉的影響。假設某個Tomcat宕掉,那相應的Session所有失效,嚴重影響用戶體驗!
這就又引出Session Replication(複製會話)的概念。也就是相同的Session在其餘Server中也存在,當Server宕掉,另外一臺能夠當即被使用。
實現會話複製的方案有很多:
1. 創建Session服務器,全部Session所有存儲於該服務器之上。當某個Tomcat Server宕掉後,其餘server能夠從該Session服務器中複製一份過來。缺點是一旦Session服務器宕掉,全部Session均失效,代價更大。
2. Tomcat集羣方案
1. 採用多播的方式在Tomcat Server之間通訊來複制Session,一個server的session在其餘全部server均存在。缺點是若是參與集羣的server數量過多,必然會致使單個server的負載太重。因此不適合大集羣環境。
2. 採用Backup機制,好比兩臺Tomcat之間通訊以保證各自Session在對方有備份。
先來嘗試多播方式的Tomcat集羣:)
一共3個步驟:
1. enable多播路由;2. 添加Cluster標籤到conf/server.xml中;3. 給app添加<distributable/>
這裏面的多播是網絡通訊裏的概念,正在不斷了解過程當中。。。區別於單播與廣播,和字面意思相一致。對於Tomcat集羣來講,各個之間必然進行通訊,成爲一組,多播是首選吧。
既然是會話複製,就應該涉及到session的管理問題。在Tomcat集羣中,SessionManager負責session的管理,分如下4種:
Standard Manager:
這個是tomcat默認使用的session管理。但針對stand-alone(單機)tomcat,不能用於tomcat集羣環境。
Persistent Manager:
會將session信息按期存儲於文件/數據庫中,能夠配置以何種方式存儲。但因爲按期存儲和更新,可能致使session更新不夠及時。
Delta Manager:
Tomcat集羣默認使用的session管理。每當session發生變化,好比setAttribute(), removeAttribute(),都會及時在其餘集羣節點上更新。這也就很容易形成集羣中的tomcat負載太重,因此不適合大規模的集羣環境。
Backup Manager:
這個能夠看做是Persistent Manager和Delta Manager的折中。兩套Tomcat server互爲Backup。
--------------NND,先吐槽下,多播方式的Tomcat集羣愣是前先後後耗費了2天的時間才搞定!咱國人的博客水準真是亟待提升,仍是參考了老外的博客最終搞定。。。
環境:根據Part II已經實現Sticky Session,但要說明下個人CentOS7是Win7上的虛擬機。
下面記錄我在build多播方式的Tomcat集羣過程當中的每步以及遇到的問題:
1. 按照官方文檔以及該blog,copy其中Cluster標籤的默認配置到各個tomcat實例中的server.xml文件中(位於Enginee標籤下),併爲各個tomcat實例設置不一樣的Receiver端口。
這裏須要注意,tomcat-8.5.4關於Cluster的默認配置裏已經沒有<ClusterListener className="org.apache.catalina.ha.session.JvmRouteSessionIDBinderListener"/>,並且<Interceptor className="org.apache.catalina.tribes.group.interceptors.MessageDispatch15Interceptor"/>已經變成<Interceptor className="org.apache.catalina.tribes.group.interceptors.MessageDispatchInterceptor"/>
2. route add -net 224.0.0.0 netmask 240.0.0.0 dev your_ethernet接口,添加your_ethernet接口到路由表中。
3. 在各個tomcat實例的app中的web.xml中添加標籤<distributable/>
OK,啓動httpd和3個tomcat實例(都在CentOS虛擬機上)。
按照該blog的測試方法,查看每一個tomcat實例的manager界面,看是否session之間共享。結果不是。。。
在仔細檢查各個配置文件並肯定沒問題後,開始天馬行空的想,漫無目的的搜索,但大部分的信息都是講怎麼一步步配置還有零散的一些問題解決方案。嘗試了幾個後(好比給Membership標籤添加bind屬性,綁定本地IP;修改Receiver的address屬性值爲本地IP)都沒解決,心想解決問題真心不能靠運氣啊!
可是從哪下手呢? - 日誌
相比較於Windows,在Linux下啓tomcat不會有滾動日誌顯示,不能實時知道tomcat的狀態。
總結一下我所遇到的問題:
1. java.io.IOException: Network is unreachable
Unable to join multicast group, make sure your system has multicasting enabled
很明顯,提示多播功能可能沒有enable。可是個人確作了這步的,並且經過route -e, tcpdump -ni your_ethernet接口 host 228.0.0.4也證明了(好blog)。最後有點兒醍醐灌頂的認爲應該是防火牆的問題,就把CentOS自帶的firewall.service給remove掉了,也防止對Receiver的端口的影響。
2. SimpleTcpCluster.startInternal Unable to start cluster
ChannelException: java.net.SocketException: No such device; No faulty members identified.
這個提示讓人無從下手,但根據這篇blog所說,應該是虛擬機的網絡設置不當形成的。我最後選擇了橋接模式,記得重啓後才生效。
3. skipping state transfer. No members active in cluster group
這個是耗費我時間最多的一項。僅僅提示你No members active而沒有說明可能的緣由!我是各類搜索各類嘗試,整的本身暈暈乎乎的,各類鬱悶(根上仍是網絡通訊/編程這塊不懂形成的)。
在解決這個問題以前,我用公司laptop的Win7環境搭了差很少相同的tomcat集羣+httpd。以後順利實現loadbalance+tomcat集羣。在查看log的過程當中,發現第一個啓來的tomcat會有skipping state transfer. No members active in cluster group的日誌,當時竊喜!說不定我CentOS上的那套集羣實際上已經成功了呢?!惋惜僅限於美好的想法。不過Win7下的log卻是讓我知道了什麼樣的狀況表示tomcat集羣成功built起來了:"Replication member added:org.apache.catalina.tribes.membership.MemberImpl[tcp:"。
誤打誤撞搜到這麼一篇stackoverflow,大概意思是multicast已經enable,可是tomcat就是沒法集羣。裏面提到了IPv4和IPv6,一臉萌比。。。不過下面的回答卻是讓我有了些但願。Tomcat8.5.4默認綁定IPv6,當發現server不工做時,應改綁定IPv4。
在httpd和3個tomcat實例都啓來後,我嘗試請求localhost,獲得503頁面,以後查看mod_jk.log,發現loadbalance沒有問題。再嘗試http直接訪問tomcat,沒有問題。因此判定tomcat接收分發的請求出現問題。因爲接收請求是經過ajp13協議進行,極可能IPv4和IPv6搗鬼了。
參考blog,將tomcat運行環境與IPv4綁定。
到此,多播方式的Tomcat集羣 + 負載均衡 終於搞定!
PS: 能花半天時間作記錄,我也是醉醉的了,估計僅此一次吧:)