1 概述
應用的合理部署即能提高系統的可靠性和穩定性,又能提高系統的可維護性和擴展性。本文檔詳細闡述基於Apache負載均衡和JBOSS7集群的應用系統部署方案和配置步驟。內容涉及部署方案、環境配置、方案特性。
2 安裝步驟
介紹支持以上設計方案所需的各個相關軟件的版本信息及針對以上方案在實施時的詳細配置過程。
2.1 安裝准備
2.1.1 版本列表
| 功能模塊 |
版本 |
下載 |
| JAVA |
jdk-6u45-linux-x64.bin (注:64位) |
|
| 負載均衡 |
Apache2.2.25 (依賴:apr-1.4.8.tar.gz apr-util-1.5.2.tar.gz) |
http://httpd.apache.org/download.cgi |
| mod_jk-1.2.31-httpd-2.2.x.so (注:64位) |
http://archive.apache.org/dist/tomcat/tomcat-connectors/jk/binaries/linux/jk-1.2.31/ |
|
| 集群 |
jboss-eap-6.2.0.zip |
http://www.jboss.org/jbossas/downloads/ |
2.1.2 安裝注意事項
1) 安裝前請先確認操作系統是64位
查看命令:echo $HOSTTYPE
說明:后面是X686或X86_64則內核是64位的,i686或i386則內核是32位的
2) JDK安裝包必須為64位
查看命令:java -version
說明:如果是64位的則會顯示Java HotSpot<TM>64-Bit 字樣,32位的則沒有類似信息
3) JBOSS使用官方推薦安裝包jboss-eap-6.2.0.zip
2.2 JDK安裝
Linux系統自帶了jdk,但還是1.4的老版本,所以需要先卸載,然后在安裝1.6,卸載步驟如下:
[root@localhost ~]# rpm -qa | grep jdk
[root@localhost ~]# rpm -qa | grep gcj
libgcj-4.1.2-42.el5
java-1.4.2-gcj-compat-1.4.2.0-40jpp.115
上面先確認jdk的具體版本號,然后
[root@localhost ~]# yum -y remove java-1.4.2-gcj-compat-1.4.2.0-40jpp.115
1) 解壓jdk安裝包
./jdk-6u45-linux-x64.bin
2) etc/profile最后加入
| JAVA_HOME=/prog/jdk/jdk1.6.0_45 PATH=$JAVA_HOME/bin:$PATH set CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar export JAVA_HOME export PATH export CLASSPATH |
3) 測試
命令行輸入java –version,如果顯示當前版本,則JDK安裝成功。
2.3 APACHE安裝
1) 進入到安裝程序所在目錄,執行以下命令對其進行解壓縮
tar -zxvf httpd-2.2.25.tar.gz
在同級目錄下會生成 httpd-2.2.25 文件,執行以下命令創建一個新的目錄來存放將要安裝的apache軟件
mkdir –p /usr/local/web/apache2.2/
執行以下命令將生成的源碼文件移動到其他目錄,便於管理
mv httpd-2.2.25 /usr/local/src/
進入到src目錄,再進入到httpd-2.2.25目錄執行以下命令進行安裝前的配置
./configure --prefix=/usr/local/web/apache2.2 --enable-so --enable-mods-shared=most --enable-rewrite
2) 如果上述過程報錯依賴apr與apr-util,則首先安裝apr與apr-util;如果無報錯,則忽略
| [root@localhost 52lamp]# cd apr-1.4.8 [root@localhost apr-1.4.8]# ./configure [root@localhost apr-1.4.8]# make [root@localhost apr-1.4.8]# make install |
Apr-util安裝與上述完全相同。
3) Apr與apr-util安裝完畢后重新執行configure、make、make install
| #./configure --prefix=/usr/local/web/apache2.2 --enable-so --enable-mods-shared=most --enable-rewrite --with-apr=/usr/local/apr/ --with-apr-util=/usr/local/apr-util/ #make #make install |
4) 執行 service httpd start 命令,看是否能夠啟動apache 如果不能啟動並提示httpd unrecognized service則是apache沒有配置成系統服務
5) 將apache配置成系統服務
cp /usr/local/web/apache/bin/apachectl /etc/rc.d/init.d/httpd
vi /etc/rc.d/init.d/httpd
當httpd文檔打開后,在#!/bin/sh 內容下面添加以下內容(含#符號的)
# chkconfig: 2345 90 90
# description: Activates/Deactivates Apache Web Server
添加完成后,保存並退出到命令模式,輸入以下命令將apache添加到系統服務
chkconfig --add httpd
chkconfig --level 345 httpd on
6) 測試
命令行輸入 service httpd start
然后打開瀏覽器訪問http://localhost出現it works.
Apache安裝結束。
2.4 JBOSS安裝
2.4.1 JBoss-eap-6.2簡單介紹
Jboss-eap-6.2是基於jboss as 7的企業級版本,JBoss AS7新加入了域(domain)的概念並實現了相關功能。域的提出及實現,其目的是使得多台JBoss AS服務器的配置可以集中於一點,統一配置、統一部署,從而在管理多台JBoss AS服務器時,實現集中管理。
域的目的則是將多台服務器組成一個服務器組(Server Group),並為一個服務器組內的多台主機(Host)提供:
* 單點集中配置(通過一個域控制器,即Domain Controller,實現組內主機的統一配置)。
* 單點統一部署,通過域控制器將項目一次部署至組內全部主機。
簡單來講,群集的目標是讓多台服務器分攤壓力,當一台或多台服務器當機時,服務可以繼續保持運轉;而域的目標則是提供集中配置和管理多台服務器的能力。在沒有域的概念時,要想讓群集內的多台服務器或幾組服務器保持統一的配置,一個一個分別的去手工維護,是非常麻煩的事情,而域的引入解決了這一問題。
2.4.2 准備工作
現在兩台電腦的IP分別為10.0.1.3及10.0.1.18,分別運行JBoss AS7,並組成一個服務器組(Server Group)。其中,使用10.0.1.3這台機器做為域控制器(Domain Controller):

