标签: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 "%r" %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 "%r" %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
标签:tomcat多实例 nginx反向代理tomcat tomcat
原文地址:http://zhaochj.blog.51cto.com/368705/1663663