Wednesday, December 17, 2008

Load balance and clustering with Apache HTTP Server 2.2.x and Tomcat 6.0.x

HA 在網路的世界不可或缺,尤其客戶是屬於 C 端 (customer,個人) 時,更要在 AP 端配置 HA 的架構,讓系統不斷線,客戶可以持續的交易不造成中斷。

HA 涉及的議題包含了軟體端的 Load Balance, Clustering 建置,硬體端的網路連線,磁碟空間配置。就硬體端而言,除了至少要有兩條網路線互相備援外,磁碟空間也必須做 replication 與備援才能有效的支援因外在因素而產生的影響。硬體端的 HA 可以有很多架構,但需要 $$ 去建置,這裡就不多講。

在軟體端方面,因為熟悉 J2EE 的架構,所以就選了非常 light weight 的 Apache HTTP Server 2.2.x 與 Tomcat 6.0.x 作為 load balance and clustering 的 instance.


Load Balance 設定
此部份用 Apache HTTP Server 就可做的到,這裡舉一個範例

Apache HTTP Server (HTTPs)
       |
      /  \
     /     \
    /       \
Tomcat 6.0.x(T1)  Tomcat 6.0.x(T2)

這是最簡單的架構,透過 Apache HTTP Server ,便可以存取 T1 與 T2,然後可以在 T1 與 T2 的相同 JSP 放入不同的內容,以測試 Load Balance 的正確性

1. 下載 Apache HTTP Server 與 Tomcat 6.0.x (Windows version)
1.1 下載 Apache HTTP Server 2.2.x 並裝至 d:\Program Files。此版本含有 openssl ,用來產生 key 與 certificate for HTTPS 用
1.2 下載 Tomcat 6.0.x 並解壓縮到 d:\java 中。解壓縮時需解到兩個目錄,一個是
d:\java\apache-tomcat-6.0.16-t1,另一個是 d:\java\apache-tomcat-6.0.16-t2


2. 安裝 SSL
這個部份對大部分的人應該都滿陌生的,因為 SSL 有點小 tricky,除非你正式做過需 HTTPS 的案子,不然可能會搞糊塗。 這邊的 SSL 是針對 Apache HTTP Server 上的 SSL,不是 Tomcat 上的 SSL。Tomcat 的作法與 Apche HTTP Server 不同,用的工具也不同,但其 Certificate 是可以共用的,會在後面 Tomcat with SSL 時說明

2.1 去除 D:\Program Files\Apache Software Foundation\Apache2.2\conf\httpd.conf 中有關 SSL 的 #
#LoadModule ssl_module modules/mod_ssl.so
#Include conf/extra/httpd-ssl.conf

2.2 建立 CA Root Certificate 及 Server Certificate
什麼是 CA Root Certificate ,基本上就是老大發的通行證,若網站是經由此老大認證過,IE 或 Firefox 就會認得此憑證是老大發的,就不用懷疑其效力。這些老大通常都會審核申請憑證的公司的合法性,一般 User 也比較能放心去這些網站使用或消費。

但為何要建立 CA Root Certificate 呢,因為若要公司每台 Server 都需要 Certificate ,則每個 Certificate 都需要跟老大申請認證,這些都需要費用。若這些 Server 只是內部用,則可以自己當老大做一個 CA Root Certificate 然後認證自己發的 Server Certificate,這樣可以減少許多成本,也比較方便。用的時候只需要將老大的 CA Root Certificate 安裝到公司內部的 IE 或 Fixfox 就行了,凡經由 CA Root Certificate 認證過的 Server Certificate 都不會被詢問其 SSL的安全性問題,因為老大說了算 (不知道是否已經有人昏倒了)


建立 CA Root Certificate
d:\>cd D:\Program Files\Apache Software Foundation\Apache2.2\bin
d:>openssl genrsa -des3 -out ..\conf\caroot.key 2048
Loading 'screen' into random state - done Generating RSA private key, 2048 bit long modulus ...........+++ .+++ e is 65537 (0x10001) Enter pass phrase for ..\conf\caroot.key: Verifying - Enter pass phrase for ..\conf\caroot.key:

