tomcat之与静态web结合

tomcat与前端httpd或nginx的结合,实现动静分离

tomcat与前端通信方式

​ 由于connector是tomcat与外部通信的唯一关口,tomcat与其他服务通信方式,即是conector与其他服务通信的方式,connector能够定义的通信类型如下:

connector定义类型

按照协议分

  • http
    • 1.1常用
    • 1.2
  • ajp
    • 专用前端是httpd做web服务器时

按照io模型分

  • nio
  • nio2
  • apr/native

协议与io模型组合

  • http1.1 + nio
  • http1.1 + nio2
  • http1.1 + apr/native
  • ajp + nio
  • ajp + nio2
  • ajp + apr/native
  • ...

connector定义示例

<connector port="8080" protocol="HTTP/1.1" />
http1.1会自动选择NIO nio2 apr其中一个
<connector port="8080" protocol="org.apache.coyote.http11NioProtocol"/>
<connector port="8080" protocol="org.apache.coyote.http11Nio2Protocol"/>
<connector port="8080" protocol="org.apache.coyote.http11AprProtocol"/>

<connector port="8009" protocol="AJP/1.3" />
<connector port="8009" protocol="org.apache.coyote.ajp.AjpNioProtocol"/>
<connector port="8009" protocol="org.apache.coyote.ajp.AjpNio2Protocol"/>
<connector port="8009" protocol="org.apache.coyote.ajp.AjpAprProtocol"/>

tomcat与nginx

​ 由于ajp只适用于httpd,所有tomcat和nginx只能通过http协议进行通信;

tomcat与httpd

​ ajp和http都可以用于和httpd通信,httpd前端有2个模块与tomact的connector通信,mod_proxy支持http和ajp,mod_jk支持ajp,

tomcat与静态web服务组合架构

  • web服务器如nginx/httpd,同时担任静态web服务,以及动态请求转发的反代服务;
  • web服务器如nginx/httpd,只担任静态web服务器,由前端nginx/haproxy/lvs进行动静请求的分离反代;

示例

tomcat+nginx

192.168.80.100 nginx

192.168.80.101 tomcat1
192.168.80.102 tomcat2

1,安装2台tomcat

​ 安装jdk

​ 安装tomcat

2,安装一台nginx

​ 采用nginx官方repo,安装最新稳定版1.18即可

3,nginx配置一台虚拟主机,配置转发

[root@host1 nginx]# cat conf.d/tomcat.conf 
upstream tomcat {
	server 192.168.80.101:8080;
	#server 192.168.80.102:8080;
}

server {
	listen 80;
	server_name 192.168.80.100;
	
	location / {
		root /usr/share/nginx/html;
		index index.html index.htm;

	}
	
	location ~* \.(jsp|jspx|do) {
		proxy_pass http://tomcat;
	}

}
# nginx -t; nginx -s reload

4、浏览器访问

​ 访问192.168.80.100/时,会返回nginx静态首页,访问.jsp后缀时,就根据配置转发到后端tomcat,tomcat运行jsp并返回处理后数据,文字部分直接返回,正常显示,图片部分返回的是包含在首页的链接,浏览器接收到首页后,分析其中链接,然后再次发起请求向80.100,但80.100的静态部分寻找路径是本机/usr/share/nginx/html目录,自然找不到对应文件,所有图片、样式等静态资源全部缺失,最终界面如图:

image-20200905174233595

5、解决方法:

配置nginx将全部请求,无论动静都转发给tomcat处理

nginx配置如下:

[root@host1 nginx]# cat conf.d/tomcat.conf 
upstream tomcat {
	server 192.168.80.101:8080;
	#server 192.168.80.102:8080;
}

server {
	listen 80;
	server_name 192.168.80.100;
	
	location / {
#		root /usr/share/nginx/html;
#		index index.html index.htm;
	proxy_pass  http://tomcat;

	}
	
#	location ~* \.(jsp|jspx|do) {
#		proxy_pass http://tomcat;
#	}

}

[root@host1 nginx]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@host1 nginx]# nginx -s reload

浏览器访问,全部页面都可以正常显示,因为nginx将全部请求都交由tomcat处理,不存在动静分离,也不存在文件找不到问题;

image-20200905180015125

合理配置nginx,使得其能找到静态资源,

如将ROOT目录下所有文件,以及examples这个webapp的目录拷贝到nginx的网页根目录下,再次访问,根据nginx和tomcat两台主机相同的目录路径,可以找到对应的静态资源文件,即可正常展示页面

# 在tomcat上,将对应目录原样复制到nginx上,
[root@host2 webapps]# scp -r examples/ 192.168.80.100:/usr/share/nginx/html
[root@host2 webapps]# scp -r ./ROOT/* 192.168.80.100:/usr/share/nginx/html

# nginx目录
# examples是将整个目录放在html/目录下,而ROOT是将其下文件直接放在html/目录下
[root@host1 nginx]# ll /usr/share/nginx/html/
total 188
-rw-r--r-- 1 nginx nginx   494 Apr 21 23:07 50x.html
-rw-r----- 1 nginx nginx 27235 Sep  5 17:45 asf-logo-wide.svg
-rw-r----- 1 nginx nginx   713 Sep  5 17:45 bg-button.png
-rw-r----- 1 nginx nginx  1918 Sep  5 17:45 bg-middle.png
-rw-r----- 1 nginx nginx  1401 Sep  5 17:45 bg-nav.png
-rw-r----- 1 nginx nginx  3103 Sep  5 17:45 bg-upper.png
drwxr-x--- 6 nginx nginx    83 Sep  5 17:49 examples
-rw-r----- 1 nginx nginx 21630 Sep  5 17:45 favicon.ico
-rw-r--r-- 1 nginx nginx   612 Apr 21 23:07 index.html
-rw-r----- 1 nginx nginx 12219 Sep  5 17:45 index.jsp
-rw-r----- 1 nginx nginx  7136 Sep  5 17:45 RELEASE-NOTES.txt
-rw-r----- 1 nginx nginx  5581 Sep  5 17:45 tomcat.css
-rw-r----- 1 nginx nginx  2066 Sep  5 17:45 tomcat.gif
-rw-r----- 1 nginx nginx  5103 Sep  5 17:45 tomcat.png
-rw-r----- 1 nginx nginx  2376 Sep  5 17:45 tomcat-power.gif
-rw-r----- 1 nginx nginx 67795 Sep  5 17:45 tomcat.svg
drwxr-x--- 2 nginx nginx    21 Sep  5 17:45 WEB-INF

访问examples可以,首页可以,其他如docs的webapp,由于没有复制对应目录到nginx下,所以仍然无法显示

image-20200905180957819

image-20200905175011811

tomcat与httpd

mod_jk下载地址:

http://tomcat.apache.org/download-connectors.cgi

配置手册:

http://tomcat.apache.org/tomcat-8.5-doc/connectors.html

mod_jk转发tomcat

mod_jk模块,反代tomcat,一般只用ajp协议

  1. httpd编译mod_jk模块
  2. 配置httpd,引入mod_jk,指明后端节点信息配置文件,uri转发规则配置
  3. 创建后端节点信息配置文件,其中配置后端节点信息
  4. 重启httpd
  5. tomcat:设置jvmRoute参数在engine上
  6. 设置connector,开启ajp13,配置监听地址,默认监听的所有ipv6地址,ipv4地址去连接拒绝;

1、编译mod_jk模块

下载源码包,解压;进入解压后目,再进入native目录,内有configure脚本
tar -xf tomcat-connectors-1.2.48-src.tar.gz
cd tomcat-connectors-1.2.48-src/
cd native
 
下载编译工具,包含apxs工具的httpd-devel包
yum install -y gcc gcc++ httpd-devel

编译,变异后的模块在apache-2.0目录下
./configure --with-apxs=/usr/bin/apxs
make

复制到httpd的模块目录下
cp apache-2.0/mod_jk.so /etc/httpd/modules/

2,导入mod jk,配置转发规则等

LoadModule jk_module modules/mod_jk.so
# 导入jk模块

# Update this path to match your conf directory location (put workers.properties next to httpd.conf)
# 节点信息配置文件
JkWorkersFile /etc/httpd/conf.d/workers.properties


# Where to put jk shared memory
# Update this path to match your local state directory or logs directory
JkShmFile     /var/log/httpd/mod_jk.shm
# Where to put jk logs
# Update this path to match your logs directory location (put mod_jk.log next to access_log)
JkLogFile     /var/log/httpd/mod_jk.log

# Set the jk log level [debug/error/info]
JkLogLevel    info
# Select the timestamp log format
JkLogStampFormat "[%a %b %d %H:%M:%S %Y] "
# Send everything for context /examples to worker named worker1 (ajp13)

# uri的转发规则,status的是状态页,其余的全部转发给后端TomcatA节点
######### "JkMount /* TomcatA" will send all request to TomcatA   ########
JkMount   /status/*     statA
JkMount   /*        TomcatA

3,配置workers.properties文件

[root@host1 httpd]# cat conf.d/workers.properties 
worker.list=TomcatA,statA
worker.TomcatA.type=ajp13
worker.TomcatA.host=192.168.80.102
worker.TomcatA.port=8009
worker.TomcatA.lbfactor=1
worker.statA.type = status
# 配置2个节点,一个是status内置状态页,一个是实际tomcat节点80.102
# 重启httpd

4,tomcat设置类型为ajp13的connector,和engine的jvmRoute参数

# 设置ajp13的连接器,地址要改为本机地址,默认的监听所有ipv6地址不不接受ipv4连接;
<Connector protocol="AJP/1.3"
               address="192.168.80.102"
               port="8009"
               redirectPort="8443" secretRequired="" />

# engine加上jvmRoute参数
  <Engine name="Catalina" defaultHost="localhost" jvmRoute="TomcatA">

# 重启tomcat

5,访问测试

100为httpd服务器,访问其上jsp文件,都可以转发给后端102的tomcat,从而正常访问;

image-20200906163318818

访问状态页也正常;

image-20200906161959829

遇到的错误:

根据上述配置完成后,一直无法正常访问,即httpd和tomcat反代一直失败,最终查看catalina引擎的日志,发现如下错误, The AJP Connector is configured with secretRequired="true" but the secret attribute is either null or ""

[root@host3 tomcat]# tailf logs/catalina.2020-09-06.log 
...
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
		at java.lang.reflect.Method.invoke(Method.java:498)
		at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:342)
		at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:473)
	Caused by: java.lang.IllegalArgumentException: The AJP Connector is configured with secretRequired="true" but the secret attribute is either null or "". 

# 根据google搜索结果,在connector部分,加入一个secretRequired=""后重启,即可;
	  <Connector protocol="AJP/1.3"
               address="192.168.80.102"
               port="8009"
               redirectPort="8443" secretRequired="" />
# 之后可以正常访问;

mod_jk负载均衡tomcat

1、修改jk的配置文件,将转发目标设置为一个负载均衡的worker,此处命名为lb,是一个逻辑的节点,其下包含2个真实节点;

[root@host1 httpd]# cat conf.d/mod_jk.conf 
LoadModule jk_module modules/mod_jk.so
...

######### "JkMount /* TomcatA" will send all request to TomcatA   ########
JkMount   /status/*     statA
JkMount   /*        lb

2、修改workers.properties文件,定义lb和其下2个真实节点

​ 定义了内置的stata状态页,lb一个逻辑节点,其下包含的2个真实节点,2个真实节点的地址,协议,端口,权重都根据实际情况设置,这里设置为权重一比一,关闭会话粘性,所以访问效果会是轮询!

[root@host1 httpd]# cat conf.d/workers.properties
worker.list=lb,statA
worker.statA.type = status
worker.lb.type=lb
worker.lb.sticky_session=false
worker.lb.balance_workers=TomcatA,TomcatB

worker.TomcatA.type=ajp13
worker.TomcatA.host=192.168.80.102
worker.TomcatA.port=8009
worker.TomcatA.lbfactor=1

worker.TomcatB.type=ajp13
worker.TomcatB.host=192.168.80.101
worker.TomcatB.port=8009
worker.TomcatB.lbfactor=1

3,分别配置2个后端tomcat节点

​ 以TomcatA为例

# 配置connector和jvmRoute参数
<Connector protocol="AJP/1.3"
               address="192.168.80.102"
               port="8009"
               redirectPort="8443" secretRequired="" />


 <Engine name="Catalina" defaultHost="localhost" jvmRoute="TomcatA">


# 创建一个test的webapp,
[root@host3 tomcat]# mkdir -pv /usr/local/tomcat/webapps/test/WEB-INF/{classes,lib}
mkdir: created directory ‘/usr/local/tomcat/webapps/test’
mkdir: created directory ‘/usr/local/tomcat/webapps/test/WEB-INF’
mkdir: created directory ‘/usr/local/tomcat/webapps/test/WEB-INF/classes’
mkdir: created directory ‘/usr/local/tomcat/webapps/test/WEB-INF/lib’

# 写入首页文件,
[root@host3 tomcat]# vim /usr/local/tomcat/webapps/test/index.jsp
<%@ page language="java" %>
<html>
  <head><title>TomcatA</title></head>
  <body>
    <h1><font color="red">TomcatA </font></h1>
    <table align="centre" border="1">
      <tr>
        <td>Session ID</td>
    <% session.setAttribute("abc","abc"); %>
        <td><%= session.getId() %></td>
      </tr>
      <tr>
        <td>Created on</td>
        <td><%= session.getCreationTime() %></td>
     </tr>
    </table>
  </body>
</html>

# 重启
[root@host3 tomcat]# catalina.sh stop;catalina.sh start

​ TomcatB,修改对应参数为TomcatB即可,其余步骤一致

# connector和jvmRoute参数
    <Connector protocol="AJP/1.3"
               address="192.168.80.101"
               port="8009"
               redirectPort="8443" secretRequired=""/>

<Engine name="Catalina" defaultHost="localhost" jvmRoute="TomcatB">


# 首页文件不同,改成TomcatB
[root@host2 tomcat]# cat /usr/local/tomcat/webapps/test/index.jsp 
<%@ page language="java" %>
<html>
  <head><title>TomcatB</title></head>
  <body>
    <h1><font color="blue">TomcatB </font></h1>
    <table align="centre" border="1">
      <tr>
        <td>Session ID</td>
    <% session.setAttribute("abc","abc"); %>
        <td><%= session.getId() %></td>
      </tr>
      <tr>
        <td>Created on</td>
        <td><%= session.getCreationTime() %></td>
     </tr>
    </table>
  </body>
</html>

# 重启tomcat

4、重启httpd,tomcat,然后用无痕模式访问测试,排除缓存干扰

​ 轮询效果如下:

​ 若将sticky_session设置为ture,则是会话绑定效果;

image-20200906193453170

image-20200906193510005

mod_proxy转发tomcat

mod_proxy做tomcat的反代,可以使用http和ajp两种协议配置反代时,协议头选择ajp或http,以及对应的端口即可;

mod_proxy必须的几种模块如下:yum安装自带这些模块,编译安装时,需要enable这些模块;

[root@host1 httpd]# httpd -k restart
[root@host1 httpd]# httpd -M |grep proxy
 proxy_module (shared)
 proxy_ajp_module (shared)
 proxy_balancer_module (shared)
 proxy_http_module (shared)

1、配置httpd,配置反代,

[root@host1 httpd]# cat conf.d/ajp.conf
<Location /status>
	SetHandler balancer-manager
	ProxyPass !
	Require ip 192.168.80.0
</Location>

ProxyVia off
ProxyRequests off
ProxyPreserveHost off

ProxyPassMatch "^/(.*)$" ajp://192.168.80.101:8009/$1
ProxyPassReverse "^/(.*)$" ajp://192.168.80.101:8009/$1

<Proxy *>
	Require all granted
</Proxy>

2、浏览器访问,成功反代;

mod_proxy负载均衡tomcat

1、配置后端节点组,在反代时,引用后端节点组名称即可

[root@host1 httpd]# pwd
/etc/httpd
[root@host1 httpd]# cat conf.d/ajp.conf
<proxy balancer://tomcatlb>
	BalancerMember ajp://192.168.80.101:8009
	BalancerMember ajp://192.168.80.102:8009

</proxy>
ProxyVia off
ProxyRequests off
ProxyPreserveHost off

ProxyPassMatch "^/(.*\.jsp)$" balancer://tomcatlb/$1
ProxyPassReverse "^/(.*\.jsp)$" balancer://tomcatlb/$1

<Proxy *>
	Require all granted
</Proxy>

2、浏览器访问

​ 访问:http://192.168.80.100/test/index.jsp,结果仍为轮询调度;

updatedupdated2020-10-192020-10-19
加载评论