如上圖所示,兩台主機分別被命名為”master“及”slave“。通過配置,將master與slave組成一個服務器組,其中master將做為這個服務器組的域控制器。
需要說明一點的是,服務器組(Server Group)可以由多台服務器(Host)組成,並不一定只有兩台,所以不要被master及slave這樣的名字給迷惑了,以為一個服務器組僅支持一主一從兩台hosts。本文中因為只使用兩台服務器做實驗,因此出於方便角度將它們分別命名為master及slave。此外,在一個服務器組中,只有一台域控制器,在本實驗中我們將使用master這台機器做為domain controller。
2.4.3 Domain Controller配置
1) 在domain controller一段創建一個Management User,具體到JBOSS_HOME/bin目錄下執行add-user.sh
| [kylin@unused bin]$ ./add-user.sh What type of user do you wish to add? a) Management User (mgmt-users.properties) b) Application User (application-users.properties) (a): Enter the details of the new user to add. Realm (ManagementRealm) : Username : admin123 Password :admin111_ Re-enter Password :admin111_ About to add user 'admin123' for realm 'ManagementRealm' Is this correct yes/no? yes Added user 'admin123' to file '/home/kylin/work/./standalone/configuration/mgmt-users.properties' Added user 'admin123' to file '/home/kylin/work/./domain/configuration/mgmt-users.properties' Is this new user going to be used for one AS process to connect to another AS process? e.g. for a slave host controller connecting to the master or for a Remoting connection for server to server EJB calls. yes/no? yes To represent the user add the following to the server-identities definition <secret value="YWRtaW4xMTFf=" /> |
2) JBOSS_HOME/domain/configuration/host.xml中,刪除servers,表示這台主機只用來做域控制器,不用於發布server,jboss已經為我們提供了對應的配置文件便於參考,即JBOSS_HOME/domain/configuration/host-master.xml