用 RSA 演算法+Triple Des Encryption (des3) 建立 CA root 的 key,強度為 2048bit。密碼請輸入 暫時輸入 changeit

d:>openssl req -config ..\conf\openssl.cnf -new -key ..\conf\caroot.key -out ..\conf\caroot.csr
Enter pass phrase for ..\conf\caroot.key: Loading 'screen' into random state - done You are about to be asked to enter information that will be incorporated into your certificate request. What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank For some fields there will be a default value, If you enter '.', the field will be left blank.
----- Country Name (2 letter code) [AU]:TW
State or Province Name (full name) [Some-State]:Taiwan

Locality Name (eg, city) []:Taipei
Organization Name (eg, company) [Internet Widgits Pty Ltd]:My Company Inc.
Organizational Unit Name (eg, section) []:My Company Dept
Service Provider
Common Name (eg, YOUR name) []:My Company Trust
Email Address []:

Please enter the following 'extra' attributes to be sent with your certificate request A challenge password []:
An optional company name []:


這裡是產生 CSR (Certificate Service Request),用以讓別的 CA 簽發憑證。因為是自己要用的 Root,所以等一下會自己簽自己。基本上所以有 CA Root 都是自己簽自己。

d:>openssl x509 -req -days 7305 -sha1 -extensions v3_ca -signkey ..\conf\caroot.key -in ..\conf\caroot.csr -out ..\conf\caroot.crt
Loading 'screen' into random state - done Signature ok subject=/C=TW/ST=Taiwan/L=Taipei/O=My Company/OU=My Company Dept/CN=My Company Trust/emailAddress=
Getting Private key
Enter pass phrase for ..\conf\caroot.key:

這裡就是自己簽自己的簽發憑證。若 double click ..\conf\caroot.crt 並安裝此憑證,可以打開 IE > 網際網路選項 > 內容 > 憑證 看到此憑證被放到根憑證的目錄中





















PS : caroot.key 一定要保存好並記住密碼,不然掉了,所以憑證全部要重新簽發,很費時間。

建立 Server Certificate
當建立完 CA Root Certificate 後,再來就是要建立 Server Certificate 再用 CA Root Certificate 對 Server Certitificate 做簽發 (Sign)
d:>openssl genrsa -out ..\conf\server.key 2048

建立 Server 用的 key
d:>openssl req -config ..\conf\openssl.cnf -new -key ..\conf\server.key -out ..\conf\server.csr
Loading 'screen' into random state - done You are about to be asked to enter information that will be incorporated into your certificate request. What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank For some fields there will be a default value, If you enter '.', the field will be left blank. -----
Country Name (2 letter code) [AU]:TW
State or Province Name (full name) [Some-State]:Taiwan

Locality Name (eg, city) []:Taipei
Organization Name (eg, company) [Internet Widgits Pty Ltd]:My Company Ltd

Organizational Unit Name (eg, section) []:RD Dept

Common Name (eg, YOUR name) []:www.mycompnay.com
Email Address []:


Please enter the following 'extra' attributes
to be sent with your certificate request A challenge password []:
An optional company name []:


以上會建立申請簽章的檔案 server.csr,這裡需記得 Common Name 必須與 server 的 url domain name 一樣如 www.mycompany.com,這樣才能通過 IE 或 Firefox 的認證,否則會出現 warning。

d:>openssl x509 -req -days 3650 -sha1 -extensions v3_req -CA ..\conf\caroot.crt -CAkey ..\conf\caroot.key -CAcreateserial -in ..\conf\server.csr -out ..\conf\server.crt

Loading 'screen' into random state - done

Signature ok

subject=/C=TW/ST=Taiwan/L=Taipei/O=My Company Ltd/OU=RD Dept/CN=www.mycompnay.co
m
Getting CA Private Key
Enter pass phrase for ..\conf\caroot.key:

這裡會用 caroot 簽發 server.csr 並產生 server.crt。double click server.crt 可得畫面如下
























這裡可以發現,沒有 warning, 發行者是 CA Root ,有效是 10 年

