Tomcat配置和优化(转)

---恢复内容开始---


本文链接:https://blog.csdn.net/Ezra1991/article/details/88605169

Tomcat 服务器是一个免费的开放源代码的Web 应用服务器,属于轻量级应用服务器,在中小型系统和并发访问用户不是很多的场合下被普遍使用,是开发和调试JSP 程序的首选。对于一个初学者来说,可以这样认为,当在一台机器上配置好Apache 服务器,可利用它响应HTML(标准通用标记语言下的一个应用)页面的访问请求。实际上Tomcat是Apache 服务器的扩展,但运行时它是独立运行的,所以当你运行tomcat 时,它实际上作为一个与Apache 独立的进程单独运行的。

Tomcat的拓扑方案:

方案一: Tomcat
方案二: Nginx+Tomcat
方案三:
Nginx
|
+----------------------------------------------+
| | | |
Tomcat1 Tomcat2 Tomcat3 nginx

一、Tomcat Http Server


1. 部署JAVA环境
# tar xf jdk-8u91-linux-x64.tar.gz -C /usr/local
# ln -s /usr/local/jdk1.8.0_91 /usr/local/java

# vim /etc/profile.d/jdk.sh
JAVA_HOME=/usr/local/java
PATH=$JAVA_HOME/bin:$PATH
export JAVA_HOME PATH

# source /etc/profile.d/jdk.sh
# env |grep JAVA
JAVA_HOME=/usr/local/java
# java -version
java version "1.8.0_91"
Java(TM) SE Runtime Environment (build 1.8.0_91-b14)
Java HotSpot(TM) 64-Bit Server VM (build 25.91-b14, mixed mode)

2. 安装Tomcat:
# tar xf apache-tomcat-7.0.34.tar.gz -C /usr/local/
# ln -s /usr/local/apache-tomcat-7.0.34 /usr/local/tomcat

定义Tomcat所需环境变量:
# vim /etc/profile.d/jdk.sh //定义Tomcat环境变量
CATALINA_HOME=/usr/local/tomcat //Tomcat安装目录
PATH=$CATALINA_HOME/bin:$PATH
export CATALINA_HOME PATH
# source /etc/profile.d/jdk.sh

启动Tomcat
# /usr/local/tomcat/bin/startup.sh //启动tomcat
Using CATALINA_BASE: /usr/local/tomcat
Using CATALINA_HOME: /usr/local/tomcat
Using CATALINA_TMPDIR: /usr/local/tomcat/temp
Using JRE_HOME: /usr/java/jdk1.7.0_11
Using CLASSPATH: /usr/local/tomcat/bin/bootstrap.jar:/usr/local/tomcat/bin/tomcat-juli.jar
Tomcat started.

# netstat -tnlp |grep java
tcp 0 0 ::ffff:127.0.0.1:8005 :::* LISTEN 6191/java
tcp 0 0 :::8009 :::* LISTEN 6191/java
tcp 0 0 :::8080 :::* LISTEN 6191/java

# /usr/local/tomcat/bin/shutdown.sh //关闭tomcat

关于tomcat端口:
Tomcat服务器通过Connector连接器组件与客户程序建立连接,Connector组件负责接收客户的请求,以及把Tomcat服务器的响应结果发送给客户。默认情况下,Tomcat在server.xml中配置了两种连接器:
  第一个连接器监听8080端口,负责建立HTTP连接。在通过浏览器访问Tomcat服务器的Web应用时,使用的就是这个连接器。  
  第二个连接器监听8009端口,负责和其他的HTTP服务器建立连接。在把Tomcat与其他HTTP服务器集成时,就需要用到这个连接器。

8005是tomcat本身的端口

3. 测试
http://192.168.1.6:8080/


 

二. Tomcat多实例子部署

多实例运行不同的应用(类似虚拟主机)
多实例运行相同的应用(实现负载均衡,支持高并发处理)

(1) 配置多实例目录

分别在/usr/local/tomcat下创建目录instance1 instance2 instance3,拷贝原来的conf,logs,temp,work到3个目录下

(2) 配置实例server.xml

<Server port="****" 管理实例端口
<Connector port="****" protocol="HTTP/1.1 提供web服务端口
<Connector port="****" protocol="AJP/1.3" 用于前端如Apache通过AJP方式连接tomcat的端口

 

[root@www ~]# vim /usr/local/tomcat/instance1/conf/server.xml

第一个修改点:22 <Server port="8015" shutdown="SHUTDOWN"> 修改为8015,8025,8035.......

第二个修改点:71 <Connector port="8081" protocol="HTTP/1.1" 修改为8081,8082,8083...........
connectionTimeout="20000"
redirectPort="8443" />

第三个修改点:93 <Connector port="8019" protocol="AJP/1.3" redirectPort="8443" /> 修改为8019,8029,8039........

