码迷,mamicode.com
首页 > 其他好文 > 详细

tengine反向代理tomcat多实例实现负载均衡

时间:2015-06-19 21:42:14      阅读:351      评论:0      收藏:0      [点我收藏+]

标签:tomcat多实例 nginx反向代理tomcat tomcat

目录

1、引语

2、jdk与tomcat的安装

3、tomcat多实例配置与测试

4、tengine安装与负载均衡配置

5、整体测试

6、思考和优化tomcat配置流程

7、总结

1、引语

    有没有这样一种情况,你在一台服务器跑了一个tomcat实例,当有一天你发现不管你怎么优化tomcat,它的并发能力处理能力始终上不去了,而你服务器的硬件资源还有一部份剩余时,这时你就得采用tomcat启用多实例的方式,让剩下的硬件资源也一起利用起来,让用户的请求分摊到多个实例上来处理,这样只要硬件资源允许能大大提升tomcat的整体性能,利用前端的反向代理软件还可实例tomcat实例级别的高可用和负载均衡。前端的反向代理软件选择比较多,可以用LVS、Haproxy、Apache、Nginx,比较常用的是Apache和Nginx。Apache可以实现http和AJP方式与tomcat结合,而Nginx只能选择http的方式。关于apache与tomcat整合请见http://zhaochj.blog.51cto.com/368705/1641939

    接下来我们在tomcat上实现多实例,并利用nginx以反向代理的方式与tomcat整合实现负载均衡。

2、jdk与tomcat的安装

    这次测试所使用的系统环境与软件如下所示:

[root@nod3 tomcat]# cat /etc/issue
CentOS release 6.4 (Final)
Kernel \r on an \m
[root@nod3 tomcat]# uname -r
2.6.32-358.el6.x86_64
[root@nod3 tomcat]# pwd
/root/tomcat
[root@nod3 tomcat]# ls
apache-tomcat-7.0.62.tar.gz  jdk-7u9-linux-x64.rpm  tengine-2.1.0-1.el6.x86_64.rpm

安装JDK:

[root@nod3 tomcat]# rpm -ivh jdk-7u9-linux-x64.rpm
Preparing...                ########################################### [100%]
   1:jdk                    warning: /etc/init.d/jexec saved as /etc/init.d/jexec.rpmorig    #之前我这系统好像装过jdk
########################################### [100%]
Unpacking JAR files...
 rt.jar...
Error: Could not open input file: /usr/java/jdk1.7.0_09/jre/lib/rt.pack
 jsse.jar...
Error: Could not open input file: /usr/java/jdk1.7.0_09/jre/lib/jsse.pack
 charsets.jar...
Error: Could not open input file: /usr/java/jdk1.7.0_09/jre/lib/charsets.pack
 tools.jar...
Error: Could not open input file: /usr/java/jdk1.7.0_09/lib/tools.pack
 localedata.jar...
Error: Could not open input file: /usr/java/jdk1.7.0_09/jre/lib/ext/localedata.pack
#上边的错误可忽略,不影响jdk的安装和使用
[root@nod3 tomcat]# vim /etc/profile.d/java.sh   #导出二进制文件路径:
export PATH=$PATH:/usr/java/latest/bin
[root@nod3 tomcat]# source /etc/profile.d/java.sh
[root@nod3 tomcat]# java -version
java version "1.7.0_09"
Java(TM) SE Runtime Environment (build 1.7.0_09-b05)
Java HotSpot(TM) 64-Bit Server VM (build 23.5-b02, mixed mode)
#能够正常显示java的版本信息

tomcat安装:

[root@nod3 tomcat]# tar xf apache-tomcat-7.0.62.tar.gz -C /usr/local/
[root@nod3 local]# ln -sv apache-tomcat-7.0.62 tomcat-7
`tomcat-7‘ -> `apache-tomcat-7.0.62‘
[root@nod3 local]# vim /etc/profile.d/tomcat.sh   #导出tomcat的二进制文件目录
export PATH=$PATH:/usr/local/tomcat-7/bin
[root@nod3 local]# source /etc/profile.d/tomcat.sh
[root@nod3 local]# catalina.sh version
Using CATALINA_BASE:   /usr/local/tomcat-7
Using CATALINA_HOME:   /usr/local/tomcat-7
Using CATALINA_TMPDIR: /usr/local/tomcat-7/temp
Using JRE_HOME:        /usr
Using CLASSPATH:       /usr/local/tomcat-7/bin/bootstrap.jar:/usr/local/tomcat-7/bin/tomcat-juli.jar
Server version: Apache Tomcat/7.0.62
Server built:   May 7 2015 17:14:55 UTC
Server number:  7.0.62.0
OS Name:        Linux
OS Version:     2.6.32-358.el6.x86_64
Architecture:   x86_64
JVM Version:    1.5.0
JVM Vendor:     Free Software Foundation, Inc.
#上边正确显示出tomcat版本信息

注:在以前的博文中写到在安装好JDK与tomcat后都全配置一些环境变量,但这里不需要去配置全局的环境变量,因为在多实例运行环境下对每个实例的管理都需要用脚本,所在那些环境变量都配置在各自的脚本中,以接下来的内容中有所体现。

3、tomcat多实例配置与测试

    在进行多实例环境部署时先要有个总体的规划,各个实例存放的目录在哪里?你的webapp程序放在哪里?我这里是这样的规划的,把各个实例都存放在“/usr/local/tomcat_instances/”目录下,webapp程序就存放在“/usr/local/tomcat_instances/站点名称/webapps/”目录下。

 创建实例目录:

[root@nod3 local]# mkdir -pv /usr/local/tomcat_instances/{nod1.test.com-instance-1,nod1.test.com-instance-2}  
mkdir: created directory `/usr/local/tomcat_instances‘
mkdir: created directory `/usr/local/tomcat_instances/nod1.test.com-instance-1‘
mkdir: created directory `/usr/local/tomcat_instances/nod1.test.com-instance-2‘

拷贝配置文件到各个实例目录并创建相应的工作目录:

[root@nod3 local]# cp -r /usr/local/tomcat-7/conf /usr/local/tomcat_instances/nod1.test.com-instance-1/
[root@nod3 local]# cp -r /usr/local/tomcat-7/conf /usr/local/tomcat_instances/nod1.test.com-instance-2/
[root@nod3 local]# mkdir -pv /usr/local/tomcat_instances/nod1.test.com-instance-1/{logs,temp,webapps/webpages,work}
[root@nod3 local]# mkdir -pv /usr/local/tomcat_instances/nod1.test.com-instance-2/{logs,temp,webapps/webpages,work}
[root@nod3 local]# tree /usr/local/tomcat_instances/nod1.test.com-instance-1//usr/local/tomcat_instances/nod1.test.com-instance-1/├── conf│   ├── catalina.policy│   ├── catalina.properties│   ├── context.xml│   ├── logging.properties│   ├── server.xml│   ├── tomcat-users.xml│   └── web.xml├── logs├── temp├── webapps│   └── webpages└── work6 directories, 7 files[root@nod3 local]# tree /usr/local/tomcat_instances/nod1.test.com-instance-2//usr/local/tomcat_instances/nod1.test.com-instance-2/├── conf│   ├── catalina.policy│   ├── catalina.properties│   ├── context.xml│   ├── logging.properties│   ├── server.xml│   ├── tomcat-users.xml│   └── web.xml├── logs├── temp├── webapps│   └── webpages└── work6 directories, 7 files

修改各个实例的监听端口站点目录:

第一个实例:

[root@nod3 local]# vim /usr/local/tomcat_instances/nod1.test.com-instance-1/conf/server.xml
............
 <!-- 在现在高版本的tomcat中也只是允许本地连接此端口,也是比较安全的 -->
<Server port="8005" shutdown="SHUTDOWN">
...........
<!-- http连接器监听的端口,第一个实例我不修改此值 -->
<Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" />
..........
<!-- AJP连接器监听的端口,只有当使用apache作为反向代理时才支持AJP协议,我这里采用nginx作为反应代理,所以禁用 -->
<!-- <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />  -->
........
<!-- 定义host容器,主要是定义appBase,host name可以不作修改,因为前端会用nginx作反应代理,tomcat并不直接面向用户,再增加了<Context />容器 -->
<Host name="localhost"  appBase="/usr/local/tomcat_instances/nod1.test.com-instance-1/webapps"
            unpackWARs="true" autoDeploy="true">
            <Context path="" docBase="webpages" />
.......
<!-- 修改日志文件的prefix -->
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
               prefix="nod1.test.com_access_log." suffix=".txt"
               pattern="%h %l %u %t &quot;%r&quot; %s %b" />

第二个实例:

[root@nod3 local]# vim /usr/local/tomcat_instances/nod1.test.com-instance-2/conf/server.xml
........
<!-- 第2个实例监听端口更换成8006,只要不与其他实例监听的端口相冲突即可-->
<Server port="8006" shutdown="SHUTDOWN">
......
<!-- http监听端口更换为8081端口,只要不与其他实例中监听的端口相冲突-->
<Connector port="8081" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" />
............
<!-- <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" /> -->
.........
<Host name="localhost"  appBase="/usr/local/tomcat_instances/nod1.test.com-instance-2/webapps"
            unpackWARs="true" autoDeploy="true">
            <Context path="" docBase="webpages" />
........
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
               prefix="nod1.test.com_access_log." suffix=".txt"
               pattern="%h %l %u %t &quot;%r&quot; %s %b" />
.......

为两个实例提供测试页面:

[root@nod3 local]# vim /usr/local/tomcat_instances/nod1.test.com-instance-1/webapps/webpages/index.jsp
<html><body><center>
<h1>This is "nod1.test.com-instance-1"</h1>
</br>
Now time is: <%=new java.util.Date()%>
</center>
</body></html>
[root@nod3 local]# vim /usr/local/tomcat_instances/nod1.test.com-instance-2/webapps/webpages/index.jsp
<html><body><center>
<h1>This is "nod1.test.com-instance-2"</h1>
</br>
Now time is: <%=new java.util.Date()%>
</center>
</body></html>

编写脚本启动各个实例:

[root@nod3 local]# vim /usr/local/tomcat_instances/nod1.test.com-instance-1/tomcat.sh
#!/bin/bash
#Program: manager tomcat instance
#Author: zhaochj
#Date: 2015-6-18
#Version 1.0
#
source /etc/rc.d/init.d/functions
JAVA_HOME=/usr/java/latest
CATALINA_HOME=/usr/local/tomcat-7
CATALINA_BASE=$PWD
export JAVA_HOME CATALINA_HOME CATALINA_BASE
export PATH=$PATH:$JAVA_HOME/bin:$CATALINA_HOME/bin
case "$1" in
        start)
                $CATALINA_HOME/bin/startup.sh && exit 0
        ;;
        stop)
                $CATALINA_HOME/bin/shutdown.sh && exit 0
        ;;
        *)
                echo "Usage: $0{start|stop}" && exit 1
        ;;
esac
[root@nod3 local]# chmod +x /usr/local/tomcat_instances/nod1.test.com-instance-1/tomcat.sh
[root@nod3 local]# cd /usr/local/tomcat_instances/nod1.test.com-instance-1/   #切换到实例目录
[root@nod3 nod1.test.com-instance-1]# sh tomcat.sh start
Using CATALINA_BASE:   /usr/local/tomcat_instances/nod1.test.com-instance-1
Using CATALINA_HOME:   /usr/local/tomcat-7
Using CATALINA_TMPDIR: /usr/local/tomcat_instances/nod1.test.com-instance-1/temp
Using JRE_HOME:        /usr/java/latest
Using CLASSPATH:       /usr/local/tomcat-7/bin/bootstrap.jar:/usr/local/tomcat-7/bin/tomcat-juli.jar
Tomcat started.

注意:利用这个脚本来启动实例时一定要切换到实例的目录才可以,因为脚本中“CATALINA_BASE=$PWD”是把当前目录当作tomcat的工作目录,当然也可以写成绝对的路径,像这样“CATALINA_BASE=/usr/local/tomcat_instances/nod1.test.com-instance-1”,这样定义后使用此脚本就没有一定要切换到实例的目录的限制。

[root@nod3 nod1.test.com-instance-1]# ss -tnlp | grep java
LISTEN     0      100                      :::8080                    :::*      users:(("java",2119,42))
LISTEN     0      1          ::ffff:127.0.0.1:8005                    :::*      users:(("java",2119,46))
#两个端口已正常监听

再用浏览器测试,如下:

技术分享

[root@nod3 nod1.test.com-instance-1]# cp tomcat.sh ../nod1.test.com-instance-2/  #把脚本文件拷贝到另一个实例
[root@nod3 nod1.test.com-instance-1]# cd ../nod1.test.com-instance-2/
[root@nod3 nod1.test.com-instance-2]# pwd
/usr/local/tomcat_instances/nod1.test.com-instance-2
[root@nod3 nod1.test.com-instance-2]# ls
conf  logs  temp  tomcat.sh  webapps  work
[root@nod3 nod1.test.com-instance-2]# sh tomcat.sh start
Using CATALINA_BASE:   /usr/local/tomcat_instances/nod1.test.com-instance-2
Using CATALINA_HOME:   /usr/local/tomcat-7
Using CATALINA_TMPDIR: /usr/local/tomcat_instances/nod1.test.com-instance-2/temp
Using JRE_HOME:        /usr/java/latest
Using CLASSPATH:       /usr/local/tomcat-7/bin/bootstrap.jar:/usr/local/tomcat-7/bin/tomcat-juli.jar
Tomcat started.
[root@nod3 nod1.test.com-instance-2]# ss -tnlp | grep java
LISTEN     0      100                      :::8080                    :::*      users:(("java",2187,42))
LISTEN     0      100                      :::8081                    :::*      users:(("java",2216,42))
LISTEN     0      1          ::ffff:127.0.0.1:8005                    :::*      users:(("java",2187,46))
LISTEN     0      1          ::ffff:127.0.0.1:8006                    :::*      users:(("java",2216,46))
#两个实例各自监听的端口都处于LISTEN状态

打开浏览器测试一下第二个实例,如下:

技术分享

4、tengine安装与负载均衡配置

    tengine是taobao在官方nginx上的基础上二次发行的一个版本,tengine继承了nginx的特性,完全兼容nginx,taobao还在nginx基础上增加了一些新的特性,比如能动态加载模块等,详细请见http://tengine.taobao.org/

[root@nod3 tomcat]# pwd
/root/tomcat
[root@nod3 tomcat]# ls
apache-tomcat-7.0.62.tar.gz  jdk-7u9-linux-x64.rpm  tengine-2.1.0-1.el6.x86_64.rpm
[root@nod3 tomcat]# rpm -ivh tengine-2.1.0-1.el6.x86_64.rpm   #安装tengine
Preparing...                ########################################### [100%]
   1:tengine                ########################################### [100%]
[root@nod3 tomcat]# cp /etc/tengine/nginx.conf{,.back}   #备份原有配置文件
[root@nod3 tomcat]# ls /etc/tengine/nginx.conf*
/etc/tengine/nginx.conf  /etc/tengine/nginx.conf.back  /etc/tengine/nginx.conf.default

修改配置文件,满足我们的需求:

[root@nod3 tomcat]# vim /etc/tengine/nginx.conf
#user  nobody;
worker_processes  1;
#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;
#pid        logs/nginx.pid;
events {
    worker_connections  1024;
}
# load modules compiled as Dynamic Shared Object (DSO)
#
#dso {
#    load ngx_http_fastcgi_module.so;
#    load ngx_http_rewrite_module.so;
#}
http {
    include       mime.types;
    default_type  application/octet-stream;
    #log_format  main  ‘$remote_addr - $remote_user [$time_local] "$request" ‘
    #                  ‘$status $body_bytes_sent "$http_referer" ‘
    #                  ‘"$http_user_agent" "$http_x_forwarded_for"‘;
    #access_log  logs/access.log  main;
    sendfile        on;
    #tcp_nopush     on;
    #keepalive_timeout  0;
    keepalive_timeout  65;
    #gzip  on;
    upstream tomcat_backend {   #定义一个upstream
#       ip_hash;   #调度算法,在测试时可禁用
        server 127.0.0.1:8080;  #定义一个后端tomcat实例
        server 127.0.0.1:8081;  #定义另一个后端tomcat实例
        server 127.0.0.1:9111 backup;  #定义一个backup,当后端的所有tomcat实例down后向这个备份站点调度
        check interval=3000 rise=2 fall=5 timeout=1000 type=http;  #定义对后端服务器的健康检测机制
        check_http_send "HEAD / HTTP/1.0\r\n\r\n";   #定义健康检测方法,以http的方式检测
        check_http_expect_alive http_2xx http_3xx;
    }
    server {   #定义backup的虚拟主机
        listen 9111;
        server_name localhost;
        location / {
            root html;
            index index.html;
        }
    }
    server {  #定义对外提供服务的虚拟主机
        listen       80;
        server_name  nod3.test.com;
        #charset koi8-r;
        #access_log  logs/host.access.log  main;
        location / {
            proxy_pass http://tomcat_backend;    #定义向后端转发
        }
        location /status {  #定义健康检测的监控页面
            auth_basic "nginx check health status";  #定义进行健康页面的认证方式
            auth_basic_user_file /etc/tengine/.htpasswd;  #认证用户名及密码在存放路径
            check_status;  #开启健康检测
            access_log off;  #对后端健康检测的行为不记录到日志
            allow 192.168.0.0/24;  #允许访问检测页面的网段
            deny all; #拒绝其他访问
        }
.....略....

修改nginx的备份虚拟主机的主页面:

[root@nod3 tomcat]# cp /usr/local/tengine/html/index.html{,.back}
[root@nod3 tomcat]# vim /usr/local/tengine/html/index.html
<h1>Sorry, you visit the website is currently under maintenance!</h1>
创建访问健康检测页面的用户名及密码:
[root@nod3 tomcat]# htpasswd -c -m /etc/tengine/.htpasswd tengine
New password:
Re-type new password:
Adding password for user tengine
[root@nod3 tomcat]# cat /etc/tengine/.htpasswd
tengine:$apr1$W9U8oBI3$Ae2Q7FpSWGJw9CEcNdqWK0

启动nginx,测试健康检测页面:

[root@nod3 tomcat]# service nginx start
Starting nginx:                                            [  OK  ]
[root@nod3 tomcat]# ss -tnlp | grep nginx
LISTEN     0      128                       *:80                       *:*      users:(("nginx",2360,7),("nginx",2361,7))
LISTEN     0      128                       *:9111                     *:*      users:(("nginx",2360,6),("nginx",2361,6))
#两个虚拟主机都在监听状态

打开浏览器访问健康检测页面:

技术分享输入正确的用户名和密码后能正常打开,如下:

技术分享

后端的两个tomcat实例还没有启动,所以状态是down的。

分别切换到两个tomcat实例目录,启动相应的实例:

[root@nod3 tomcat]# cd /usr/local/tomcat_instances/nod1.test.com-instance-1/  #切换到第一个实例目录
[root@nod3 nod1.test.com-instance-1]# sh tomcat.sh start  #启动第一个实例
Using CATALINA_BASE:   /usr/local/tomcat_instances/nod1.test.com-instance-1
Using CATALINA_HOME:   /usr/local/tomcat-7
Using CATALINA_TMPDIR: /usr/local/tomcat_instances/nod1.test.com-instance-1/temp
Using JRE_HOME:        /usr/java/latest
Using CLASSPATH:       /usr/local/tomcat-7/bin/bootstrap.jar:/usr/local/tomcat-7/bin/tomcat-juli.jar
Tomcat started.
[root@nod3 nod1.test.com-instance-1]# cd ../nod1.test.com-instance-2/  #切换到第二个实例
[root@nod3 nod1.test.com-instance-2]# sh tomcat.sh start  #启动第二个实例
Using CATALINA_BASE:   /usr/local/tomcat_instances/nod1.test.com-instance-2
Using CATALINA_HOME:   /usr/local/tomcat-7
Using CATALINA_TMPDIR: /usr/local/tomcat_instances/nod1.test.com-instance-2/temp
Using JRE_HOME:        /usr/java/latest
Using CLASSPATH:       /usr/local/tomcat-7/bin/bootstrap.jar:/usr/local/tomcat-7/bin/tomcat-juli.jar
Tomcat started.
[root@nod3 nod1.test.com-instance-2]# ss -tnl
State      Recv-Q Send-Q                                   Local Address:Port                                     Peer Address:Port
LISTEN     0      100                                                 :::8080                                               :::*    
LISTEN     0      128                                                  *:80                                                  *:*    
LISTEN     0      100                                                 :::8081                                               :::*    
LISTEN     0      128                                                 :::22                                                 :::*    
LISTEN     0      128                                                  *:22                                                  *:*    
LISTEN     0      128                                                  *:9111                                                *:*    
LISTEN     0      100                                                ::1:25                                                 :::*    
LISTEN     0      100                                          127.0.0.1:25                                                  *:*    
LISTEN     0      1                                     ::ffff:127.0.0.1:8005                                               :::*    
LISTEN     0      1                                     ::ffff:127.0.0.1:8006                                               :::*    
#nginx、tomcat各自监听的端口已全部处于LISTEN状态
[root@nod3 nod1.test.com-instance-2]# jps
2389 Bootstrap
2462 Jps
2435 Bootstrap
#两个tomcat实例已在线

刷新一下健康状态监控页面,可见backend server已全部在线,如下图:

技术分享

5、整体测试

    测试主要有以下几项,第一:在后端tomcat各实例都正常工作时,看用户访问能不能根据调度算法调度到各个实例上;第二:让后端的一个实例处理维护状态,测试前端的调度器能否切换到正常工作的实例上;第三:把后端各个实例都处理维护状态,测试调度器能否把用户的访问调度到backup服务器上,返回给用户一个网站在维护状态的页面;    

    先来测试第一项,打开浏览器直接访问前端nginx对外提供服务的地址“nod3.test.com”:

技术分享刷新一次后

技术分享

不断的刷新页面,会在后端两个tomcat实例上轮询访问相应的站点,因为我们在nginx.conf中没有指定调度算法,默认时就是round-robin算法,第一项测试通过。

    再来测试第二项,先编辑nginx.conf配置文件,让后端的一个实例处理维护状态,如下:

[root@nod3 nod1.test.com-instance-2]# vim /etc/tengine/nginx.conf
.....
upstream tomcat_backend {
#       ip_hash;
        server 127.0.0.1:8080 down;  #在server后加上down就表示让后端的这个实例下线,调度算法不再往这个实例上进行调度
        server 127.0.0.1:8081;
        server 127.0.0.1:9111 backup;
        check interval=3000 rise=2 fall=5 timeout=1000 type=http;
        check_http_send "HEAD / HTTP/1.0\r\n\r\n";
        check_http_expect_alive http_2xx http_3xx;
    }
[root@nod3 nod1.test.com-instance-2]# service nginx reload  #重新载入配置文件
the configuration file /etc/tengine/nginx.conf syntax is ok
configuration file /etc/tengine/nginx.conf test is successful
Reloading nginx:                                           [  OK  ]

刷新健康状态监控页面,看有什么变化,如下图:

技术分享刷新后,Name为“127.0.0.1:8080”的这个实例已被踢出,不再是集群的一部份,这正是我们所要的,再在主页的访问页面上刷新观察变化,如下图:

技术分享刷新后页面一直访问的是tomcat第二个实例提供的页面内容,所以调度器已把所有的请求都调度到了此实例上。至此,第二项测试通过!

接下来开始第三项测试,也让第二个实例处理维护状态,和上边同样操作:

[root@nod3 nod1.test.com-instance-2]# vim /etc/tengine/nginx.conf
.....
upstream tomcat_backend {
#       ip_hash;
        server 127.0.0.1:8080 down;  #在server后加上down就表示让后端的这个实例下线,调度算法不再往这个实例上进行调度
        server 127.0.0.1:8081 down; #同样加上down,让实例处理维护状态
        server 127.0.0.1:9111 backup;
        check interval=3000 rise=2 fall=5 timeout=1000 type=http;
        check_http_send "HEAD / HTTP/1.0\r\n\r\n";
        check_http_expect_alive http_2xx http_3xx;
    }
[root@nod3 nod1.test.com-instance-2]# service nginx reload  #重新载入配置文件
the configuration file /etc/tengine/nginx.conf syntax is ok
configuration file /etc/tengine/nginx.conf test is successful
Reloading nginx:                                           [  OK  ]

再刷新健康状态监控页面,如下图:

技术分享上图中后端的两个实例都不在了,再看一下主页访问页面,如下图:

技术分享

刷新后被调度到了nginx自己的虚拟主机上,给用户提供了一个友好的说明信息。至此,第三项测试也通过!

6、思考和优化tomcat配置流程

    至此,以nginx反向代理多实例tomcat实现负载均衡已能正常的工作,但不得不还要思考以下几个问题:

第一:安全问题,以上的测试都是基于root用户来启动tomcat的各个实例的,以root权限来运行一个服务是不可取的,应该以一个权限较低的用户来启动tomcat实例;

[root@nod3 ~]# ps  ax -o user,command | grep java  #下边的输出信息可见运行tomcat实例的用户是“root”
root     /usr/java/latest/bin/java -Djava.util.logging.config.file=/usr/local/tomcat_instances/nod1.test.com-instance-1/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djava.endorsed.dirs=/usr/local/tomcat-7/endorsed -classpath /usr/local/tomcat-7/bin/bootstrap.jar:/usr/local/tomcat-7/bin/tomcat-juli.jar -Dcatalina.base=/usr/local/tomcat_instances/nod1.test.com-instance-1 -Dcatalina.home=/usr/local/tomcat-7 -Djava.io.tmpdir=/usr/local/tomcat_instances/nod1.test.com-instance-1/temp org.apache.catalina.startup.Bootstrap start
root     /usr/java/latest/bin/java -Djava.util.logging.config.file=/usr/local/tomcat_instances/nod1.test.com-instance-2/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djava.endorsed.dirs=/usr/local/tomcat-7/endorsed -classpath /usr/local/tomcat-7/bin/bootstrap.jar:/usr/local/tomcat-7/bin/tomcat-juli.jar -Dcatalina.base=/usr/local/tomcat_instances/nod1.test.com-instance-2 -Dcatalina.home=/usr/local/tomcat-7 -Djava.io.tmpdir=/usr/local/tomcat_instances/nod1.test.com-instance-2/temp org.apache.catalina.startup.Bootstrap start

第二:tomcat多实例配置过程比较繁琐,如果能以一个脚本来完成配置,脚本运行后运维人员只需要提供好应用的源码,再修改相应的配置文件,这样一个实例很快就可配置好;

第三:当服务器运行的实例较多时,怎样对全部实例进行统一的管理,比如我需要所所有的实例都给停掉,再把所有的实例启动起来,这也需要一个脚本来对所有的实例进行统一的管理;

接下来我们就来解决上边的三个问题,第一个问题与第二个问题可以统一起来解决,在配置多实例时把手动创建目录,复制文件,修改权限操作全部在脚本中完成,并在启动实例时su到一个普通帐号就可实现,脚本如下:

[root@nod3 tomcat]# pwd
/root/tomcat
[root@nod3 tomcat]# ls
apache-tomcat-7.0.62.tar.gz  jdk-7u9-linux-x64.rpm  tengine-2.1.0-1.el6.x86_64.rpm  tomcat_instances_config.sh
[root@nod3 tomcat]# vim tomcat_instances_config.sh
#!/bin/bash
#Program: tomcat multiple instances configuration
#Author: zhaochj
#Date: 2015-6-18
#Version 1.0
#
source /etc/rc.d/init.d/functions
JAVA_HOME=/usr/java/latest
CATALINA_HOME=/usr/local/tomcat-7
INSTANCE_DIR=/usr/local/tomcat_instances
INSTANCE_NAME=nod1.test.com-instance-3
TOMCAT_USER=tomcat
#创建实例目录
if [ -d $INSTANCE_DIR ];then
    mkdir $INSTANCE_DIR/$INSTANCE_NAME
else
    echo ‘Plase check the $INSTANCE_DIR‘ && exit 1
fi
#复制所需文件及创建相应的工作目录
if [ -d $INSTANCE_DIR/$INSTANCE_NAME ];then
    cp -r $CATALINA_HOME/conf $INSTANCE_DIR/$INSTANCE_NAME/ > /dev/null 2>&1
    mkdir -pv $INSTANCE_DIR/$INSTANCE_NAME/{logs,temp,webapps/ROOT,work} > /dev/null 2>&1
fi
#创建用于启动tomcat实例的用户并修改实例目录的权限
id $TOMCAT_USER > /dev/null 2>&1 || useradd -r $TOMCAT_USER
chown -R $TOMCAT_USER:$TOMCAT_USER $INSTANCE_DIR/$INSTANCE_NAME
#定义一个控制tomcat启动关闭的脚本
cat > $INSTANCE_DIR/$INSTANCE_NAME/tomcat.sh << EOF
#!/bin/bash
#Program: manager tomcat instance start or stop
#Author: zhaochj
#Date: 2015-6-18
#Version 1.0
#
source /etc/rc.d/init.d/functions
JAVA_HOME=/usr/java/latest
#定义tomcat启动参数
JAVA_OPTS="-Xms128M -Xmx128M"
CATALINA_HOME=/usr/local/tomcat-7
CATALINA_BASE=\$PWD
TOMCAT_USER=tomcat
export JAVA_HOME JAVA_OPTS CATALINA_HOME CATALINA_BASE
#定义函数
start() {
        su \$TOMCAT_USER \$CATALINA_HOME/bin/startup.sh
}
stop() {
        su \$TOMCAT_USER \$CATALINA_HOME/bin/shutdown.sh
}
restart() {
        stop
        sleep 3
        start
}
#接受传递的参数做相应的操作
case "\$1" in
        start)
             \$1
             ;;
        stop)
             \$1
             ;;
        restart)
             \$1
             ;;
        *)
                echo "Usage: \$0{start|stop|restart}" && exit 1
        ;;
esac
EOF
#修改脚本权限
chmod ug+x $INSTANCE_DIR/$INSTANCE_NAME/tomcat.sh
[root@nod3 tomcat]# chmod +x tomcat_instances_config.sh

接下来测试脚本的可用性:

[root@nod3 tomcat]# ls /usr/local/tomcat_instances/   #存放tomcat各实例目录里只有两个目录
nod1.test.com-instance-1  nod1.test.com-instance-2
[root@nod3 tomcat]# sh tomcat_instances_config.sh   #运行脚本
[root@nod3 tomcat]# ls /usr/local/tomcat_instances/ -l
total 12
drwxr-xr-x 7 root   root   4096 Jun 18 22:28 nod1.test.com-instance-1
drwxr-xr-x 7 root   root   4096 Jun 18 22:42 nod1.test.com-instance-2
drwxr-xr-x 7 tomcat tomcat 4096 Jun 19 15:15 nod1.test.com-instance-3   #第三个实例目录生成,并且属主与属组已是tomcat
[root@nod3 tomcat]# ls /usr/local/tomcat_instances/nod1.test.com-instance-3/ -l  #只有脚本的属主、属组是root,而且其他用户没有可执行权限
total 24
drwxr-xr-x 2 tomcat tomcat 4096 Jun 19 15:15 conf
drwxr-xr-x 2 tomcat tomcat 4096 Jun 19 15:15 logs
drwxr-xr-x 2 tomcat tomcat 4096 Jun 19 15:15 temp
-rwxr-xr-- 1 root   root    717 Jun 19 15:15 tomcat.sh
drwxr-xr-x 3 tomcat tomcat 4096 Jun 19 15:15 webapps
drwxr-xr-x 2 tomcat tomcat 4096 Jun 19 15:15 work

提供一个测试主页做测试:

[root@nod3 tomcat]# vim /usr/local/tomcat_instances/nod1.test.com-instance-3/webapps/ROOT/index.jsp
<html><body><center>
<h1>This is a new tomcat instance!</h1>
</br>
Now time is: <%=new java.util.Date()%>
</center>
</body></html>

启动第三个实例:

[root@nod3 tomcat]# cd /usr/local/tomcat_instances/nod1.test.com-instance-3/
  #不要忘记切换到实例目录
[root@nod3 nod1.test.com-instance-3]# ./tomcat.sh start
  #启动实例
Using CATALINA_BASE:   /usr/local/tomcat_instances/nod1.test.com-instance-3
Using CATALINA_HOME:   /usr/local/tomcat-7
Using CATALINA_TMPDIR: /usr/local/tomcat_instances/nod1.test.com-instance-3/temp
Using JRE_HOME:        /usr/java/latest
Using CLASSPATH:       /usr/local/tomcat-7/bin/bootstrap.jar:/usr/local/tomcat-7/bin/tomcat-juli.jar
Tomcat started.
[root@nod3 nod1.test.com-instance-3]# ss -tnlp | grep java
LISTEN     0      100                      :::8080                    :::*      users:(("java",3592,42))
LISTEN     0      1          ::ffff:127.0.0.1:8005                    :::*      users:(("java",3592,47))
LISTEN     0      100                      :::8009                    :::*      users:(("java",3592,43))
#默认的配置文件监听的三个端口都处于LISTEN状态
[root@nod3 nod1.test.com-instance-3]# ps ax -o user,command | grep java
  #查看java进程
tomcat   /usr/java/latest/bin/java -Djava.util.logging.config.file=/usr/local/tomcat_instances/nod1.test.com-instance-3/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Xms128M -Xmx128M -Djava.endorsed.dirs=/usr/local/tomcat-7/endorsed -classpath /usr/local/tomcat-7/bin/bootstrap.jar:/usr/local/tomcat-7/bin/tomcat-juli.jar -Dcatalina.base=/usr/local/tomcat_instances/nod1.test.com-instance-3 -Dcatalina.home=/usr/local/tomcat-7 -Djava.io.tmpdir=/usr/local/tomcat_instances/nod1.test.com-instance-3/temp org.apache.catalina.startup.Bootstrap start
root     grep java
#上边的输出结果可见运行java进程的用户不再是root,而是tomcat用户

而用浏览器访问此实例提供的服务也是正常的,见下图:

技术分享

再测试一下tomcat.sh脚本的stop、restart功能,这里就不略过。至此用脚本的方式来部署tomcat多实例就顺利完成。下边再来写一个能管理全部实例的脚本。

脚本内容如下:

[root@nod3 tomcat]# vim tomcat_instances_manager.sh
#!/bin/bash
#Describe: Unified management tomcat instances
#Author: zhaochj
#Date: 2015-6-19
#Version: 1.0
#
source /etc/init.d/functions
JAVA_HOME=/usr/java/latest
CATALINA_HOME=/usr/local/tomcat-7
INSTANCE_DIR=/usr/local/tomcat_instances
TOMCAT_USER=tomcat
SCRIPT_NAME=tomcat.sh
startall() {
    for instance_name in `ls $INSTANCE_DIR`;do
        cd $INSTANCE_DIR/$instance_name
        sh $SCRIPT_NAME start > /dev/null 2>&1 && echo "$instance_name start ok!" || echo "$instance_name unable to start."
        sleep 3
    done
}
stopall() {
    for instance_name in `ls $INSTANCE_DIR`;do
        cd $INSTANCE_DIR/$instance_name
        sh $SCRIPT_NAME stop > /dev/null 2>&1 && echo "$instance_name stoped." || echo "$instance_name unable to stop."
        sleep 3
    done
}
#直接杀掉进程
killall() {
    for jvmpid in `$JAVA_HOME/bin/jps | grep -i bootstrap | awk ‘{print $1}‘`;do
        kill -9 $jvmpid
    done
}
case "$1" in
    startall)
            $1
            ;;
    stopall)
            $1
            ;;
    killall)
            $1
            ;;
    *)
            echo "Usage: $0{startall|stopall|killall}" && exit 1
            ;;
esac
[root@nod3 tomcat]# chmod +x tomcat_instances_manager.sh

为了方便测试能统一管理全部实例的脚本,先把先前部署的第一个和第二个实例目录的属主与属组修改成tomcat,并把启动实例的脚本更换为实例三中的脚本,即如下操作:

[root@nod3 tomcat]# chown -R tomcat:tomcat /usr/local/tomcat_instances/nod1.test.com-instance-1/
[root@nod3 tomcat]# chown -R tomcat:tomcat /usr/local/tomcat_instances/nod1.test.com-instance-2/
[root@nod3 tomcat]# cp /usr/local/tomcat_instances/nod1.test.com-instance-3/tomcat.sh /usr/local/tomcat_instances/nod1.test.com-instance-1/
cp: overwrite `/usr/local/tomcat_instances/nod1.test.com-instance-1/tomcat.sh‘? y
[root@nod3 tomcat]# cp /usr/local/tomcat_instances/nod1.test.com-instance-3/tomcat.sh /usr/local/tomcat_instances/nod1.test.com-instance-2/
cp: overwrite `/usr/local/tomcat_instances/nod1.test.com-instance-2/tomcat.sh‘? y
[root@nod3 tomcat]# ll /usr/local/tomcat_instances/nod1.test.com-instance-1/
total 24
drwxr-xr-x 3 tomcat tomcat 4096 Jun 18 22:34 conf
drwxr-xr-x 2 tomcat tomcat 4096 Jun 19 11:02 logs
drwxr-xr-x 2 tomcat tomcat 4096 Jun 18 21:16 temp
-rwxr-xr-x 1 tomcat tomcat  717 Jun 19 16:05 tomcat.sh
drwxr-xr-x 3 tomcat tomcat 4096 Jun 18 21:34 webapps
drwxr-xr-x 3 tomcat tomcat 4096 Jun 18 22:14 work
[root@nod3 tomcat]# ll /usr/local/tomcat_instances/nod1.test.com-instance-2/
total 24
drwxr-xr-x 3 tomcat tomcat 4096 Jun 18 22:48 conf
drwxr-xr-x 2 tomcat tomcat 4096 Jun 19 11:03 logs
drwxr-xr-x 2 tomcat tomcat 4096 Jun 18 21:16 temp
-rwxr-xr-x 1 tomcat tomcat  717 Jun 19 16:06 tomcat.sh
drwxr-xr-x 3 tomcat tomcat 4096 Jun 18 21:35 webapps
drwxr-xr-x 3 tomcat tomcat 4096 Jun 18 22:47 work

注意:第三个实例监听的端口是与第一个实例相冲突的,不要忘记修改,把<Server />容器中的"prot=8005"修改成"prot=8007",注释掉AJP连接器,http连接器的端口修改为8082,修改过程不再列出,可以按照上边修改第二个实例的方法来修改。

用脚本启动所有的实例:

[root@nod3 tomcat]# sh tomcat_instances_manager.sh startall
nod1.test.com-instance-1 start ok!
nod1.test.com-instance-2 start ok!
nod1.test.com-instance-3 start ok!
[root@nod3 tomcat]# jps
5269 Bootstrap
5241 Bootstrap
5294 Bootstrap
5308 Jps

等一会后查看端口的监听状态,如下:

[root@nod3 tomcat]# ss -tnl
State      Recv-Q Send-Q                                   Local Address:Port                                     Peer Address:Port
LISTEN     0      100                                                 :::8080                                               :::*    
LISTEN     0      100                                                 :::8081                                               :::*    
LISTEN     0      100                                                 :::8082                                               :::*    
LISTEN     0      128                                                 :::22                                                 :::*    
LISTEN     0      128                                                  *:22                                                  *:*    
LISTEN     0      100                                                ::1:25                                                 :::*    
LISTEN     0      100                                          127.0.0.1:25                                                  *:*    
LISTEN     0      1                                     ::ffff:127.0.0.1:8005                                               :::*    
LISTEN     0      1                                     ::ffff:127.0.0.1:8006                                               :::*    
LISTEN     0      1                                     ::ffff:127.0.0.1:8007                                               :::* 
#各个实例的监听端口都是LISTEN状态

再关闭所有实例,如下:

[root@nod3 tomcat]# sh tomcat_instances_manager.sh stopall
nod1.test.com-instance-1 stoped.
nod1.test.com-instance-2 stoped.
nod1.test.com-instance-3 stoped.
[root@nod3 tomcat]# jps
5439 Jps
#如果stopall不能全部关闭实例,那直接传递killall参数。

7、总结

    至此,一个多实例的tomcat配置就完成了,并利用tengine实现了实例级别的负载均衡系统。tomcat的运行也是用root用户运行,在安全性在得到了一定的保障,在配置多实例时还利用脚本完成配置操作,在对多实例的统一管理上也实现了用脚本来统一管理,这大大节省了部署的时间,提高了生产率,但在生产环境下,在tomcat上线前还得做一些基本安全加固和优化操作,下一次再开一博来唠唠。

两个tomcat多实例的管理脚本请在这里下载:https://github.com/zhaochj/myrepository/tree/master/shellscripts


本文出自 “专注运维,与Linux共舞” 博客,请务必保留此出处http://zhaochj.blog.51cto.com/368705/1663663

tengine反向代理tomcat多实例实现负载均衡

标签:tomcat多实例 nginx反向代理tomcat tomcat

原文地址:http://zhaochj.blog.51cto.com/368705/1663663

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!