2.3 重新啟動 Apache HTTP Server
因為產生 Server 的 certificate 檔名已經同步 conf/extra/httpd-ssl.conf 裡面所定義的命名方式,所以直接啟動 Apache HTTP Server 便可以使用 HTTPS (SSL)
























3. 設定 load balance

3.1 下載 mod_jk (Tomcat 6.0.x for win32 版)
下載完 mod_jk 後 請將檔名改為 mod_jk.so 並放到 D:\Program Files\Apache Software Foundation\Apache2.2\modules 中

3.2 在 D:\Program Files\Apache Software Foundation\Apache2.2\conf\extra 中新增一個檔案 httpd-load-balance.conf
內容如下
================================
#(httpd.conf)
#載入 mod_jk 模組
LoadModule jk_module modules/mod_jk.so

#
# Configure mod_jk
#
JkWorkersFile conf/workers.properties
JkMountFile conf/uriworkermap.properties
JkLogFile logs/mod_jk.log
JkLogLevel info


JkMount jkstatus
Order deny,allow
Deny from all
Allow from 127.0.0.1

===============================

3.3 在 D:\Program Files\Apache Software Foundation\Apache2.2\conf\httpd.conf 的最後新增一行
內容為
Include conf/extra/httpd-load-balance.conf

如此重新啟動 Apache HTTP Server 時才會把 load balance 的 module 放到 kernel 中執行

3.4 在 D:\Program Files\Apache Software Foundation\Apache2.2\conf 中新增一個檔案 workers.properties
內容為
=====================================
# The advanced router LB worker
worker.list=router,jkstatus

# Define a worker using ajp13
worker.worker1.port=8009
worker.worker1.host=localhost
worker.worker1.type=ajp13
worker.worker1.lbfactor=1
# Define prefered failover node for worker1
#worker.worker1.redirect=worker2

# Define another worker using ajp13
worker.worker2.port=9009
worker.worker2.host=localhost
worker.worker2.type=ajp13
worker.worker2.lbfactor=1
# Disable worker2 for all requests except failover
#worker.worker2.activation=disabled

# Define the LB worker
worker.router.type=lb
worker.router.balance_workers=worker1,worker2

# Define a 'jkstatus' worker using status
worker.jkstatus.type=status
====================================

這裡指定 worker1 為 T1, 用的 port 為 8009,worker2 為 T2,用的 port 為 9009

