http://w.gdu.me/wiki/Java/tomcat_cluster.html
1
2
3
4
|
cat
/etc/hosts
192.168.0.100 web.example.com web
#add
127.0.0.1 localhost.localdomain localhost
::1 localhost6.localdomain6 localhost6
|
1
2
3
4
5
6
7
8
9
10
11
12
|
# 先查看当前JDK的版本是多少
java –version
# 进入下载目录,授权JDK文件的可执行权限
cd
/tools/
chmod
a+x jdk-6u24-linux-i586.bin
# 执行JDK的安装解压缩,完成后按回车结束
.
/jdk-6u24-linux-i586
.bin
# 把解压出来的目录移动到/usr/local下面
mv
jdk1.6.0_24
/usr/local/
|
1
2
3
4
5
6
7
|
cat
>
/etc/profile
.d
/java
.sh <<EOF
# set java environment
export
JAVA_HOME=
/usr/local/jdk1
.6.0_24
export
CLASSPATH=.:\$JAVA_HOME
/lib/dt
.jar:\$JAVA_HOME
/lib/tools
.jar
export
PATH=\$JAVA_HOME
/bin
:\$PATH
EOF
chmod
a+x
/etc/profile
.d
/java
.sh
|
java -version
(1)先选择Download下面的tomcat版本(如tomcat 7.0) (2)再点击“Core”下面的“tar.gz”进行下载,如apache-tomcat-7.0.12.tar.gz (3)下载完成后上传到web服务器上的“/tools”目录下(自己建的目录)
1
2
3
4
5
6
7
8
9
10
|
# 进入下载目录,进行解压缩:
cd
/tools
tar
zxvf apache-tomcat-7.0.12.
tar
.gz
# 复制并重命名目录到/usr/lcoal下面
ls
-l
cp
apache-tomcat-7.0.12
/usr/local/tomcat1
#(web1服务器)
cp
apache-tomcat-7.0.12
/usr/local/tomcat2
#(web1服务器)
cp
apache-tomcat-7.0.12
/usr/local/tomcat3
#(web2服务器)
cp
apache-tomcat-7.0.12
/usr/local/tomcat4
#(web2服务器)
|
1
2
3
4
5
|
<
Server
port
=
"8005"
shutdown
=
"SHUTDOWN"
>
<!--'8005'改为'8001'端口-->
<
Connector
port
=
"8080"
protocol
=
"HTTP/1.1"
>
<!--'8080'发布端口改为'81'端口-->
<
Connector
port
=
"8009"
protocol
=
"AJP/1.3"
redirectPort
=
"8443"
/>
<!--改为'8011'端口-->
<!--Engine name="Catalina" defaultHost="localhost"-->
<
Engine
name
=
"Catalina"
defaultHost
=
"localhost"
jvmRoute
=
"tomcat1"
>
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
<!--
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/>
-->
<!--下面的代码是实现session复制功能-->
<
Cluster
className
=
"org.apache.catalina.ha.tcp.SimpleTcpCluster"
channelSendOptions
=
"6"
>
<
Manager
className
=
"org.apache.catalina.ha.session.BackupManager"
expireSessionsOnShutdown
=
"false"
notifyListenersOnReplication
=
"true"
mapSendOptions
=
"6"
/>
<
Channel
className
=
"org.apache.catalina.tribes.group.GroupChannel"
>
<
Membership
className
=
"org.apache.catalina.tribes.membership.McastService"
address
=
"228.0.0.4"
port
=
"45564"
frequency
=
"500"
dropTime
=
"3000"
/>
<
Receiver
className
=
"org.apache.catalina.tribes.transport.nio.NioReceiver"
address
=
"192.168.100.63"
<!—这里填写本机IP地址-->
port="5000"
selectorTimeout="100" />
<
Sender
className
=
"org.apache.catalina.tribes.transport.ReplicationTransmitter"
>
<
Transport
className
=
"org.apache.catalina.tribes.transport.nio.PooledParallelSender"
/>
</
Sender
>
<
Interceptor
className
=
"org.apache.catalina.tribes.group.interceptors.TcpFailureDetector"
/>
<
Interceptor
className
=
"org.apache.catalina.tribes.group.interceptors.MessageDispatch15Interceptor"
/>
<
Interceptor
className
=
"org.apache.catalina.tribes.group.interceptors.ThroughputInterceptor"
/>
</
Channel
>
<
Valve
className
=
"org.apache.catalina.ha.tcp.ReplicationValve"
filter
=
".*\.gif;.*\.js;.*\.jpg;.*\.png;.*\.htm;.*\.html;.*\.css;.*\.txt;"
/>
<
Valve
className
=
"org.apache.catalina.ha.session.JvmRouteBinderValve"
/>
<
Deployer
className
=
"org.apache.catalina.ha.deploy.FarmWarDeployer"
tempDir
=
"/tmp/war-temp/"
deployDir
=
"/tmp/war-deploy/"
watchDir
=
"/tmp/war-listen/"
watchEnabled
=
"false"
/>
<
ClusterListener
className
=
"org.apache.catalina.ha.session.JvmRouteSessionIDBinderListener"
/>
<
ClusterListener
className
=
"org.apache.catalina.ha.session.ClusterSessionListener"
/>
</
Cluster
>
|
1
2
3
4
5
6
7
8
|
<!--....--!>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<distributable /> <!--在倒数第二行增加这个代码才能实现session同步复制功能-->
</
web-app
>
|
cp tomcat1/bin/catalina.sh /etc/rc.d/init.d/tomcat1
#chkconfig:35 85 15 #description:tomcat1 server CATALINA_HOME=/usr/local/tomcat1 JRE_HOME=/usr/local/jdk1.6.0_24
chkconfig --add tomcat1 chkconfig --list tomcat1 chkconfig tomcat1 on service tomcat1 start
./catalina.sh run
./startup.sh
启动的话,查看启动日志tail –f /usr/local/tomcat4/logs/catalina.out
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
ServerName localhost:80
#发布的端口说明
<VirtualHost *:80>
ServerAdmin [email protected]
ServerName localhost
ServerAlias localhost
<proxy balancer:
//testcluster
>
#testcluster可自己命名,没什么特别的意义
BalancerMember ajp:
//192
.168.0.101:8011 loadfactor=1 route=tomcat1
#要与tomcat中的ajp对应
BalancerMember ajp:
//192
.168.0.101:8012 loadfactor=1 route=tomcat2
BalancerMember ajp:
//192
.168.0.102:8013 loadfactor=1 route=tomcat3
BalancerMember ajp:
//192
.168.0.104:8014 loadfactor=1 route=tomcat4
<
/proxy
>
ProxyRequests Off
ProxyPass
/server-status
!
ProxyPass
/balancer-manager
!
ProxyPass / balancer:
//testcluster/
stickysession=JSESSIONID
#注意balancer前面有空格
ProxyPassReverse / balancer:
//testcluster/
#注意balancer前面有空格
<
/VirtualHost
>
SetHandler server-status
<
/Location
>
SetHandler balancer-manager
<
/Location
>
|
<%@ page contentType="text/html; charset=UTF-8" %> <%@ page import="java.util.*" %> <html><head><title>Cluster App Test</title></head> <body> Server Info: <% request.setCharacterEncoding("UTF-8"); out.println(request.getLocalAddr() + " : " + request.getLocalPort()+"<br>");%> <% out.println("<br> ID " + session.getId()+"<br>"); // 如果有新的 Session 属性设置 String dataName = request.getParameter("dataName"); if (dataName != null && dataName.length() > 0) { String dataValue = request.getParameter("dataValue"); session.setAttribute(dataName, dataValue); } out.print("<b>Session 列表</b>"); Enumeration e = session.getAttributeNames(); while (e.hasMoreElements()) { String name = (String)e.nextElement(); String value = session.getAttribute(name).toString(); out.println( name + " = " + value+"<br>"); System.out.println( name + " = " + value); } %> <form action="index.jsp" method="POST"> 名称:<input type=text size=20 name="dataName"><br> 值:<input type=text size=20 name="dataValue"><br> <input type=submit> </form> </body> </html>
tail -f /usr/local/tomcat1/logs/catalina.out tail -f /usr/local/tomcat2/logs/catalina.out tail -f /usr/local/tomcat3/logs/catalina.out tail -f /usr/local/tomcat4/logs/catalina.out
chkconfig httpd on
1
2
3
4
5
|
cd
/tools
tar
zxvf pcre-8.12.
tar
.gz
cd
pcre-8.12
.
/configure
#默认是安装在/usr/local/目录下面,也可指定目录加参数 --prefix=/usr/local/
make
&&
make
install
|
1
2
3
4
5
|
cd
/tools
tar
zxvf openssl-1.0.0d.
tar
.gz
cd
openssl-1.0.0d
.
/configure
# 默认是安装在/usr/local/目录下面,也可指定目录加参数 --prefix=/usr/local/
make
&&
make
install
|
1
2
3
4
5
|
cd
/tools
tar
zxvf nginx-1.0.0.
tar
.gz
cd
nginx-1.0.0
.
/configure
#默认是安装在/usr/local/目录下面,也可指定目录加参数 --prefix=/usr/local/
make
&&
make
install
|
1
2
3
4
5
|
cd
/usr/local/nginx/sbin/
.
/nginx
-t
nginx: the configuration
file
/usr/local/nginx/conf/nginx
.conf syntax is ok
nginx: configuration
file
/usr/local/nginx/conf/nginx
.conf
test
is successful
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
pid logs
/nginx
.pid;
upstream tomcat {
# 负载均衡站点的名称为tomcat,可以自己取
ip_hash;
# 可选,根据来源IP方式选择web服务器,省略的话按默认的轮循方式选择web服务器
server 192.168.0.101:81;
# web服务器的IP地址及tomcat发布端口
server 192.168.0.101:82;
server 192.168.0.102:83;
server 192.168.0.102:84;
}
server {
listen 80;
# 站点侦听端口80
server_name localhost;
# 站点名称
location / {
root html;
index index.html index.htm;
proxy_pass http:
//tomcat
;
# 负载均衡指向的发布服务tomcat
}
|
upstream
部分要放在server { listen 80
这部分的前面,不能放到下面去,不然会出错proxy_pass
部分要放在localtion这部分的括号里面,且http://
后面跟的名称要与上面upstream
中一样
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
cd
/usr/local/nginx/sbin/
.
/nginx
-t
# 测试配置有无错误
.
/nginx
# 启动服务
netstat
-tlnp |
grep
:80
#查看nginx端口的进程号
kill
-9 11274
#杀死nginx的主进程,11274是上面查询出来的主进程号,实际环境中不一定一样
# 在线修改配置参数(在nginx启动的情况),并让它重新加载,其间nginx不用停止服务。
vi
nginx.conf
kill
-HUP `
cat
/usr/local/nginx/logs/nginx
.pid`
# 设置Nginx开机自动启动
vim
/etc/rc
.d
/init
.d
/nginx
,增加内容
#chkconfig:35 80 10
#description:Nginx server
/usr/local/nginx/sbin/nginx
chmod
a+x nginx
chkconfig --add nginx
chkconfig nginx on
|
Tomcat7所支持的本地连接:
其他AJP连接器可能可以工作,但不再维护。
从上面的说明可以看出,如果你只需要一个Tomcat,那就直接用就好了,不用和Apache HTTP Server连接。如果需要多个Tomcat集群,就是AJP连接。所以用HTTP连接Apache和Tomcat这种情况应该不多,简单说明一下怎么连接: 取消两个module的注释:
LoadModule proxy_module modules/mod_proxy.so LoadModule proxy_http_module modules/mod_proxy_http.so
在httpd.conf文件中添加以下两行:
ProxyPass /webappname http://ip:8080/webappname ProxyPassReverse /webappname http://ip:8080/webappname
ip、端口号和webappname根据实际情况修改
说明:上述写法可能有安全隐患。不要使用ProxyRequests启用代理,除非对代理做了权限控制。否则对你的网络和互联网都是很大的危险。默认ProxyRequests为off。
参考:http://httpd.apache.org/docs/2.4/mod/mod_proxy.html#access
AJP连接官方支持两种方式JK 1.2.x和mod_proxy。
JK是老牌连接器,被广泛使用和验证,值得信任,但是配置比较复杂。
mod_proxy是Apache2.2以后的默认设置,配置简单,但是因为比较新,所以没有经过大范围的验证。
网上JK的文档比较多,这里我们介绍一下mod_proxy的写法。其实跟HTTP的方式一样,只是把http://
修改为ajp://
就可以了。
取消两个module的注释
LoadModule proxy_module modules/mod_proxy.so LoadModule proxy_ajp_module modules/mod_proxy_ajp.so
在httpd.conf文件中添加以下行:
ProxyPass /webappname ajp://ip:8009/webappname
ip、端口号和webappname根据实际情况修改
AJP连接通常不需要设置ProxyPassReverse。
参考:http://httpd.apache.org/docs/2.4/mod/mod_proxy_ajp.html
如文章开始所述,Apache Http Server和Tomcat集群要用AJP方式连接
同样集群可以用JK和mod_proxy两种方式,这里介绍mod_proxy的方式:
取消五个module的注释
LoadModule proxy_module modules/mod_proxy.so LoadModule proxy_ajp_module modules/mod_proxy_ajp.so LoadModule proxy_balancer_module modules/mod_proxy_balancer.so LoadModule slotmem_shm_module modules/mod_slotmem_shm.so LoadModule lbmethod_heartbeat_module modules/mod_lbmethod_heartbeat.so
根据负载均衡调度策略的不同,取消如下module的注释
LoadModule lbmethod_byrequests_module modules/mod_lbmethod_byrequests.so LoadModule lbmethod_bytraffic_module modules/mod_lbmethod_bytraffic.so LoadModule lbmethod_bybusyness_module modules/mod_lbmethod_bybusyness.so
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
<Proxy balancer:
//mycluster
>
#定义一个集群,起个名字
#定义集群成员。loadfactor是权重,数值越大权重越大被分配的请求约多。route和Tomcat中配置的jvmRoute一至。
#还有一些参数可以添加,比如:max=20 ttl=120 retry=300 timeout=15,详细参考:http://httpd.apache.org/docs/2.4/mod/mod_proxy.html#proxypass
BalancerMember ajp:
//ip
:8019 loadfactor=1 route=tomcat7_a
BalancerMember ajp:
//ip
:8029 loadfactor=2 route=tomcat7_b
#热备服务器,只有在上面的BalancerMember都坏掉之后才会被启用。
BalancerMember ajp:
//ip
:8009 status=+H
#现有3种负载均衡调度策略
#byrequests:请求计数(Request Counting)
#bytraffic:流量加权计数(Weighted Traffic Counting)
#bybusyness:挂起请求计数(Pending Request Counting)
#默认是byrequests
ProxySet lbmethod=bytraffic
<
/Proxy
>
ProxyPass
/examples
balancer:
//mycluster/examples
#设置代理连接
|
当一个请求被代理到某个节点,接下来同一个用户的请求都将被代理到相同的节点。很多均衡器通过一张记录客户端ip和节点的关系表来实现这个特性。这种方式对客户端和节点都是透明的,但是存在一些问题:如果客户端藏在某些代理之后将导致负载分布不均,当客户端使用动态IP地址,并在请求间变更,将失去粘性,关系表溢出将导致错误等问题。
mod_proxy_balancer通过两种方式实现粘性:cookies和URL encoding。cookie可以被Apache服务器和节点使用,URL encoding通常在节点中使用。
下面的例子使用mod_headers提供负载均衡粘性,即使节点服务器没有设置合适的session cookie。
Header add Set-Cookie "ROUTEID=.%{BALANCER_WORKER_ROUTE}e; path=/" env=BALANCER_ROUTE_CHANGED <Proxy balancer://mycluster> ...... </Proxy> ProxyPass /test balancer://mycluster
env变量有6种,参考:http://httpd.apache.org/docs/2.4/mod/mod_proxy_balancer.html#environment
以下配置同时支持cookies和URL encoding
ProxyPass /test balacer://mycluuster stickysession=JSESSIONID|jsessionid scolonpathdelim=On <Proxy balancer://mycluster> BlancerMember http://192.168.1.50:80 route=node1 BlancerMember http://192.168.1.51:80 route=node2 </Proxy>
LogFormat "%v %h %l %u %t \"%r\" %{Set-Cookie}o %{BALANCER_SESSION_STICKY}e %{BALANCER_SESSION_ROUTE}e %{BALANCER_WORKER_ROUTE}e %>s %b" balance_common CustomLog logs/balance_log balance_common
将集群的日志写到Apache服务器目录下的logs/balance_log文件中。
参考:http://httpd.apache.org/docs/2.4/mod/mod_proxy_balancer.html#stickyness_troubleshooting
需要mod_status。管理页面可以动态更新集群成员,修改平衡器的属性和特定成员或使之离线。
<Location /balancer-manager> SetHandler balancer-manager Require ip 192.168 </Location>
你可以通过http://your.server.name/balancer-manager
访问管理页面。
注意,只有balancers在<Location ...>之外定义,才能使用管理页面。
1
2
3
4
5
6
7
8
|
server {
#添加一个站点
listen 82;
#设置端口
server_name localhost;
#站点名称/域名
location / {
#设置路径
proxy_pass http:
//ip
:8080;
#http代理,指向tomcat http地址
}
}
|
在nginx.conf文件中添加一个server{},listen设置端口,server_name设置域名,location设置目录。
proxy_pass是http代理,指向tomcat地址。
修改后conf后,nginx -s reload就可以热更新了,很方便。
关于AJP连接,有一种说法是Nginx采用连接池,所以HTTP方式的连接不比AJP方式差。
有人的测试结果是Nginx通过HTTP连接Tomcat 性能略强于Apache通过AJP连接Tomcat。
参见:http://nginx.2469901.n2.nabble.com/AJP-td7582236.html
Nginx本身并不支持AJP连接,但有人写了一个nginx_ajp_module来支持ajp。由于是第三方控件,所以请在充分测试后使用。
cd nginx_dir/ patch -p1 < /tools/nginx_ajp_module/ajp.patch ./configure --prefix=/usr/nginx1.5.3 --add-module=/tools/nginx_ajp_module make make install
先到nginx安装文件的目录下,打ajp补丁,重新配置configure,编辑,安装。
1
2
3
4
5
6
7
8
9
|
server {
listen 82;
server_name localhost;
location / {
ajp_keep_conn on;
#设置是否保持连接
ajp_pass ajp:
//ip
:8009;
#Tomcat ajp连接地址和端口
}
}
|
其他配置详情参考:https://github.com/yaoweibin/nginx_ajp_module
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
upstream tomcat_http {
#用upstream定义一组服务器
#ip_hash通过记录客户端ip实现粘性session。有一个第三方的module可以用cookie实现粘性:https://code.google.com/p/nginx-sticky-module/
ip_hash;
#通过server定义多个服务器
#weight是权重,默认为1。
#max_fails和fail_timeout配合使用,在fail_timeout时间内通信失败达到max_fails的次数后,此服务器在fail_timeout时间内被认为不可用。
server 192.168.50.65:8090 weight=2;
server 192.168.50.65:8091 max_fails=3 fail_timeout=30s;
#keepalive为连接开启缓存,并设置缓存连接的最大数量。
keepalive 10;
}
server {
listen 82;
server_name localhost;
location / {
#将proxy_pass后的服务器地址,变为upstream的名字
proxy_pass http:
//tomcat_http
;
}
}
|
更多参数说明参考:http://nginx.org/en/docs/http/ngx_http_upstream_module.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
upstream tomcat_ajp {
# upstream定义一组服务器
#srun_id同Tomcat配置中Engine的jvmRoute。
server 192.168.50.65:8019 srun_id=tomcat7_a weight=2;
server 192.168.50.65:8029 srun_id=tomcat7_b;
#用cookie方式实现粘性session
jvm_route $cookie_JSESSIONID reverse;
keepalive 10;
}
server {
listen 82;
server_name localhost;
location / {
ajp_keep_conn on;
ajp_pass tomcat_ajp;
#指定连接到哪个upstream上
}
}
|