第四个修改点:125 <Host name="localhost" appBase="/webapps1" //修改网站基准目录
unpackWARs="true" autoDeploy="true">

(3). 脚本内容(多实例启动脚本)
[root@www ~]# vim /usr/local/tomcat/instance1/ins1.sh

#!/bin/bash
#instance1
. /etc/init.d/functions
export CATALINA_BASE="/usr/local/tomcat/instance1"

case "$1" in
start)
$CATALINA_HOME/bin/startup.sh
;;
stop)
$CATALINA_HOME/bin/shutdown.sh
;;
restart)
$CATALINA_HOME/bin/shutdown.sh
sleep 3
$CATALINA_HOME/bin/startup.sh
;;
esac

(4). 启动测试
[root@www ~]# /usr/local/tomcat/instance1/ins1.sh start
[root@www ~]# /usr/local/tomcat/instance2/ins2.sh start
[root@www ~]# /usr/local/tomcat/instance3/ins3.sh start

[root@tomcat instance3]# ss -tnlp |grep :80 |column -t
LISTEN  0  1    ::ffff:127.0.0.1:8015  :::*  users:(("java",pid=2940,fd=46))
LISTEN  0  100  :::8080                :::*  users:(("java",pid=2733,fd=42))
LISTEN  0  100  :::8081                :::*  users:(("java",pid=2940,fd=42))
LISTEN  0  100  :::8082                :::*  users:(("java",pid=2905,fd=42))
LISTEN  0  100  :::8083                :::*  users:(("java",pid=2999,fd=42))
LISTEN  0  100  :::8019                :::*  users:(("java",pid=2940,fd=43))
LISTEN  0  1    ::ffff:127.0.0.1:8025  :::*  users:(("java",pid=2905,fd=46))
LISTEN  0  100  :::8029                :::*  users:(("java",pid=2905,fd=43))
LISTEN  0  1    ::ffff:127.0.0.1:8035  :::*  users:(("java",pid=2999,fd=48))
LISTEN  0  1    ::ffff:127.0.0.1:8005  :::*  users:(("java",pid=2733,fd=46))
LISTEN  0  100  :::8039                :::*  users:(("java",pid=2999,fd=43))
LISTEN  0  100  :::8009                :::*  users:(("java",pid=2733,fd=43))
 

三. Tomcat负载均衡:

采用Nginx作为反向代理服务器实现Tomcat负载均衡:

配置Nginx:

1. 停止原有web服务器:
2. 添加普通用户账号来运行nginx:
# useradd -M -s /sbin/nologin nginx
3. 安装依赖,解压并安装Nginx:
#yum -y install zlib zlib-devel openssl openssl-devel pcre pcre-devel gcc gcc-c++ make cmake
# tar xf nginx-1.10.3.tar.gz
# cd nginx-1.10.3
# ./configure --prefix=/usr/local/nginx --user=nginx --group=nginx --with-http_stub_status_module --with-http_ssl_module
# make && make install

4. 启动:

[root@tomcat sbin]# vim /etc/profile
export NGINX_HOME=/usr/local/nginx
export PATH=$NGINX_HOME/sbin:$PATH
[root@tomcat sbin]# source /etc/profile
[root@tomcat sbin]# nginx

5. 测试:

[root@tomcat sbin]# netstat -tanp | grep 80
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 5614/nginx: master

#curl 127.0.0.1

6. 配置负载均衡:

[root@www ~]# vim /usr/local/nginx/conf/nginx.conf
http {
upstream tomcat_pool {                                         //轮询方式
server 192.168.1.6:8081;
server 192.168.1.6:8082;
server 192.168.1.6:8083;
}

server {
location / {
proxy_pass http://tomcat_pool;
proxy_redirect off; 开启代理重定向
proxy_set_header Host $host; 开启使用远程主机
proxy_set_header X-Real-IP $remote_addr; 获取远程主机IP
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 使用代理主机转发地址
}
}
}

在三个tomcat发布目录/webapp1/ROOT/中写入对应IP,curl本地回环后出现轮询的负载均衡效果:

[root@tomcat ROOT]# curl 127.0.0.1
192.168.1.6:8081
[root@tomcat ROOT]# curl 127.0.0.1
192.168.1.6:8082
[root@tomcat ROOT]# curl 127.0.0.1
192.168.1.6:8083
 

四. 优化:

tomcat调优主要从以下三方面着手:
1. 内存优化
2. 并发优化
3. 内核优化


1. JVM内存优化

再讲解JVM内存优化之前,需要大家知道什么是JAVA堆。

首先:Java把内存划分成两种:一种是栈内存,一种是堆内存。

其中Java堆是Java虚拟机所管理的内存中最大的一块。Java堆是指:在JAVA中被所有线程所共享的一块内存区域,在虚拟机启动时创建。
此内存区域的唯一目的就是存储对象实例,几乎所有的对象实例都在这里分配内存。