3.5 在 D:\Program Files\Apache Software Foundation\Apache2.2\conf 中新增一個檔案 uriworkermap.properties
內容為
===============================
/*=router
===============================

這裡會將 URI 為 /* 的 mapping 全部轉向 T1 或 T2

3.6 更改 T2 的設定檔
因為 T2 用的 port 還是 8009,需改為 9009 以配合 workers.properties 中的設定
修改 D:\java\apache-tomcat-6.0.16-t2\conf\server.xml 中的

line 22 port="8005" 改為 port="9005"
line 67 port="8080" 改為 port="9090"
line 89 port="8009" 改為 port="9009"

port 改成如此是因為要避免與 T1 衝突。
3.7 重新啟動 Apache HTTP Server 與 T1, T2
重新啟動 Apache HTTP Server 後再啟動 T1, T2,接下來打開 IE 將 URL 指向 http://localhost 可以得到

















這裡可以看到跑的是 Apache Tomcat T2 (webapps\ROOT\index.html 有修改過),證明 Load Balance 已經開始作用中

3.8 啟動 SSL 的 Load Balance
這時候當 URL 指向 https://localhost 時,Tomcat 的畫面並不會跑出來,需要在
D:\Program Files\Apache Software Foundation\Apache2.2\conf\extra\httpd-ssl.conf
的 VirtualHost 裡面加上這一行

JkMountFile conf/uriworkermap.properties

然後重新啟動 Apache HTTP Server ,SSL 便可以做到 Load Balance 了
以下畫面是把 T2 Shutdown 後,Refresh IE 則會 Forward 到 T1 上

















4. 設定 Tomcat 的 Clustering
若有人要OOXX,現在是一個好時機,因為在 Windows XP 上無法做 Clustering。花了幾乎快一個下午的時間試,也無法試出來用 2 個 Tomcat instance 跑在同一台機器,後來用 VMWare 跑 Ubuntu 8.10 然後在上面跑 2 個 Tomcat ,一切搞定。所以,Linux 實在非常適合做 Server。

話不多說,把 Ubuntu 8.10 跑起來後,利用 SSH 將兩個 tomcat 複製到 /opt 下
/$ cd /
/$ sudo mkdir /opt
/$ sudo chmod o+w opt
這樣才能在非 root 的使用者下將 tomcat 複製到 /opt
/opt$ ls -l
apache-tomcat-6.0.16-t1
apache-tomcat-6.0.16-t2
/opt$ chmod +x apache-tomcat-6.0.16-t1/bin/*.sh
/opt$ chmod +x apache-tomcat-6.0.16-t2/bin/*.sh

4.1 設定 Tomcat Cluster in server.xml
更改 /opt/apache-tomcat-6.0.16-t1/conf/server.xml
在 line 100 的 Engine 中加入 jvmRoute="worker1"
在 line 106 將 Cluster 的上下 comment !-- -- 拿掉

更改 /opt/apache-tomcat-6.0.16-t2/conf/server.xml
在 line 100 的 Engine 中加入 jvmRoute="worker2"
在 line 106 將 Cluster 的上下 comment !-- -- 拿掉

4.2 設定 web application
因之前有發表過 appfuse 2.0.2 for JPA ,所以就直接把 war 檔放到 t1 與 t2 的 webapps 下,也修改了 WEB-INF/classes/jdbc.properties 中的 localhost 為原本的 XP 上

4.3 啟動 Tomcat t1, t2
打開一個 xterm (應用程式 > 附屬應用程式 > 終端機 )
$ cd /opt/apache-tomat-6.0.16-t1/bin
/bin$ export JAVA_HOME=/usr/lib/jvm/java-6-sun
/bin$ ./catalina.sh run

打開另一個 xterm (應用程式 > 附屬應用程式 > 終端機 )
$ cd /opt/apache-tomat-6.0.16-t2/bin
/bin$ export JAVA_HOME=/usr/lib/jvm/java-6-sun
/bin$ ./catalina.sh run

這時候應該可以看到 t1, t2 會互相 talk 如下畫面

















4.4 修改 Apache HTTP Server
因之前的 load balance 設定用的 tomcat 是 localhost ,但因 XP 無法支援,所以要將 D:\Program Files\Apache Software Foundation\Apache2.2\conf\workers.properties 中的
worker.worker1.host=localhost
worker.worker2.host=localhost
改為
worker.worker1.host=svn
worker.worker2.host=svn

PS : 此 svn 是 Ubuntu VM 上的 hostname

然後重新啟動 Apache HTTP Server

4.5 測試 Cluster
打開一個 IE 網址為 https://localhost/myprojectjpa-1.0-SNAPSHOT/然後用 admin/admin login,再進入 系統管理 > 訪問紀錄 可以看到用的是 worker1 的 tomat t1








再打開另一個 IE 網址為 https://localhost/myprojectjpa-1.0-SNAPSHOT/ 然後用 admin/admin login,再進入 系統管理 > 訪問紀錄 可以看到有兩個 Stream ,點進去看可以看到分別是 worker1 與 worker2









經由此測試可以發現 Cluster 試驗成功,因為 worker1 上或 worker2 上的 tomcat 都有兩個 session 在

接下來將 t1 shutdown ,然後在按 worker1 上的 IE 的訪問紀錄,可發現 session 已轉到 worker2 了。因為此 session 是由 worker1 複製過來的,所以 Name 被改為 127.0.0.1 了













後記 :
1. 經由此測試發現在 Windows XP 上無法模擬 Cluster (也許要改設定),有興趣的人可以試試在 Windows 2003 server 上試,但建議用 VMware 跑 Ubuntu,因為省錢又方便
2. Tomcat 6 的設定比 Tomcat 5 簡單多了,因為預設值都被 Tomcat container 處理掉了
3. Load Balance 除了用 mod_jk 外,好像也可以用 ProxyPass 的方式,改天再來試試看

No comments: