Tomcat部署及优化

607 阅读9分钟

1. Tomcat介绍

Tomcat是Java语言开发的,Tomcat服务器是一个免费的开放源代码的Web应用服务器,是Apache软件基金会的Jakarta项目中的一个核心项目,由Apache、Sun和其他一些公司及个人共同开发而成。

Tomcat属于轻量级应用服务器,在中小型系统和并发访问用户不是很多的场合下被普遍使用,是开发和调试JSP程序的首选。一般来说,Tomcat虽然和Apache 或者Nginx这些Web服务器一样,具有处理HTML 页面的功能,然而由于其处理静态HTML的能力远不及Apache 或者Nginx, 所以Tomcat通常是作为一个Servlet和JSP容器,单独运行在后端。

1.1 Tomcat的组成

  • Tomcat 由一系列的组件构成,其中核心的组件有三个
  1. Web容器:完成Web服务器的功能。
  2. Servlet容器:名字为catalina, 用于处理Servlet 代码。
  3. JSP容器:用于将JSP动态网页翻译成Servlet代码。

因此Tomcat是Web应用服务器,也是一个Servlet/JSP 容器。Tomcat 作为Servlet 容器,负责处理客户请求,把请求传送给Servlet, 并将Servlet的响应传送回给客户。

1.2 什么是servlet?

Servlet是Java Servlet的简称,可以理解为是一 个服务连接器,是用Java编写的服务器端程序,具有独立于平台和协议的特性, 简单的理解: servlet就是一个中间件,包含了接口和方法,将客户端和数据库连接,从而实现动态网页的创建。

1.3 什么是JSP?

  1. JSP全称Java Server Pages, 是一种动态网页开发技术。它使用JSP标签在HTML网页中插入Java代码。标签通常以<%开头,以%>结束
  2. JSP是一种Java servlet, 主要用于实现Java web应用程序的用户界面部分。
  3. JsP通过网页表单获取用户输入数据、访问数据库及其他数据源,然后动态地创建网页。

1.4 Tomcat功能组件结构

Tomcat的核心功能有两个,分别是负责接收和反馈外部请求的连接器Connector,和负责处理请求的容器Container。其中连接器和容器相辅相成,起构成了基本的web服务Service。 每个Tomcat 服务器可以管理多个Service。

image.png

  • Connector:负责对外接收和响应请求。它是Tomcat与外界的交通枢纽,监听端口接收外界请求,并将请求处理后传递给容器做业务处理,最后将容器处理后的结果响应给外
  • Container:负责对内处理业务逻辑。其内部由Engine、Host、Context和Wrapper四个容器组成,用于管理和调用Servlet 相关逻辑。
  • Service: 对外提供的Web服务。主要包含Connector 和Container 两个核心组件,以及其他功能组件。Tomcat 可以管理多个Service, 且各Service之间相互独立。

1.4.1 Container 结构分析

每个service会包含一个Container 容器。在Container 内部包含了4个子容器

  • 4个子容器的作用分别是
  1. Engine:引擎,用来管理多个虚拟主机,一个Service最多只能有一个Engine;
  2. Host:代表一个虚拟主机,也可以叫站点,通过配置Host就可以添加站点;
  3. Context: 代表一个Web应用,包含多个Servlet 封装器;
  4. Wrapper: 封装器,容器的最底层。每一wrapper 封装着一个Servlet, 负责对象实例的创建、执行和销毁功能。

Engine、Host、 Context 和wrapper, 这四个容器之间属于父子关系

容器由一个引擎可以管理多个虚拟主机。每个虚拟主机可以管理多个web应用。每个Web应用会有多个Servlet 封装器。

1.5 Tomcat请求过程

  1. 用户在浏览器中输入网址,请求被发送到本机端口8080, 被在那里监听的Connector 获得;
  2. Connector 把该请求交给它所在的Service 的Engine (Container) 来处理,并等待Engine 的回应;
  3. 请求在Engine、 Host、 Context 和Wrapper 这四个容器之间层层调用,最后在Servlet 中执行对应的业务逻辑、数据存储等。
  4. 执行完之后的请求响应在Context、 Host、Engine 容器之间层层返回,最后返回给Connector, 并通过Connector 返回给客户端。

2. 部署Tomcat

在部署Tomcat之前必须安装好jdk,因为jdk是Tomcat运行的必要环境。

2.1 关闭防火墙,将安装Tomcat 所需软件包传到/opt目录下

jdk-8u201-linux-x64.rpm

apache-tomcat-9.0.16.tar.gz

[root@www ~]# systemctl stop firewalld
[root@www ~]# systemctl disable firewalld
[root@www ~]# setenforce 0

2.2 安装JDK

[root@www ~]# cd /opt
[root@www ~]# rpm -qpl jdk-8u201-linux-x64.rpm 
[root@www ~]# rpm -ivh jdk-8u201-linux-x64.rpm 
[root@www ~]# java -version

2.3 设置JDK环境变量

[root@www ~]# vim /etc/profile.d/java.sh
export JAVA_HOME=/usr/java/jdk1.8.0_201-amd64
export JRE_HOME=$JAVA_HOME/jre
export CLASSPATH=.:$JAVA_HOME/lib:$JRE_HOME/lib
export PATH=$JAVA_HOME/bin:$JRE_HOME/bin:$PATH
[root@www ~]# source /etc/profile.d/java.sh
[root@www ~]# java -version
  • 小知识

CLASSPATH:编译、运行Java程序时,JRE会去该变量指定的路径中搜索所需的类(.class)文件。

JDK :java development kit (java开发工具)

JRE :java runtime environment (java运行时环境)

JVM :java virtuak machine (java虚拟机),使java程序可以在多种平台上运行class文件。

首先使用文本工具编写java源代码,比如 Hello.java ; 在命令行中,输入命令:javac Hello.java,对源代码进行编译,生成 class 字节码文件;

编译完成后,如果没有报错信息,输入命令:java Hello,运行 class 字节码文件,由 JVM 对字节码进行解释和运行,打印 “Hello World”。

[root@www ~]# vim Hello.java
#类名、接口名命令:英文大小写字母、数字字符、$和_,不能使用关键字和数字开头;
#一个单词命名时第一个单词的首字母要大写;多单词组成时,所有单词的首字母大写:XxxYyyZzz(大驼峰命名法)
public class Hello {			
  public static void main(String[] args){
    System.out.println("Hello world!");
  }
}
[root@www ~]# javac Hello.java
[root@www ~]# java Hello

2.4 安装启动Tomcat

[root@www ~]# cd /opt
[root@www ~]# tar zxvf apache-tomcat-9.0.16.tar.gz
[root@www ~]# mv apache-tomcat-9.0.16 /usr/local/tomcat

2.4.1 启动tomcat

  • 后台启动
[root@www ~]# /usr/local/tomcat/bin/startup.sh 
或
[root@www ~]# /usr/local/tomcat/bin/catalina.sh start	
  • 前台启动
[root@www ~]# /usr/local/tomcat/bin/catalina.sh run	
[root@www ~]# netstat -natp | grep 8080

浏览器访问Tomcat的默认主页 http://192.168.200.100:8080

image.png

2.5 优化tomcat启动速度

第一次启动tomcat可能会发现 Tomcat 启动很慢,默认情况下可能会需要几十秒,可以修改jdk参数进行改。

[root@www ~]# vim /usr/java/jdk1.8.0_201-amd64/jre/lib/security/java.security
##--117行--修改
securerandom.source=file:/dev/urandom
  1. tomcat启动慢的原因是随机数产生遭到阻塞,遭到阻塞的原因是 熵池大小 。
  2. /dev/random:阻塞型,读取它就会产生随机数据,但该数据取决于熵池噪声,当熵池空了,对/dev/random 的读操作也将会被阻塞。
  3. /dev/urandom:非阻塞的随机数产生器,它会重复使用熵池中的数据以产生伪随机数据。这表示对/dev/urandom的读取操作不会产生阻塞,但其输出的熵可能小于/dev/random的。它可以作为生成较低强度密码的伪随机数生成器,不建议用于生成高强度长期密码。
  4. Linux内核采用熵来描述数据的随机性。熵(entropy)是描述系统混乱无序程度的物理量,一个系统的熵越大则说明该系统的有序性越差,即不确定性越大。在信息学中,熵被用来表征一个符号或系统的不确定性,熵越大,表明系统所含有用信息量越少,不确定度越大。计算机本身是可预测的系统,因此,用计算机算法不可能产生真正的随机数。但是机器的环境中充满了各种各样的噪声,如硬件设备发生中断的时间,用户点击鼠标的时间间隔等是完全随机的,事先无法预测。Linux内核实现的随机数产生器正是利用系统中的这些随机噪声来产生高质量随机数序列。内核维护了一个熵池用来收集来自设备驱动程序和其它来源的环境噪音。理论上,熵池中的数据是完全随机的,可以实现产生真随机数序列。为跟踪熵池中数据的随机性,内核在将数据加入池的时候将估算数据的随机性,这个过程称作熵估算。熵估算值描述池中包含的随机数位数,其值越大表示池中数据的随机性越好。
[root@www ~]# /usr/local/tomcat/bin/shutdown.sh 
/usr/local/tomcat/bin/startup.sh 
[root@www ~]# ll /usr/local/tomcat/
  • 主要目录说明

image.png

bin存放启动和关闭Tomcat的脚本文件,如catalina.sh、startup.sh、shutdown.sh

conf存放 Tomcat 服务器的各种配置文件,如主配置文件 server.xml 和 应用默认的部署描述文件 web.xml

lib存放 Tomcat运行需要的库文件的jar包,一般不作任何改动

logs存放 Tomcat 执行时的日志

temp存放 Tomcat 运行时产生的文件

webapps存放Tomcat 默认的 Web 应用项目资源的目录

work:Tomcat 的工作目录,存放 Web 应用代码生成和编译文件


3. Tomcat 虚拟主机配置

很多时候公司会有多个项目需要运行,一般不会是在一台服务器上运行多个 Tomcat 服务,这样会消耗太多的系统资源。此时, 就需要使用到 Tomcat 虚拟主机。

例如现在新增两个域名 www.can.comwww.benet.com, 希望通过这两个域名访问到不同的项目内容。

3.1 创建 can 和 benet 项目目录和文件

[root@www ~]# mkdir /usr/local/tomcat/webapps/can
[root@www ~]# mkdir /usr/local/tomcat/webapps/benet
[root@www ~]# echo "This is can page\!" > /usr/local/tomcat/webapps/can/index.jsp
[root@www ~]# echo "This is benet page\!" > /usr/local/tomcat/webapps/benet/index.jsp

3.2 修改 Tomcat 主配置文件server.xml

[root@www ~]# vim /usr/local/tomcat/conf/server.xml
##--165行前--插入
<Host name="www.can.com" appBase="webapps" unpackWARs="true" autoDeploy="true" xmlValidation="false" xmlNamespaceAware="false">
	<Context docBase="/usr/local/tomcat/webapps/can" path="" reloadable="true" />
</Host>
<Host name="www.benet.com" appBase="webapps" unpackWARs="true" autoDeploy="true" xmlValidation="false" xmlNamespaceAware="false">
	<Context docBase="/usr/local/tomcat/webapps/benet" path="" reloadable="true" />
</Host>
  • Host

name:主机名

appBase:Tomcat程序工作目录,即存放web应用程序的目录;相对路径为webapps,绝对路径为/usr/local/tomcat/webapps

unpackWARs:在启用此webapps时是否对WAR格式的归档文件先进行展开;默认为true

autoDeploy:在Tomcat处于运行状态时放置于appBase目录中的应用程序文件是否自动进行deploy;默认为true

xmlValidation:是否验证xml文件执行有效性检验的标志

xmlNamespaceAware:是否启用xml命名空间,设置该值与 xmlValidation为true,表示对web.xml文件执行有效性检验

  • Context

docBase:相应的Web应用程序的存放位置;也可以使用相对路径,起始路径为此Context所属Host中appBase定义的路径;

path:相对于Web服务器根路径而言的URI;如果为空"",则表示为此webapp的根路径 / ;

reloadable:是否允许重新加载此context相关的Web应用程序的类;默认为false

[root@www ~]# /usr/local/tomcat/bin/shutdown.sh
[root@www ~]# /usr/local/tomcat/bin/startup.sh

3.3 客户端浏览器访问验证

[root@www ~]# echo "192.168.200.100 www.can.com www.benet.com" >> /etc/hosts

浏览器访问 www.can.com:8080/ 页面显示This is can page!

image.png

浏览器访问 www.benet.com:8080/ 页面显示This is benet page!

image.png

3.4 HTTP 请求过程

  • Connector 连接器监听的端口是 8080。由于请求的端口和监听的端口一致,连接器接受了该请求。
  • 因为引擎的默认虚拟主机是 www.can.com ,并且虚拟主机的目录是webapps。所以请求找到了 tomcat/webapps 目录。
  • 访问的路径为根路径,URI 为空,即空是 Web 程序的应用名,也就是 context。此时请求找到 /usr/local/tomcat/webapps/can 目录,解析 index.jsp 并返回。

4. Tomcat 优化

Tomcat默认安装下的缺省配置并不适合生产环境,它可能会频繁出现假死现象需要重启,只有通过不断压测优化才能让它最高效率稳定的运行。优化主要包括三方面,分别为操作系统优化(内核参数优化),Tomcat配置文件参数优化,Java虚拟机(JVM)调优。

4.1 Tomcat 配置文件参数优化

4.1.1 常用的优化相关参数如下

redirectPort: 如果某连接器支持的协议是HTTP,当接收客户端发来的HTTPS请求时,则转发至此属性定义的 8443 端口。

maxThreads: Tomcat使用线程来处理接收的每个请求,这个值表示Tomcat可创建的最大的线程数,即支持的最大并发连接数,默认值是 200。

minSpareThreads: 最小空闲线程数,Tomcat 启动时的初始化的线程数,表示即使没有人使用也开这么多空线程等待,默认值是 10。

maxSpareThreads: 最大备用线程数,一旦创建的线程超过这个值,Tomcat就会关闭不再需要的socket线程。默认值是-1(无限制)。一般不需要指定。

processorCache: 进程缓冲器,可以提升并发请求。默认值是200,如果不做限制的话可以设置为-1,一般采用maxThreads的值或者-1。

URIEncoding: 指定 Tomcat 容器的 URL 编码格式,网站一般采用UTF-8作为默认编码。

connnectionTimeout: 网络连接超时,单位:毫秒,设置为 0 表示永不超时,这样设置有隐患的。通常默认 20000 毫秒就可以。

enableLookups: 是否反查域名,以返回远程主机的主机名,取值为:true 或 false,如果设置为 false,则直接返回 IP 地址,为了提高处理能力,应设置为 false。

disableUploadTimeout: 上传时是否使用超时机制。应设置为 true。

connectionUploadTimeout: 上传超时时间,毕竟文件上传可能需要消耗更多的时间,这个根据你自己的业务需要自己调,以使Servlet有较长的时间来完成它的执行,需要与上一个参数一起配合使用才会生效。

acceptCount: 指定当所有可以使用的处理请求的线程数都被使用时,可传入连接请求的最大队列长度,超过这个数的请求将不予处理,默认为 100 个。

maxKeepAliveRequests: 指定一个长连接的最大请求数。默认长连接是打开的,设置为1时,代表关闭长连接;为-1时,代表请求数无限制

compression是否对响应的数据进行GZIP压缩,off:表示禁止压缩;on:表示允许压缩(文本将被压缩)、force:表示所有情况下都进行压缩,默认值为 off,压缩数据后可以有效的减少页面的大小,一般可以减小 1/3 左右,节省带宽。

compressionMinSize: 表示压缩响应的最小值,只有当响应报文大小大于这个值的时候才会对报文进行压缩,如果开启了压缩功能,默认值就是 2048。

compressableMimeType: 压缩类型,指定对哪些类型的文件进行数据压缩。

noCompressionUserAgents="gozilla, traviata": 对于以下的浏览器,不启用压缩

如果已经进行了动静分离处理,静态页面和图片等数据就不需做 Tomcat 处理,也就不要在 Tomcat 中配置压缩了。

以上是一些常用的配置参数,还有好多其它的参数设置,还可以继续深入的优化,HTTP Connector 与 AJP Connector 的参数属性值,可以参考官方文档的详细说明进行学习。

[root@www ~]# vim /usr/local/tomcat/conf/server.xml
<Connector port="8080" protocol="HTTP/11.1" 
connectionTimeout="20000" 
redirectPort="8443" 
##--71行--插入
minSpareThreads="50" 
enableLookups="false" 
disableUploadTimeout="true" 
acceptCount="300" 
maxThreads="500" 
processorCache="500"
URIEncoding="UTF-8" 
maxKeepAliveRequests="100"
compression="on" 
compressionMinSize="2048" 
compressableMimeType="text/html,text/xml,text/javascript,text/css,text/plain,image/gif,image /jpg,image/png"/>

5. Tomcat多实例部署

5.1 环境配置

  • 安装好 jdk
  • 安装 tomcat
[root@www ~]# cd /opt
[root@www ~]# tar zxvf apache-tomcat-9.0.16.tar.gz
[root@www ~]# mkdir /usr/local/tomcat
[root@www ~]# mv apache-tomcat-9.0.16 /usr/local/tomcat/tomcat1
[root@www ~]# cp -a /usr/local/tomcat/tomcat1 /usr/local/tomcat/tomcat2

5.2 配置 tomcat 环境变量

[root@www ~]# vim /etc/profile.d/tomcat.sh
#tomcat1
export CATALINA_HOME1=/usr/local/tomcat/tomcat1
export CATALINA_BASE1=/usr/local/tomcat/tomcat1
export TOMCAT_HOME1=/usr/local/tomcat/tomcat1

#tomcat2
export CATALINA_HOME2=/usr/local/tomcat/tomcat2
export CATALINA_BASE2=/usr/local/tomcat/tomcat2
export TOMCAT_HOME2=/usr/local/tomcat/tomcat2
[root@www ~]# source /etc/profile.d/tomcat.sh

5.3 修改 tomcat2 中的 server.xml 文件

要求各 tomcat 实例配置不能有重复的端口号

[root@www ~]# vim /usr/local/tomcat/tomcat2/conf/server.xml
<Server port="8006" shutdown="SHUTDOWN">		#22行,修改Server prot,默认为8005 -> 修改为8006
<Connector port="8081" protocol="HTTP/1.1"		#69行,修改Connector port,HTTP/1.1  默认为8080 -> 修改为8081
<Connector port="8010" protocol="AJP/1.3" redirectPort="8443" />	#116行,修改Connector port AJP/1.3,默认为8009 -> 修改为8010

第一个连接器默认监听8080端口,负责建立HTTP连接。在通过浏览器访问Tomcat服务器的Web应用时,使用的就是这个连接器。

第二个连接器默认监听8009端口,AJP端口,即容器使用,如Apache能通过AJP协议访问Tomcat的8009端口。

5.4 修改各 tomcat 实例中的文件

修改startup.sh 和 shutdown.sh 文件,添加 tomcat 环境变量

[root@www ~]# vim /usr/local/tomcat/tomcat1/bin/startup.sh 
# -----------------------------------------------------------------------------
# Start Script for the CATALINA Server
# -----------------------------------------------------------------------------
##添加以下内容
export CATALINA_BASE=$CATALINA_BASE1
export CATALINA_HOME=$CATALINA_HOME1
export TOMCAT_HOME=$TOMCAT_HOME1
[root@www ~]# vim /usr/local/tomcat/tomcat1/bin/shutdown.sh
# -----------------------------------------------------------------------------
# Stop script for the CATALINA Server
# -----------------------------------------------------------------------------
export CATALINA_BASE=$CATALINA_BASE1
export CATALINA_HOME=$CATALINA_HOME1
export TOMCAT_HOME=$TOMCAT_HOME1
[root@www ~]# vim /usr/local/tomcat/tomcat2/bin/startup.sh 
# -----------------------------------------------------------------------------
# Start Script for the CATALINA Server
# -----------------------------------------------------------------------------
export CATALINA_BASE=$CATALINA_BASE2
export CATALINA_HOME=$CATALINA_HOME2
export TOMCAT_HOME=$TOMCAT_HOME2

[root@www ~]# vim /usr/local/tomcat/tomcat2/bin/shutdown.sh
# -----------------------------------------------------------------------------
# Stop script for the CATALINA Server
# -----------------------------------------------------------------------------
export CATALINA_BASE=$CATALINA_BASE2
export CATALINA_HOME=$CATALINA_HOME2
export TOMCAT_HOME=$TOMCAT_HOME2

5.5 启动各 tomcat 中的 /bin/startup.sh

[root@www ~]# /usr/local/tomcat/tomcat1/bin/startup.sh 
[root@www ~]# /usr/local/tomcat/tomcat2/bin/startup.sh 
[root@www ~]# netstat -natp | grep java

5.6 浏览器访问测试

http://192.168.200.100:8080

image.png

http://192.168.200.100:8081

image.png

6. Nginx+Tomcat负载均衡、动静分离

6.1 实验环境

Nginx 服务器:192.168.200.100:80

Tomcat服务器1:192.168.200.101:80

Tomcat服务器2:192.168.200.102:8080 192.168.200.102:8081

6.2 部署Nginx 负载均衡器

[root@www ~]# systemctl stop firewalld
[root@www ~]# setenforce 0
[root@www ~]# yum -y install pcre-devel zlib-devel openssl-devel gcc gcc-c++ make
[root@www ~]# useradd -M -s /sbin/nologin nginx
[root@www ~]# cd /opt
[root@www ~]# tar zxvf nginx-1.12.0.tar.gz -C /opt/
[root@www ~]# cd nginx-1.12.0/
[root@www ~]# ./configure \
--prefix=/usr/local/nginx \
--user=nginx \
--group=nginx \
--with-file-aio \									#启用文件修改支持
--with-http_stub_status_module \					#启用状态统计
--with-http_gzip_static_module \					#启用 gzip静态压缩
--with-http_flv_module \							#启用 flv模块,提供对 flv 视频的伪流支持
--with-http_ssl_module								#启用 SSL模块,提供SSL加密功能
--with-stream										#启用 stream模块,提供4层调度
----------------------------------------------------------------------------------------------------------
[root@www ~]# ./configure --prefix=/usr/local/nginx --user=nginx --group=nginx --with-file-aio --with-http_stub_status_module --with-http_gzip_static_module --with-http_flv_module --with-stream

[root@www ~]# make && make install
[root@www ~]# ln -s /usr/local/nginx/sbin/nginx /usr/local/sbin/
[root@www ~]# vim /lib/systemd/system/nginx.service
[Unit]
Description=nginx
After=network.target
[Service]
Type=forking
PIDFile=/usr/local/nginx/logs/nginx.pid
ExecStart=/usr/local/nginx/sbin/nginx
ExecrReload=/bin/kill -s HUP $MAINPID
ExecrStop=/bin/kill -s QUIT $MAINPID
PrivateTmp=true
[Install]
WantedBy=multi-user.target

[root@www ~]# chmod 754 /lib/systemd/system/nginx.service
[root@www ~]# systemctl start nginx.service
[root@www ~]# systemctl enable nginx.service

6.3 部署2台Tomcat 应用服务器

[root@www ~]# systemctl stop firewalld
[root@www ~]# setenforce 0
[root@www ~]# tar zxvf jdk-8u91-linux-x64.tar.gz -C /usr/local/
[root@www ~]# vim /etc/profile
export JAVA_HOME=/usr/local/jdk1.8.0_91
export JRE_HOME=${JAVA_HOME}/jre
export CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/lib
export PATH=${JAVA_HOME}/bin:${JRE_HOME}/bin:$PATH
[root@www ~]# source /etc/profile
[root@www ~]# tar zxvf apache-tomcat-8.5.16.tar.gz
[root@www ~]# mv /opt/apache-tomcat-8.5.16/ /usr/local/tomcat
[root@www ~]# /usr/local/tomcat/bin/shutdown.sh 
[root@www ~]# /usr/local/tomcat/bin/startup.sh
[root@www ~]# netstat -ntap | grep 8080

6.4 动静分离配置

6.4.1 Tomcat1 server 配置

[root@www ~]# mkdir /usr/local/tomcat/webapps/test
[root@www ~]# vim /usr/local/tomcat/webapps/test/index.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<html>
<head>
<title>JSP test1 page</title>   #指定为 test1 页面
</head>
<body>
<% out.println("动态页面 1,http://www.test1.com");%>
</body>
</html>
[root@www ~]# vim /usr/local/tomcat/conf/server.xml
#由于主机名 name 配置都为 localhost,需要删除前面的 HOST 配置
<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true" xmlValidation="false" xmlNamespaceAware="false">
	<Context docBase="/usr/local/tomcat/webapps/test" path="" reloadable="true">
	</Context>
</Host>
[root@www ~]# /usr/local/tomcat/bin/shutdown.sh 
[root@www ~]# /usr/local/tomcat/bin/startup.sh 

6.4.2 Tomcat2 server 配置

[root@www ~]# mkdir /usr/local/tomcat/tomcat1/webapps/test /usr/local/tomcat/tomcat2/webapps/test
[root@www ~]# vim /usr/local/tomcat/tomcat1/webapps/test/index.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<html>
<head>
<title>JSP test2 page</title>   #指定为 test2 页面
</head>
<body>
<% out.println("动态页面 2,http://www.test2.com");%>
</body>
</html>
[root@www ~]# vim /usr/local/tomcat/tomcat1/conf/server.xml
#删除前面的 HOST 配置
<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true" xmlValidation="false" xmlNamespaceAware="false">
	<Context docBase="/usr/local/tomcat/tomcat1/webapps/test" path="" reloadable="true" />
</Host>
[root@www ~]# /usr/local/tomcat/tomcat1/bin/shutdown.sh 
[root@www ~]# /usr/local/tomcat/tomcat1/bin/startup.sh 
[root@www ~]# vim /usr/local/tomcat/tomcat2/webapps/test/index.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<html>
<head>
<title>JSP test3 page</title>   #指定为 test3 页面
</head>
<body>
<% out.println("动态页面 3,http://www.test3.com");%>
</body>
</html>
[root@www ~]# vim /usr/local/tomcat/tomcat2/conf/server.xml
#删除前面的 HOST 配置
<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true" xmlValidation="false" xmlNamespaceAware="false">
	<Context docBase="/usr/local/tomcat/tomcat2/webapps/test" path="" reloadable="true" />
</Host>
[root@www ~]# /usr/local/tomcat/tomcat2/bin/shutdown.sh 
[root@www ~]# /usr/local/tomcat/tomcat2/bin/startup.sh 

6.4.3 Nginx server 配置

//准备静态页面和静态图片
[root@www ~]# echo '<html><body><h1>这是静态页面</h1></body></html>' > /usr/local/nginx/html/index.html
[root@www ~]# mkdir /usr/local/nginx/html/img
[root@www ~]# cp /root/game.jpg /usr/local/nginx/html/img
[root@www ~]# vim /usr/local/nginx/conf/nginx.conf
......
http {
......
	#gzip on;
	#配置负载均衡的服务器列表,weight参数表示权重,权重越高,被分配到的概率越大
	upstream tomcat_server {
		server 192.168.80.100:8080 weight=1;
		server 192.168.80.101:8080 weight=1;
		server 192.168.80.101:8081 weight=1;
	}
	server {
		listen 80;
		server_name www.can.com;
		charset utf-8;
		#access_log logs/host.access.log main;
		#配置Nginx处理动态页面请求,将 .jsp文件请求转发到Tomcat 服务器处理
		location ~ .*\.jsp$ {
			proxy_pass http://tomcat_server;
                        #设置后端的Web服务器可以获取远程客户端的真实IP
                        ##设定后端的Web服务器接收到的请求访问的主机名(域名或IP、端口),默认HOST的值为proxy_pass指令设置的主机名。如果反向代理服务器不重写该请求头的话,那么后端真实服务器在处理时会认为所有的请求都来自反向代理服务器,如果后端有防攻击策略的话,那么机器就被封掉了。
			proxy_set_header HOST $host;
                        ##把$remote_addr赋值给X-Real-IP,来获取源IP
			proxy_set_header X-Real-IP $remote_addr;
                        ##在nginx 作为代理服务器时,设置的IP列表,会把经过的机器ip,代理机器ip都记录下来
			proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
		}
		
		#配置Nginx处理静态图片请求
		location ~ .*\.(gif|jpg|jpeg|png|bmp|swf|css)$ {
			root /usr/local/nginx/html/img;
			expires 10d;
		}
		location / {
			root html;
			index index.html index.htm;
		}
......
	}
......
}
  • 测试静态页面效果

浏览器访问 http://192.168.200.100/

浏览器访问 http://192.168.200.100/game.jpg

  • 测试负载均衡效果,不断刷新浏览器测试

浏览器访问 http://192.168.200.100/index.jsp

6.5 Nginx 负载均衡模式

  • rr 负载均衡模式

每个请求按时间顺序逐一分配到不同的后端服务器,如果超过了最大失败次数后(max_fails,默认1),在失效时间内(fail_timeout,默认10秒),该节点失效权重变为0,超过失效时间后,则恢复正常,或者全部节点都为down后,那么将所有节点都恢复为有效继续探测,一般来说rr可以根据权重来进行均匀分配。

  • least_conn 最少连接

优先将客户端请求调度到当前连接最少的服务器。

  • ip_hash 负载均衡模式

每个请求按访问ip的hash结果分配,这样每个访客固定访问一个后端服务器,可以解决session的问题,但是ip_hash会造成负载不均,有的服务请求接受多,有的服务请求接受少,所以不建议采用ip_hash模式,session 共享问题可用后端服务的 session 共享代替 nginx 的 ip_hash(使用后端服务器自身通过相关机制保持session同步)。

  • fair(第三方)负载均衡模式

按后端服务器的响应时间来分配请求,响应时间短的优先分配。

  • url_hash(第三方)负载均衡模式

基于用户请求的uri做hash。和ip_hash算法类似,是对每个请求按url的hash结果分配,使每个URL定向到同一个后端服务器,但是也会造成分配不均的问题,这种模式后端服务器为缓存时比较好。

6.6 怎么实现动静分离?

nginx使用location去正则匹配用户的访问路径的前缀或后缀去判断接受的请求是静态的还是动态的,静态资源请求在nginx本地进行响应,动态页面请求通过反向代理转发给后端应用服务器

6.7 怎么实现反向代理?

现在http块中使用upstream模块定义服务器组名和服务器列表,使用location匹配路径在用proxy_pass http://服务器组名 进行七层转发

7. Nginx四层反向代理和七层反向代理配置

7.1 反向代理的两种类型

7.1.1七层代理

  • 基于http、https、mail等七层协议的反向代理

使用场景:动静分离

特点:功能强大,但转发性能较4层偏低

7层是指应用层

  • 配置

在http块里设置upstream后端服务器池,在server里用location匹配动态页面路径,使用proxy_pass http://服务器池名 进行7层协议(http协议)转发

http {
  upstream backerserver {
      server IP1:PORT1 {weight=   fail=...};
      server IP2:PORT2 {weight=   fail=...};
      ....
  }
  
  server {
       listen 80;
       server_name xxx;
       location ~ 正则表达式 {
           proxy_pass http://backerserver;
           .....
       }
  }
}

7.1.2 四层代理

  • 基于IP+(tcp或者udp)端口的代理

使用场景:负载均衡器/负载调度器,做服务器集群的访问入口

特点:只能根据IP+端口转发,但是转发性能较好

在做四层代理是编译需要添加 --with-stream

4层是在网络层

  • 配置

和http块同一层上面配置stream模块,在stream模块中的upstream模块中定义服务器组名和服务器列表,在stream模块中的server模块配置监听的ip:端口,主机名和proxy_pass服务器组名

stream {
     upstream backerserver {
       server IP1:PORT1 [wegiht=  max_fails=...];
       server IP2:PORT2 [wegiht=  max_fails=...];
       ....
     }
      server {
          listen 80;
          server_name xxx;
          location ~ 正则表达式 {
              proxy_pass backerserver;
       }
      }     
}
用户  --> 192.168.200.100:80  ---> 192.168.200.101:8080
            nginx服务器              tomcat服务器
  • Nginx四层代理配置步骤
  1. 配置好两台Nginx七层代理服务器
  2. 在四层代理的Nginx服务器上做相关配置
//在配置好的Nginx服务器上新增模块
[root@www ~]# ./configure --with-stream
[root@www ~]# make 只需编译无需安装
[root@www ~]# vim /usr/local/nginx/conf/nginx.conf
##和http同等级:所以一般只在http上面一段设置
stream {
 
   upstream appserver{
     server 192.168.229.70:8080 weight=1;
     server 192.168.229.90:8080 weight=1;
  }
   server {
      listen 8080;
      proxy_pass appserver;
  }
}

7.2 nginx如何实现会话保持

ip_hash url_hash (造成负载不均)

使用sticky_cookie_insert基于cookie来判断

通过后端服务器session共享实现

7.2.1 sticky_cookie_insert

使用sticky_cookie_insert启用会话亲缘关系,这会导致来自同一客户端的请求被传递到一组服务器在同一台服务器。与ip_hash不同之处在于,它不是基于ip来判断客户端的,而是基于cookie来判断,因此可以避免上述ip_hash中来自同一局域网的客户端和前段代理导致负载失衡的情况

  • 语法
upstream backend {
  server backend1.example.com;
  server backend2.example.com;
  sticky_cookie_insert srv_id expires=1h domain=toxingwang.com path=/;
}
expires:设置浏览器中保持cookie 的时间
domain:定义cookie的域
path:为cookie定义路径