内存溢出的处理办法(tomcat内存优化):
Tomcat内存优化主要是对 tomcat 启动参数优化.
Tomcat默认使用最大内存为128M,可以修改 tomcat/bin/Catalina.sh 文件增加其内存。(在此文件第一行开始添加新的设置即可)设置 JAVA_OPTS 参数


JAVA_OPTS=”-server -Xms1024m -Xmx1024m -XX:PermSize=128m -XX:MaxPermSize=256m -Djava.awt.headless=true”

-server  以服务端模式启动,启动速度会稍微慢点,但性能会高很多.;  
-Xms    java虚拟机初始化时的初始堆大小;  
-Xmx   java虚拟机可使用的最大堆大小;  
-XX:PermSize     内存永久保留区域  
-XX:MaxPermSize   内存最大永久保留区域(老生代对象能占用内存的最大值)  
java.awt.headless=true 与图形操作有关,适用于Linux系统

注:要加“m”说明是MB,否则就是KB,在启动tomcat时会报内存不足。
注:永久保存区:是指内存的永久保存区域。这一部分用于存放Class(类)和Meta(+类)的信息,Class在被 Load(加载)的时候被放入PermGen space区域(内存永久保存区域),并且不会在主程序运行期对内存永久保存区进行清理,所以如果你的APP会LOAD很多CLASS的话,就很可能出现PermGen space错误。这种错误常见在web服务器对JSP进行pre compile(预编译)的时候。jvm的gc是不会清理PemGen space的,导致内存溢出
==================================================================

常见的内存溢出一般会有下面三种情况:
        1.OutOfMemoryError: Java heap space #堆溢出,若不是程序逻辑bug,可能是项目中引用的jar较多导致
        2.OutOfMemoryError: PermGen space #永久保存区域溢出,通常由于加载了过多的类导致
        3.OutOfMemoryError: unable to create new native thread. #当JVM的heap size(堆空间)设置过大时,thread(线程)的创建数量便会减少
解决:
1.调整-Xms -Xmx参数可以解决第一种情况

64位操作系统对堆内存大小没有限制
堆的大小可以使用 java -Xmx***M  -version 命令来测试,***位置填写想设置的内存大小。支持的话会出现jdk的版本号,不支持会报错。

    -Xms -Xmx一般配置成一样比较好比如set JAVA_OPTS= -Xms1024m -Xmx1024m
   注意:java -Xmx***M  version 命令来测试的最大堆内存是 -Xmx与 -XX:PermSize的和。
   
2.加大-XX:PermSize  -XX:MaxPermSize来解决第二种情况  
3.解决问题3方法如下:
  1).如果程序中有bug,导致创建大量不需要的线程或者线程没有及时回收,那么必须解决这个bug,修改参数是不能解决问题的。
  2).如果程序确实需要大量的线程,现有的设置不能达到要求,那么可以通过修改MaxProcessMemory(内存最大永久保留区),JVMMemory(JVM内存),ThreadStackSize(线程栈大小)这三个因素,来增加能创建的线程数:
如下方式解决:
  a, MaxProcessMemory 使用64位操作系统
  b, JVMMemory   减少JVMMemory的分配  使用tomcat的catalina.sh这里配置,JAVA_OPTS=-Xms1024m -Xmx1024m -XX:PermSize=256M -XX:MaxNewSize=512m-XX:MaxPermSize=256m
  c, ThreadStackSize  减小单个线程的栈大小 

这个异常问题本质原因是:
我们创建了太多的线程,而能创建的线程数是有限制的,导致了异常的发生。
能创建的线程数的具体计算公式如下: 
(MaxProcessMemory - JVMMemory - ReservedOsMemory) / (ThreadStackSize) = Number of threads
一个进程的最大内存——JVm内存——操作系统预留内存)/线程栈大小=线程数
在java语言里, 当你创建一个线程的时候,虚拟机会在JVM内存创建一个Thread(线程)对象同时创建一个操作系统线程,而这个系统线程的内存用的不是JVMMemory,而是系统中剩下的内存(MaxProcessMemory - JVMMemory - ReservedOsMemory)。由公式得出结论:你给JVM内存越多,那么你能创建的线程越少,越容易发生java.lang.OutOfMemoryError: unable to create new native thread。

2. 并发优化
线程池设置:
线程池指定Web请求负载的数量,因此,为获得更好的性能这部分应小心处理。可以通过调整连接器属性“maxThreads”完成设置。maxThreads的值应该根据流量的大小,如果值过低,将有没有足够的线程来处理所有的请求,请求将进入等待状态,只有当一个的处理线程释放后才被处理;如果设置的太大,Tomcat的启动将花费更多时间。因此并发优化好坏取决于我们是否给maxThreads设置了一个正确的值。
#vim server.xml
<Connector port="8080" protocol="HTTP/1.1"
maxThreads="500"
connectionTimeout="20000"
redirectPort="8443" />

在上述配置中,maxThreads值设定为“500”,指定可以由服务器处理的并发请求的最大数量是500。如果没有指定,这个属性的默认值为“200”。任何多出的并发请求将收到“拒绝连接”的错误提示,直到另一个处理请求进程被释放。错误看起来如下,
[ org.apache.tomcat.util.threads.ThreadPool logFull SEVERE: All threads (500) are  currently busy, waiting. Increase maxThreads (500) or check the servlet status  

最好使用“Tomcat集群”的多个实例。也就是说,如果有“1000”请求,两个Tomcat实例设置“maxThreads= 500”,而不在单Tomcat实例的情况下设置maxThreads=1000。

-----------------------------
<Connector port="9027"      
                protocol="HTTP/1.1"     
                maxHttpHeaderSize="8192"     
 maxThreads="1000"      客户请求最大线程数
                minSpareThreads="100"      Tomcat初始化时创建的 socket 线程数
                maxSpareThreads="1000"   Tomcat连接器的最大空闲 socket 线程数   
                minProcessors="100"     服务器创建时的最小处理线程数
                maxProcessors="1000"    服务器同时最大处理线程数
                enableLookups="false"      若设为true, 则支持域名解析,可把 ip 地址解析为主机名
                URIEncoding="utf-8"     URL统一编码
                acceptCount="1000"      监听端口队列最大数,满了之后客户请求会被拒绝(不能小于maxSpareThreads  )
                redirectPort="8443"      在需要基于安全通道的场合,把客户请求转发到基于SSL 的 redirectPort 端口
                disableUploadTimeout="true"/> 

3. 内核优化
Tomcat运行过程中可能会出现大量ESTABLISHED(已建立的)连接与Time_Wait(等待)连接
# netstat -n | awk '/^tcp/ {++y[$NF]} END {for(w in y) print w, y[w]}'
CLOSE_WAIT 348 已关闭的等待链接
ESTABLISHED 1240 已建立的链接
TIME_WAIT 5621 等待连接,也是监控web与tomcat之间的链接端口
#netstat -n | grep 8009 | wc -l
7198
1、怎样解决time_wait过多的问题:
通过调整内核参数:
# vim /etc/sysctl.conf #编辑文件,加入以下内容:
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_fin_timeout = 30
# /sbin/sysctl -p #让参数生效。
配置说明:
net.ipv4.tcp_syncookies = 1 表示开启SYN Cookies。当出现SYN等待队列溢出时,启用cookies来处理,可防范少量SYN攻击,默认为0,表示关闭;
net.ipv4.tcp_tw_reuse = 1    表示开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接,默认为0,表示关闭;
net.ipv4.tcp_tw_recycle = 1  表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭;
net.ipv4.tcp_fin_timeout=30修改系統默认的 TIMEOUT 时间。

如果以上配置调优后性能还不理想,可继续修改一下配置:
# vi /etc/sysctl.conf
net.ipv4.tcp_keepalive_time = 1200
#表示当keepalive起用的时候,TCP发送keepalive消息的频度。缺省是2小时,改为20分钟。keepalive,是在TCP中一个可以检测死连接的机制。
net.ipv4.ip_local_port_range = 1024 65000
#表示用于向外连接的端口范围。缺省情况下很小:32768到61000,可以改为1024到65000。
net.ipv4.tcp_max_syn_backlog = 8192
#表示SYN队列的长度,默认为1024,加大队列长度为8192,可以容纳更多等待连接的网络连接数。
net.ipv4.tcp_max_tw_buckets = 5000
#表示系统同时保持TIME_WAIT套接字的最大数量,如果超过这个数字,TIME_WAIT套接字将立刻被清除并打印警告信息。
默认为180000,改为5000。对于Apache、Nginx等服务器,上几行的参数可以很好地减少TIME_WAIT套接字数量,但是对于 Squid,效果却不大。此项参数可以控制TIME_WAIT套接字的最大数量,避免Squid服务器被大量的TIME_WAIT套接字拖死。
调优完毕,再压一下看看效果:
# netstat -n | awk '/^tcp/ {++y[$NF]} END {for(w in y) print w, y[w]}'
ESTABLISHED 968


2、怎么解决请求结束后依然存在大量ESTABLISHED没有被释放
初步推断是tomcat服务器回收session时出了问题,这个一般都跟服务器的Timeout设置有联系。
查看tomcat的配置文件 server.xml
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" URIEncoding="UTF-8"/>
*****检查配置得出链接的超时时间为20000毫秒的时候acceptCount(承受链接数统计)=”100” ,明显不合理,连接数也太小了。
所以进一步优化:
connectionTimeout="20000" 改为 connectionTimeout="100"
acceptCount="100"改为acceptCount="5000"

 
————————————————
版权声明:本文为CSDN博主「WUYANGEZRA」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/ezra1991/article/details/88605169

---恢复内容结束---


本文链接:https://blog.csdn.net/Ezra1991/article/details/88605169

Tomcat 服务器是一个免费的开放源代码的Web 应用服务器,属于轻量级应用服务器,在中小型系统和并发访问用户不是很多的场合下被普遍使用,是开发和调试JSP 程序的首选。对于一个初学者来说,可以这样认为,当在一台机器上配置好Apache 服务器,可利用它响应HTML(标准通用标记语言下的一个应用)页面的访问请求。实际上Tomcat是Apache 服务器的扩展,但运行时它是独立运行的,所以当你运行tomcat 时,它实际上作为一个与Apache 独立的进程单独运行的。

Tomcat的拓扑方案:

方案一: Tomcat
方案二: Nginx+Tomcat
方案三:
Nginx
|
+----------------------------------------------+
| | | |
Tomcat1 Tomcat2 Tomcat3 nginx

一、Tomcat Http Server


1. 部署JAVA环境
# tar xf jdk-8u91-linux-x64.tar.gz -C /usr/local
# ln -s /usr/local/jdk1.8.0_91 /usr/local/java

# vim /etc/profile.d/jdk.sh
JAVA_HOME=/usr/local/java
PATH=$JAVA_HOME/bin:$PATH
export JAVA_HOME PATH

# source /etc/profile.d/jdk.sh
# env |grep JAVA
JAVA_HOME=/usr/local/java
# java -version
java version "1.8.0_91"
Java(TM) SE Runtime Environment (build 1.8.0_91-b14)
Java HotSpot(TM) 64-Bit Server VM (build 25.91-b14, mixed mode)

2. 安装Tomcat:
# tar xf apache-tomcat-7.0.34.tar.gz -C /usr/local/
# ln -s /usr/local/apache-tomcat-7.0.34 /usr/local/tomcat

定义Tomcat所需环境变量:
# vim /etc/profile.d/jdk.sh //定义Tomcat环境变量
CATALINA_HOME=/usr/local/tomcat //Tomcat安装目录
PATH=$CATALINA_HOME/bin:$PATH
export CATALINA_HOME PATH
# source /etc/profile.d/jdk.sh

启动Tomcat
# /usr/local/tomcat/bin/startup.sh //启动tomcat
Using CATALINA_BASE: /usr/local/tomcat
Using CATALINA_HOME: /usr/local/tomcat
Using CATALINA_TMPDIR: /usr/local/tomcat/temp
Using JRE_HOME: /usr/java/jdk1.7.0_11
Using CLASSPATH: /usr/local/tomcat/bin/bootstrap.jar:/usr/local/tomcat/bin/tomcat-juli.jar
Tomcat started.

# netstat -tnlp |grep java
tcp 0 0 ::ffff:127.0.0.1:8005 :::* LISTEN 6191/java
tcp 0 0 :::8009 :::* LISTEN 6191/java
tcp 0 0 :::8080 :::* LISTEN 6191/java

# /usr/local/tomcat/bin/shutdown.sh //关闭tomcat

关于tomcat端口:
Tomcat服务器通过Connector连接器组件与客户程序建立连接,Connector组件负责接收客户的请求,以及把Tomcat服务器的响应结果发送给客户。默认情况下,Tomcat在server.xml中配置了两种连接器:
  第一个连接器监听8080端口,负责建立HTTP连接。在通过浏览器访问Tomcat服务器的Web应用时,使用的就是这个连接器。  
  第二个连接器监听8009端口,负责和其他的HTTP服务器建立连接。在把Tomcat与其他HTTP服务器集成时,就需要用到这个连接器。

8005是tomcat本身的端口

3. 测试
http://192.168.1.6:8080/


 

二. Tomcat多实例子部署

多实例运行不同的应用(类似虚拟主机)
多实例运行相同的应用(实现负载均衡,支持高并发处理)

(1) 配置多实例目录

分别在/usr/local/tomcat下创建目录instance1 instance2 instance3,拷贝原来的conf,logs,temp,work到3个目录下

(2) 配置实例server.xml

<Server port="****" 管理实例端口
<Connector port="****" protocol="HTTP/1.1 提供web服务端口
<Connector port="****" protocol="AJP/1.3" 用于前端如Apache通过AJP方式连接tomcat的端口

 

[root@www ~]# vim /usr/local/tomcat/instance1/conf/server.xml

第一个修改点:22 <Server port="8015" shutdown="SHUTDOWN"> 修改为8015,8025,8035.......

第二个修改点:71 <Connector port="8081" protocol="HTTP/1.1" 修改为8081,8082,8083...........
connectionTimeout="20000"
redirectPort="8443" />

第三个修改点:93 <Connector port="8019" protocol="AJP/1.3" redirectPort="8443" /> 修改为8019,8029,8039........

第四个修改点:125 <Host name="localhost" appBase="/webapps1" //修改网站基准目录
unpackWARs="true" autoDeploy="true">

(3). 脚本内容(多实例启动脚本)
[root@www ~]# vim /usr/local/tomcat/instance1/ins1.sh

#!/bin/bash
#instance1
. /etc/init.d/functions
export CATALINA_BASE="/usr/local/tomcat/instance1"

case "$1" in
start)
$CATALINA_HOME/bin/startup.sh
;;
stop)
$CATALINA_HOME/bin/shutdown.sh
;;
restart)
$CATALINA_HOME/bin/shutdown.sh
sleep 3
$CATALINA_HOME/bin/startup.sh
;;
esac

(4). 启动测试
[root@www ~]# /usr/local/tomcat/instance1/ins1.sh start
[root@www ~]# /usr/local/tomcat/instance2/ins2.sh start
[root@www ~]# /usr/local/tomcat/instance3/ins3.sh start

[root@tomcat instance3]# ss -tnlp |grep :80 |column -t
LISTEN  0  1    ::ffff:127.0.0.1:8015  :::*  users:(("java",pid=2940,fd=46))
LISTEN  0  100  :::8080                :::*  users:(("java",pid=2733,fd=42))
LISTEN  0  100  :::8081                :::*  users:(("java",pid=2940,fd=42))
LISTEN  0  100  :::8082                :::*  users:(("java",pid=2905,fd=42))
LISTEN  0  100  :::8083                :::*  users:(("java",pid=2999,fd=42))
LISTEN  0  100  :::8019                :::*  users:(("java",pid=2940,fd=43))
LISTEN  0  1    ::ffff:127.0.0.1:8025  :::*  users:(("java",pid=2905,fd=46))
LISTEN  0  100  :::8029                :::*  users:(("java",pid=2905,fd=43))
LISTEN  0  1    ::ffff:127.0.0.1:8035  :::*  users:(("java",pid=2999,fd=48))
LISTEN  0  1    ::ffff:127.0.0.1:8005  :::*  users:(("java",pid=2733,fd=46))
LISTEN  0  100  :::8039                :::*  users:(("java",pid=2999,fd=43))
LISTEN  0  100  :::8009                :::*  users:(("java",pid=2733,fd=43))
 

三. Tomcat负载均衡:

采用Nginx作为反向代理服务器实现Tomcat负载均衡:

配置Nginx:

1. 停止原有web服务器:
2. 添加普通用户账号来运行nginx:
# useradd -M -s /sbin/nologin nginx
3. 安装依赖,解压并安装Nginx:
#yum -y install zlib zlib-devel openssl openssl-devel pcre pcre-devel gcc gcc-c++ make cmake
# tar xf nginx-1.10.3.tar.gz
# cd nginx-1.10.3
# ./configure --prefix=/usr/local/nginx --user=nginx --group=nginx --with-http_stub_status_module --with-http_ssl_module
# make && make install

4. 启动:

[root@tomcat sbin]# vim /etc/profile
export NGINX_HOME=/usr/local/nginx
export PATH=$NGINX_HOME/sbin:$PATH
[root@tomcat sbin]# source /etc/profile
[root@tomcat sbin]# nginx

5. 测试:

[root@tomcat sbin]# netstat -tanp | grep 80
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 5614/nginx: master

#curl 127.0.0.1

6. 配置负载均衡:

[root@www ~]# vim /usr/local/nginx/conf/nginx.conf
http {
upstream tomcat_pool {                                         //轮询方式
server 192.168.1.6:8081;
server 192.168.1.6:8082;
server 192.168.1.6:8083;
}

server {
location / {
proxy_pass http://tomcat_pool;
proxy_redirect off; 开启代理重定向
proxy_set_header Host $host; 开启使用远程主机
proxy_set_header X-Real-IP $remote_addr; 获取远程主机IP
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 使用代理主机转发地址
}
}
}

在三个tomcat发布目录/webapp1/ROOT/中写入对应IP,curl本地回环后出现轮询的负载均衡效果:

[root@tomcat ROOT]# curl 127.0.0.1
192.168.1.6:8081
[root@tomcat ROOT]# curl 127.0.0.1
192.168.1.6:8082
[root@tomcat ROOT]# curl 127.0.0.1
192.168.1.6:8083
 

四. 优化:

tomcat调优主要从以下三方面着手:
1. 内存优化
2. 并发优化
3. 内核优化


1. JVM内存优化

再讲解JVM内存优化之前,需要大家知道什么是JAVA堆。

首先:Java把内存划分成两种:一种是栈内存,一种是堆内存。

其中Java堆是Java虚拟机所管理的内存中最大的一块。Java堆是指:在JAVA中被所有线程所共享的一块内存区域,在虚拟机启动时创建。
此内存区域的唯一目的就是存储对象实例,几乎所有的对象实例都在这里分配内存。

内存溢出的处理办法(tomcat内存优化):
Tomcat内存优化主要是对 tomcat 启动参数优化.
Tomcat默认使用最大内存为128M,可以修改 tomcat/bin/Catalina.sh 文件增加其内存。(在此文件第一行开始添加新的设置即可)设置 JAVA_OPTS 参数


JAVA_OPTS=”-server -Xms1024m -Xmx1024m -XX:PermSize=128m -XX:MaxPermSize=256m -Djava.awt.headless=true”

-server  以服务端模式启动,启动速度会稍微慢点,但性能会高很多.;  
-Xms    java虚拟机初始化时的初始堆大小;  
-Xmx   java虚拟机可使用的最大堆大小;  
-XX:PermSize     内存永久保留区域  
-XX:MaxPermSize   内存最大永久保留区域(老生代对象能占用内存的最大值)  
java.awt.headless=true 与图形操作有关,适用于Linux系统

注:要加“m”说明是MB,否则就是KB,在启动tomcat时会报内存不足。
注:永久保存区:是指内存的永久保存区域。这一部分用于存放Class(类)和Meta(+类)的信息,Class在被 Load(加载)的时候被放入PermGen space区域(内存永久保存区域),并且不会在主程序运行期对内存永久保存区进行清理,所以如果你的APP会LOAD很多CLASS的话,就很可能出现PermGen space错误。这种错误常见在web服务器对JSP进行pre compile(预编译)的时候。jvm的gc是不会清理PemGen space的,导致内存溢出
==================================================================

常见的内存溢出一般会有下面三种情况:
        1.OutOfMemoryError: Java heap space #堆溢出,若不是程序逻辑bug,可能是项目中引用的jar较多导致
        2.OutOfMemoryError: PermGen space #永久保存区域溢出,通常由于加载了过多的类导致
        3.OutOfMemoryError: unable to create new native thread. #当JVM的heap size(堆空间)设置过大时,thread(线程)的创建数量便会减少
解决:
1.调整-Xms -Xmx参数可以解决第一种情况

64位操作系统对堆内存大小没有限制
堆的大小可以使用 java -Xmx***M  -version 命令来测试,***位置填写想设置的内存大小。支持的话会出现jdk的版本号,不支持会报错。

    -Xms -Xmx一般配置成一样比较好比如set JAVA_OPTS= -Xms1024m -Xmx1024m
   注意:java -Xmx***M  version 命令来测试的最大堆内存是 -Xmx与 -XX:PermSize的和。
   
2.加大-XX:PermSize  -XX:MaxPermSize来解决第二种情况  
3.解决问题3方法如下:
  1).如果程序中有bug,导致创建大量不需要的线程或者线程没有及时回收,那么必须解决这个bug,修改参数是不能解决问题的。
  2).如果程序确实需要大量的线程,现有的设置不能达到要求,那么可以通过修改MaxProcessMemory(内存最大永久保留区),JVMMemory(JVM内存),ThreadStackSize(线程栈大小)这三个因素,来增加能创建的线程数:
如下方式解决:
  a, MaxProcessMemory 使用64位操作系统
  b, JVMMemory   减少JVMMemory的分配  使用tomcat的catalina.sh这里配置,JAVA_OPTS=-Xms1024m -Xmx1024m -XX:PermSize=256M -XX:MaxNewSize=512m-XX:MaxPermSize=256m
  c, ThreadStackSize  减小单个线程的栈大小 

这个异常问题本质原因是:
我们创建了太多的线程,而能创建的线程数是有限制的,导致了异常的发生。
能创建的线程数的具体计算公式如下: 
(MaxProcessMemory - JVMMemory - ReservedOsMemory) / (ThreadStackSize) = Number of threads
一个进程的最大内存——JVm内存——操作系统预留内存)/线程栈大小=线程数
在java语言里, 当你创建一个线程的时候,虚拟机会在JVM内存创建一个Thread(线程)对象同时创建一个操作系统线程,而这个系统线程的内存用的不是JVMMemory,而是系统中剩下的内存(MaxProcessMemory - JVMMemory - ReservedOsMemory)。由公式得出结论:你给JVM内存越多,那么你能创建的线程越少,越容易发生java.lang.OutOfMemoryError: unable to create new native thread。

2. 并发优化
线程池设置:
线程池指定Web请求负载的数量,因此,为获得更好的性能这部分应小心处理。可以通过调整连接器属性“maxThreads”完成设置。maxThreads的值应该根据流量的大小,如果值过低,将有没有足够的线程来处理所有的请求,请求将进入等待状态,只有当一个的处理线程释放后才被处理;如果设置的太大,Tomcat的启动将花费更多时间。因此并发优化好坏取决于我们是否给maxThreads设置了一个正确的值。
#vim server.xml
<Connector port="8080" protocol="HTTP/1.1"
maxThreads="500"
connectionTimeout="20000"
redirectPort="8443" />

在上述配置中,maxThreads值设定为“500”,指定可以由服务器处理的并发请求的最大数量是500。如果没有指定,这个属性的默认值为“200”。任何多出的并发请求将收到“拒绝连接”的错误提示,直到另一个处理请求进程被释放。错误看起来如下,
[ org.apache.tomcat.util.threads.ThreadPool logFull SEVERE: All threads (500) are  currently busy, waiting. Increase maxThreads (500) or check the servlet status  

最好使用“Tomcat集群”的多个实例。也就是说,如果有“1000”请求,两个Tomcat实例设置“maxThreads= 500”,而不在单Tomcat实例的情况下设置maxThreads=1000。

-----------------------------
<Connector port="9027"      
                protocol="HTTP/1.1"     
                maxHttpHeaderSize="8192"     
 maxThreads="1000"      客户请求最大线程数
                minSpareThreads="100"      Tomcat初始化时创建的 socket 线程数
                maxSpareThreads="1000"   Tomcat连接器的最大空闲 socket 线程数   
                minProcessors="100"     服务器创建时的最小处理线程数
                maxProcessors="1000"    服务器同时最大处理线程数
                enableLookups="false"      若设为true, 则支持域名解析,可把 ip 地址解析为主机名
                URIEncoding="utf-8"     URL统一编码
                acceptCount="1000"      监听端口队列最大数,满了之后客户请求会被拒绝(不能小于maxSpareThreads  )
                redirectPort="8443"      在需要基于安全通道的场合,把客户请求转发到基于SSL 的 redirectPort 端口
                disableUploadTimeout="true"/> 

3. 内核优化
Tomcat运行过程中可能会出现大量ESTABLISHED(已建立的)连接与Time_Wait(等待)连接
# netstat -n | awk '/^tcp/ {++y[$NF]} END {for(w in y) print w, y[w]}'
CLOSE_WAIT 348 已关闭的等待链接
ESTABLISHED 1240 已建立的链接
TIME_WAIT 5621 等待连接,也是监控web与tomcat之间的链接端口
#netstat -n | grep 8009 | wc -l
7198
1、怎样解决time_wait过多的问题:
通过调整内核参数:
# vim /etc/sysctl.conf #编辑文件,加入以下内容:
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_fin_timeout = 30
# /sbin/sysctl -p #让参数生效。
配置说明:
net.ipv4.tcp_syncookies = 1 表示开启SYN Cookies。当出现SYN等待队列溢出时,启用cookies来处理,可防范少量SYN攻击,默认为0,表示关闭;
net.ipv4.tcp_tw_reuse = 1    表示开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接,默认为0,表示关闭;
net.ipv4.tcp_tw_recycle = 1  表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭;
net.ipv4.tcp_fin_timeout=30修改系統默认的 TIMEOUT 时间。

如果以上配置调优后性能还不理想,可继续修改一下配置:
# vi /etc/sysctl.conf
net.ipv4.tcp_keepalive_time = 1200
#表示当keepalive起用的时候,TCP发送keepalive消息的频度。缺省是2小时,改为20分钟。keepalive,是在TCP中一个可以检测死连接的机制。
net.ipv4.ip_local_port_range = 1024 65000
#表示用于向外连接的端口范围。缺省情况下很小:32768到61000,可以改为1024到65000。
net.ipv4.tcp_max_syn_backlog = 8192
#表示SYN队列的长度,默认为1024,加大队列长度为8192,可以容纳更多等待连接的网络连接数。
net.ipv4.tcp_max_tw_buckets = 5000
#表示系统同时保持TIME_WAIT套接字的最大数量,如果超过这个数字,TIME_WAIT套接字将立刻被清除并打印警告信息。
默认为180000,改为5000。对于Apache、Nginx等服务器,上几行的参数可以很好地减少TIME_WAIT套接字数量,但是对于 Squid,效果却不大。此项参数可以控制TIME_WAIT套接字的最大数量,避免Squid服务器被大量的TIME_WAIT套接字拖死。
调优完毕,再压一下看看效果:
# netstat -n | awk '/^tcp/ {++y[$NF]} END {for(w in y) print w, y[w]}'
ESTABLISHED 968


2、怎么解决请求结束后依然存在大量ESTABLISHED没有被释放
初步推断是tomcat服务器回收session时出了问题,这个一般都跟服务器的Timeout设置有联系。
查看tomcat的配置文件 server.xml
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" URIEncoding="UTF-8"/>
*****检查配置得出链接的超时时间为20000毫秒的时候acceptCount(承受链接数统计)=”100” ,明显不合理,连接数也太小了。
所以进一步优化:
connectionTimeout="20000" 改为 connectionTimeout="100"
acceptCount="100"改为acceptCount="5000"

 

posted @ 2019-09-26 12:04  懒懒的妞  阅读(358)  评论(0编辑  收藏  举报