3) Domain.xml中< hornetq-server>節點加入<security-enabled>false</security-enabled>
| <hornetq-server> <security-enabled>false</security-enabled> … </hornetq-server> |
4) 測試
運行/bin/domain.sh,然后瀏覽器中輸入http://localhost:9990/ ,輸入用戶、密碼(剛才add-user.sh配置的),即可進入Domain管理界面
2.4.4 Host Controller配置
1) 因為Slave這台機器不作為域控制器而存在,刪除domain/configuration/domain.xml文件
2) 同樣jboss已經為我們提供了對應的配置文件便於參考,即JBOSS_HOME/domain/configuration/host-slave.xml,打開host.xml,修改<domain-controller>部分內容如下:
| <domain-controller> <remote host="10.0.1.3" port="9999" username=”admin123” security-realm="ManagementRealm"/> </domain-controller> |
3) 修改 <security-realm name="ManagementRealm">如下
| <security-realm name="ManagementRealm"> <server-identities> <secret value="YWRtaW4xMTFf="/> </server-identities> <authentication> <properties path="mgmt-users.properties" relative-to="jboss.domain.config.dir"/> </authentication> </security-realm> |
注意事項:密碼值為admin123用戶對應密碼的BASE64編碼值,同時加上’=’結尾。
編碼值可以使用網上在線工具查看。
4) 確保host名字唯一
| <host name="slave1" |
5) 確保server的名字唯一,並修改端口,遞增數為150或100(這是端口偏移量,jboss默認http端口是8080,這樣以后訪問具體的server,如果server1的端口偏移量是150,則端口就是8230)
| <servers> <server name="server1" group="other-server-group" auto-start="false"> <socket-bindings port-offset="150"/> </server> </servers> |
6) 運行domain.sh測試
訪問http://localhost:8230,進入JBOSS頁面即OK。啟動成功的話,應該可以在master上面看到日志,slave被成功的注冊進來。
2.4.5 應用部署
1) 訪問控制台http://10.0.1.3:9990/,在Runtime標簽頁下左側,點擊Manage Deployments, 進入部署功能頁面:
2) 此時點擊右邊的"Add "功能,將ShoppingCart.war添加進Content Repository(域控制器用於保存待部署資源的目錄)。
3) 然后點擊"Assign"將ShoppingCart.war添加至 "other-server-group",並將其enable


注意:這里有一點值得注意的是,jboss-eap-6.2默認設置了兩個server group分別是:main-server-group和other-server-group,但是這兩個組是有區別的main-server-group使用的默認profile和socket是full,而other-server-group使用的默認profile和socket是full-ha,然而在jboss-eap-6.2的四種profile中只有ha和full-ha支持集群的multicast協議,這一點可以在domain/configuration/domain.xml里面看到,而且jboss-eap-6.2官方文檔也有指出,如下圖:

所以在對應用分配組(Assign)的時候,如果該應用最終訪問方式是要通過apache服務器來分發請求訪問,那就不要分配給main-server-group,否則最終發布的時候,通過apache默認端口訪問的結果要么出現404,要么503.如果非要分配給main-server-group,則需要修改它默認的profile和socket為:ha或者full-ha.
2.5 集群配置
2.5.1 Apache mod_jk配置【必須】
1) 將下載的 mod_jk-1.2.31-httpd-2.2.x.so 文件改名為mod_jk.so
2) 將mod_jk.so 文件復制到 APACHE_HOME/modules/目錄下
3) 打開APACHE_HOME/conf/httpd.conf 在文件最后添加以下內容后保存
# module mod_jk config file
Include conf/mod_jk.conf
4) 進入APACHE_HOME/conf/目錄中,新建mod_jk.conf
| #load module mod_jk-1.2.31-httpd-2.2.3.so is for Apache 2.2.x. LoadModule jk_module modules/mod_jk.so #配置 mod_jk conf #加載集群中的workers JkWorkersFile conf/workers.properties #加載workers的請求處理分配文件 JkMountFile conf/uriworkermap.properties #指定jk的日志輸出文件 JkLogFile logs/mod_jk.log #指定日志級別 JkLogLevel info |
5) 進入APACHE_HOME/conf/目錄,新建workers.properties
| # worker列表 worker.list=node_lb,jkstatus #配置實例節點1 worker.node1.host=10.0.0.18 worker.node1.port=8009 worker.node1.type=ajp13 ----對於mod_jk,jboss僅支持ajp13協議 worker.node1.lbfactor=1 #配置實例節點2 worker.node2.host=10.0.0.18 worker.node2.port=8159 ----8009+150的偏移量 worker.node2.type=ajp13 worker.node2.lbfactor=1 worker.node_lb.type=lb worker.node_lb.retries=3 worker.node_lb.balance_workers=node1,node2 worker.node_lb.sticky_session=true ----粘性session,非粘性只需改成false即可 #worker.node_lb.sticky_session_force=false worker.jkstatus.type=status |
6) 進入APACHE_HOME/conf/目錄中,新建uriworkermap.properties
| #所有請求都由LB_worker這個worker處理 /*=node_lb #所有包含jkstatus請求的都由名稱叫jkstatus的這個worker處理 /jkstatus =jkstatus /jkstatus/* =jkstatus |
7) 測試
重新啟動apache,首先進入http://localhost:9990部署ShoppingCart.war
訪問http://localhost/ShoppingCart進行測試
2.5.2 jvmRoute配置【必須】
給 jboss每個host配置apache mod_jk的分發路由
| <system-properties> <property name="org.apache.catalina.connector.URI_ENCODING" value="UTF-8"/> </system-properties> |
2.5.3 Apache反向代理配置
Apache mod_proxy跟mod_jk功能類似,也具有整合負載均衡的能力,當服務搭建在一台內網機器上,通過外網機器的80端口映射內網的8080端口進行訪問。由於可對外暴露的端口只有被映射的一個8080端口,這時可以使用mod_proxy進行反向代理配置。
1) 首先httpd.conf配置中需要啟用Apache的幾個模塊
| LoadModule proxy_module modules/mod_proxy.so LoadModule proxy_balancer_module modules/mod_proxy_balancer.so LoadModule proxy_http_module modules/mod_proxy_http.so |
2) httpd.conf中打開httpd-vhosts.conf注釋,這是反向代理配置文件,如果沒有,需要自行添加如下:
# Virtual hosts
Include conf/httpd-vhosts.conf
3) 修改apache80監聽端口為8080
在httpd.conf配置文件中查找listen 80 改成8080 即可。
4) 編輯httpd-vhosts.conf
| # # Virtual Hosts # # If you want to maintain multiple domains/hostnames on your # machine you can setup VirtualHost containers for them. Most configurations # use only name-based virtual hosts so the server doesn't need to worry about # IP addresses. This is indicated by the asterisks in the directives below. # # Please see the documentation at # <URL:http://httpd.apache.org/docs/2.2/vhosts/> # for further details before you try to setup virtual hosts. # # You may use the command line option '-S' to verify your virtual host # configuration. # # Use name-based virtual hosting. # NameVirtualHost *:8080 # # VirtualHost example: # Almost any Apache directive may go into a VirtualHost container. # The first VirtualHost section is used for all requests that do not # match a ServerName or ServerAlias in any <VirtualHost> block. # RewriteEngine On Header add Set-Cookie "ROUTEID=.%{BALANCER_WORKER_ROUTE}e; " env=BALANCER_ROUTE_CHANGED #建立虛擬主機來作為負載均衡 <Proxy balancer://main_cluster> Order deny,allow Allow from all BalancerMember ajp://172.16.3.136:8109 route=slave1:cks-main ProxySet stickysession=ROUTEID </Proxy> <Proxy balancer://report_cluster> Order deny,allow Allow from all BalancerMember ajp://172.16.3.136:8209 route=slave1:WebReport ProxySet stickysession=ROUTEID </Proxy> <VirtualHost *:8080> Timeout 7200 ProxyRequests Off # ProxyPassReverseCookiePath / / ProxyPass /cks-main balancer://main_cluster/cks-main ProxyPassReverse /cks-main balancer://main_cluster/cks-main ProxyPass /WebReport balancer://report_cluster/WebReport ProxyPassReverse /WebReport balancer://report_cluster/WebReport ProxyPreserveHost On #KeepAliveTimeout 500 #MaxKeepAliveRequests 200 </VirtualHost> |
5) 最后重啟apache
service httpd restart
6) 測試
http://172.16.3.136:8080/cks-main
http://172.16.3.136:8080/WebReport/ReportServer
2.6 Session管理
2.6.1 session復制
session同步除了上述的sticky模式,還可以通過session復制實現。要實現session復制只需要在項目的web.xml里面加入<distributable />標簽即可。不過session復制會導致應用服務器性能下降,所以要慎用。
官方文檔:

2.6.2 統一管理session
如何通過一種session管理策略,確保集群某一個結點失效后,其session數據能由其他結點獲取以便其他結點接替失效結點,實現集群的容錯(failover),對於這個問題,多數的應該服務器(包括Tomcat在內)使用的是session復制(session replication)機制,即結點之間通過組播方式將各自的session發到其他所有結點上,如果其中一個訪問出錯,則另外結點仍然具有有效的session內容,從而能正常接管其session。由於服務器內置了session復制機制的實現,因而使用這種方案非常簡單,只需要做簡單的配置即可完成,但是其缺點也是很明顯的,由於大量的session信息需要復制,在用戶數量和集群數量達到一定規模后,session復制就有可能成為性能瓶頸。
session共享的另一種思路就是采用memcached。使用memcached來存儲session可以通過自己編寫filter實現.
主要思路:
(1)繼承重構HttpServletRequestWrapper,HttpSessionWrapper類,覆蓋原來和session存取相關的方法呢,都通過SessionService類來實現.
(2)使用filter攔截cookie中的sessionId,通過sessionId構造新的HttpServletRequestWrapper對象,傳給后面的應用.
(3)SessionService連接memcached服務,以sessionId作為key,存取的對象是一個map.map的內容即為session的內容.
Demo請看:附件
使用過程注意幾個問題和改進思路:
1、memcache的內存應該足夠大,這樣不會出現用戶session從Cache中被清除的問題(可以關閉memcached的對象退出機制)。
2、如果session的讀取比寫入要多很多,可以在memcache前再加一個Oscache等本地緩存,減少對memcache的讀操作,從而減小網絡開銷,提高性能。
3、如果用戶非常多,可以使用memcached組,通過set方法中帶hashCode,插入到某個memcached服務器
對於session的清除有幾種方案:
(1)可以在凌晨人最少的時候,對memcached做一次清空。(簡單)
(2)保存在緩存中的對象設置一個失效時間,通過過濾器獲取sessionId的值,定期刷新memcached中的對象.長時間沒有被刷新的對象自動被清除.(相對復雜,消耗資源)
2.7 JBOSS后台啟動、關閉、重啟
2.7.1 啟動
nohup ./domain.sh &
運行日志可以查看domain.sh對應目錄下的nohup.out
2.7.2 關閉
正常退出可以使用jboss提供的./jboss-cli.sh來連接后台裕興的domain.sh,步驟:
./jboss-cli.sh
connect
:shutdown
可以參考官方文檔,如下:

當然,如果以上方法無法奏效,那只能使用強行殺進程了:
ps aux | grep java 查PID
kill –s 9 PID
2.7.3 重啟
重啟跟關閉采用同樣的方式命令為:
:reload
2.8 JVM參數配置
設置位置:bin/domain.conf
2.8.1 內存設置
參考大小:
bin\domain.conf中
if [ "x$JAVA_OPTS" = "x" ]; then
JAVA_OPTS="-Xms64m -Xmx512m -XX:MaxPermSize=256m -Djava.net.preferIPv4Stack=true
或者:
可以對具體的server進行內存設置,如下:

2.8.2 GC設置
GC文件名為日期+時間,以便進行GC性能跟蹤。
bin\domain.conf中
if [ "x$JAVA_OPTS" = "x" ]; then
JAVA_OPTS="-Xms64m -Xmx512m -XX:MaxPermSize=256m -Djava.net.preferIPv4Stack=true -verbose:gc -Xloggc:/prog/gc/`date +%Y%m%d__%H%M%S`.out -XX:+PrintGCTimeStamps -XX:+PrintGCDetails
"
2.8.3 jboss線程數配置
\domain\configuration\domain.xml
<connector name="http" protocol="HTTP/1.1" scheme="http" socket-binding="http" max-connections="1000"/>
2.8.4 jboss請求日志配置
\domain\configuration\domain.xml中
| <subsystem xmlns="urn:jboss:domain:web:1.4" default-virtual-server="default-host" native="false"> <connector name="http" protocol="HTTP/1.1" scheme="http" socket-binding="http" max-connections="1000"/> <virtual-server name="default-host" enable-welcome-root="true"> <alias name="localhost"/> <alias name="example.com"/> <access-log pattern="%a %t %H %p %U %s %T" > <directory relative-to="jboss.server.log.dir" /> </access-log> </virtual-server> </subsystem> |
pattern的詳細說明
%a 遠端IP
%A 本地IP
%b 發送的字節數,不包含HTTP頭,如果為0,使用”-”
%B 發送的字節數,不包含HTTP頭
%h 遠端主機名(如果resolveHosts=false),遠端的IP
%H 請求協議
%l 從identd返回的遠端邏輯用戶名,總是返回’-’
%m 請求的方法
%p 收到請求的本地端口號
%q 查詢字符串
%r 請求的第一行
%s 響應的狀態碼
%S 用戶的sessionID
%t 日志和時間,使用通常的log格式
%u 認證以后的遠端用戶(如果存在的話,否則為’-’)
%U 請求的URI路徑
%v 本地服務器的名稱
%D 處理請求的時間,以毫秒為單位
%T 處理請求的時間,以秒為單位
2.8.5 jboss請求響應時間配置
默認響應超時時間為60秒
注:7.1.1不支持此設置,7.1.2支持此設置
\domain\configuration\domain.xml中
| org.apache.coyote.http11.DEFAULT_CONNECTION_TIMEOUT system property. <system-properties> <property name="org.apache.coyote.http11.DEFAULT_CONNECTION_TIMEOUT" value="600000"> </system-properties> |
3 方案特性
3.1 高性能
Ø 基於負載均衡的請求分發,快速響應客戶端請求
3.2 隔離性
Ø 物理主機硬件隔離,提供穩定可靠的服務
Ø 應用軟件部署隔離,即可獨立服務又可集群共享
3.3 可靠性
Ø 應用負載均衡,降低應用系統故障頻率及宕機風險
Ø 單個應用故障,其他應用可接管服務
3.4 伸縮性
Ø 可方便擴充硬件設備,滿足業務擴展需求
Ø 可方便應用實例擴充、部署等變更需求
4 參考文檔
https://docs.jboss.org/author/display/AS71/AS7+Cluster+Howto
https://docs.jboss.org/author/display/AS71/Using+mod_jk+with+JBoss+AS7
http://www.jbossauthority.com/jboss-eap-6-extensions-subsystems-and-profiles/
