目录
1、概述
2、方案一:以proxy_module方式反向代理
3、方案二:以mod_jk方式反向代理
4、总结
1、概述
在前一博客(http://zhaochj.blog.51cto.com/368705/1639740)中实现了tomcat的在standalone模式下的部署,这样tomcat就身兼职两职,一方向要对http的请求作出响应,又要处理JSP程序,而处理http请求不是tomcat的强项,所以这样的请求就交给httpd、nginx这样的的专业处理http请求的套件来处理,而tomcat则专业用来响应JSP的请求。
这次在上一博客的基础上来实现以httpd套件来反向代理tomcat,可以把所有的请求(包括静态与动态)都代理到后端的tomcat服务器,这样tomcat也是一样会处理静态和动态的请求,只是前端的请求接入将由了httpd或nginx来处理,而像nginx这样的专业软件拥有强大的会话并发能力,这样tomcat就不需要去保持与用户的会话。然而把静态与动态的请求都让tomcat来作出响应也不是很恰当,应该把静态的请求直接在httpd或nginx端面就直接响应给用户请求,而JSP的动态页面则由httpd或nginx代理向后端的tomcat请求,把动态页面请求的结果生成静态页面后再把结果反馈给用户,这样让httpd或nginx和tomcat各司其职,把自己的优势发挥出来,最终部署的应用才能发挥良好的性能。
以httpd作为前端的反向代理,那有两种选择,一是利用"proxy_module"这个代理框架下的"proxy_http_module"与"proxy_ajp_module"这两个代理模块,这两个代理模块是独自工作的,二是利用“mod_jk”模块实现httpd的反向代理至后端tomcat。
2、方案一:以proxy_module方式反向代理
在上一次博客中tomcat已能正常运行,并部署了shopxx一个测试电商站点,现在安装httpd套件并配置成能反向代理JSP请求到tomcat的场景。而我这里系统自带的httpd的rpm包是2.2版本的,而这个版本就包含了我们所需要的模块,所以就用此版本来实现我们的环境。
2.1、网站以"proxy_http_module"实现反应代理
httpd版本及模块检查:
[root@master ~]# rpm -q httpd httpd-2.2.15-39.el6.centos.x86_64 [root@master ~]# httpd -M | grep proxy Syntax OK proxy_module (shared) #主模块 proxy_balancer_module (shared) proxy_ftp_module (shared) proxy_http_module (shared) #走http协议的反向代理模块 proxy_ajp_module (shared) #走ajp协议的反向代理模块 proxy_connect_module (shared)
配置httpd的配置文件,使其成为tomcat的代理服务器,这里我以虚拟主机的方式提供http服务:
[root@master ~]# vim /etc/httpd/conf/httpd.conf #DocumentRoot "/var/www/html" #注释掉中心主机 [root@master ~]# vim /etc/httpd/conf.d/virtual.conf #虚拟主机我以单独的配置文件提供DocumentRoot /tomcat/webapps/shopxx ServerName test.shopxx.com ErrorLog logs/test.shopxx.com-error.log CustomLog logs/test.shopxx.com-access.log common ProxyVia Off ProxyRequests Off ProxyPreserveHost On ProxyPass / http://test.shopxx.com:8080/ ProxyPa***everse / http://test.shopxx.com:8080/
参数解释:
ProxyVia {On|Off|Full|Block}:用于控制在http首部是否使用Via:,主要用于在多级代理中控制代理请求的流向。默认为Off,即不启用此功能;On表示每个请求和响应报文均添加Via:;Full表示每个Via:行都会添加当前apache服务器的版本号信息;Block表示每个代理请求报文中的Via:都会被移除。
ProxyRequests {On|Off}:是否开启apache正向代理的功能;启用此项时为了代理http协议必须启用mod_proxy_http模块。同时,如果为apache设置了ProxyPass,则必须将ProxyRequests设置为Off。
ProxyPreserveHost {On|Off}:如果启用此功能,代理会将用户请求报文中的Host:行发送给后端的服务器,而不再使用ProxyPass指定的服务器地址。如果想在反向代理中支持虚拟主机,则需要开启此项,否则就无需打开此功能。
ProxyPass path [!]|[url [key=value key=value ...]]:将后端服务器某URL与当前服务器的某虚拟路径关联起来作为提供服务的路径,path为当前服务器上的某虚拟路径,url为后端服务器上某URL路径。使用此指令时必须将ProxyRequests的值设置为Off。需要注意的是,如果path以“/”结尾,则对应的url也必须以“/”结尾,反之亦然。
另外,mod_proxy模块在httpd 2.1的版本之后支持与后端服务器的连接池功能,连接在按需创建在可以保存至连接池中以备进一步使用。连接池大小或其它设定可以通过在ProxyPass中使用key=value的方式定义。常用的key如下所示:
min:连接池的最小容量,此值与实际连接个数无关,仅表示连接池最小要初始化的空间大小。
max:连接池的最大容量,每个MPM都有自己独立的容量;都值与MPM本身有关,如Prefork的总是为1,而其它的则取决于ThreadsPerChild指令的值。
loadfactor:用于负载均衡集群配置中,定义对应后端服务器的权重,取值范围为1-100。
retry:当apache将请求发送至后端服务器得到错误响应时等待多长时间以后再重试。单位是秒钟。
点击这里有更详细的说明:http://httpd.apache.org/docs/2.2/mod/mod_proxy.html#proxypass
配置文件修改好后启动httpd服务:
[root@master ~]# httpd -t Syntax OK [root@master ~]# service httpd start
访问主页,查看日志文件:
打开chrome浏览器,输入http://test.shopxx.com访问主页,如果之前访问过可按住“ctrl”键再按“F5”就可以绕过本地缓存直接从服务器取数据。
[root@master ~]# tail -20 /usr/local/tomcat/logs/test_access_log.2015-04-29.txt ####截取部份#### 192.168.0.201 - - [29/Apr/2015:14:59:40 +0800] "GET / HTTP/1.1" 200 8432 192.168.0.201 - - [29/Apr/2015:14:59:40 +0800] "GET /shopxx/resources/shop/slider/slider.css HTTP/1.1" 200 633 192.168.0.201 - - [29/Apr/2015:14:59:40 +0800] "GET /shopxx/resources/shop/css/index.css HTTP/1.1" 200 1553 192.168.0.201 - - [29/Apr/2015:14:59:40 +0800] "GET /shopxx/resources/shop/js/jquery.tools.js HTTP/1.1" 200 3932 192.168.0.201 - - [29/Apr/2015:14:59:40 +0800] "GET /shopxx/resources/shop/css/common.css HTTP/1.1" 200 3603 192.168.0.201 - - [29/Apr/2015:14:59:40 +0800] "GET /shopxx/resources/shop/js/jquery.js HTTP/1.1" 200 33471 192.168.0.201 - - [29/Apr/2015:15:00:00 +0800] "GET /shopxx/resources/shop/js/common.js HTTP/1.1" 200 3103 192.168.0.201 - - [29/Apr/2015:15:00:00 +0800] "GET /shopxx/resources/shop/slider/slider.js HTTP/1.1" 200 3033 192.168.0.201 - - [29/Apr/2015:15:00:00 +0800] "GET /upload/p_w_picpath/logo.gif HTTP/1.1" 200 3445
仔细观察日志文件,第一列的IP地址就是本机的IP,并不是我发起访问主页的主机地址,因为做反向代理后访问tomcat的就只有前端的httpd进程,而httpd与tomcat在这里是同一主机,所以这里记录的就是本机的IP地址。再看请求的各个资源,有以下几类:.css、.js、.gif结尾的这三类,从后缀可推断这都是静态资源,从网站系统架构上讲这些静态文件是不应该让tomcat容器来响应的,从另一方面也说明一个网站的主页在设计上最好不要有动态资源的请求,因为静态资源的请求时间会远远短于动态资源请求的时间,这样主页打开的速度会更快。
在shopxx的主页随便点击几个链接,再来观察tomcat的日志文件:
[root@master ~]# tail /usr/local/tomcat/logs/test_access_log.2015-04-29.txt 192.168.0.201 - - [29/Apr/2015:14:59:40 +0800] "GET /shopxx/resources/shop/css/common.css HTTP/1.1" 200 3603 192.168.0.201 - - [29/Apr/2015:14:59:40 +0800] "GET /shopxx/resources/shop/js/jquery.js HTTP/1.1" 200 33471 192.168.0.201 - - [29/Apr/2015:15:00:00 +0800] "GET /shopxx/resources/shop/js/common.js HTTP/1.1" 200 3103 192.168.0.201 - - [29/Apr/2015:15:00:00 +0800] "GET /shopxx/resources/shop/slider/slider.js HTTP/1.1" 200 3033 192.168.0.201 - - [29/Apr/2015:15:00:00 +0800] "GET /upload/p_w_picpath/logo.gif HTTP/1.1" 200 3445 192.168.0.201 - - [29/Apr/2015:15:00:20 +0800] "GET /shopxx/resources/shop/p_w_picpaths/common.gif HTTP/1.1" 200 5937 192.168.0.201 - - [29/Apr/2015:15:00:20 +0800] "GET /shopxx/resources/shop/p_w_picpaths/index.gif HTTP/1.1" 200 4972 192.168.0.201 - - [29/Apr/2015:15:09:05 +0800] "GET /product/list/2.jhtml HTTP/1.1" 200 6674 192.168.0.201 - - [29/Apr/2015:15:09:05 +0800] "GET /resources/shop/js/common.js HTTP/1.1" 200 3103 192.168.0.201 - - [29/Apr/2015:15:09:28 +0800] "GET /product/list/3.jhtml HTTP/1.1" 200 5861
观察最后三行,可知这个网站的动态页面的后缀是jhtml结尾的,可不是jsp。
从tomcat日志输出中我们得到了做动静分离非常有用的信息如下:
a、静态文件(以.css、.js、..gif)存放目录,
b、动态文件的后缀是jhtml
2.2、网站动静分离实现
配置httpd配置文件:
[root@master ~]# vim /etc/httpd/conf.d/virtual.confDocumentRoot /tomcat/webapps/shopxx ServerName test.shopxx.com ErrorLog logs/test.shopxx.com-error.log CustomLog logs/test.shopxx.com-access.log common ProxyVia Off ProxyRequests Off ProxyPreserveHost On ProxyPass /resources/shop/css ! #新增加 ProxyPass /resources/shop/js ! #新增加 ProxyPass /resources/shop/p_w_picpaths ! #新增加 ProxyPass /upload/p_w_picpath ! #新增加 ProxyPass / http://test.shopxx.com:8080/ ProxyPa***everse / http://test.shopxx.com:8080/
#因"DocumentRoot /tomcat/webapps/shopxx"已指向了“shopxx”目录,所以增加的参数中去掉了开头的“/shopxx”,新增加的这几行表示这些目录不会转发到后端的tomcat上,只在本地进行处理。
重新启动httpd服务:
[root@master ~]# service httpd restart
用chrome绕过缓存再次打开主页,能正常打开,如下图:
点击主页中的各个链接,也都能正常的打开。
接下来验证动静分离,查看tomcat访问日志文件,如果没有处理静态资源,那就说明tomcat只是在处理动态页面,那从反面也证明了静态页面在前端被httpd处理了。
查看tomcat访问日志文件:
[root@master ~]# tail /usr/local/tomcat/logs/test_access_log.2015-04-29.txt 192.168.0.201 - - [29/Apr/2015:16:11:53 +0800] "GET /shopxx/resources/shop/slider/slider.css HTTP/1.1" 200 633 192.168.0.201 - - [29/Apr/2015:16:11:53 +0800] "GET /shopxx/resources/shop/js/jquery.tools.js HTTP/1.1" 200 3932 192.168.0.201 - - [29/Apr/2015:16:11:53 +0800] "GET /shopxx/resources/shop/js/jquery.js HTTP/1.1" 200 33471 192.168.0.201 - - [29/Apr/2015:16:12:13 +0800] "GET /shopxx/resources/shop/slider/slider.js HTTP/1.1" 200 3033 192.168.0.201 - - [29/Apr/2015:16:12:13 +0800] "GET /shopxx/resources/shop/js/common.js HTTP/1.1" 200 3103 192.168.0.201 - - [29/Apr/2015:16:12:33 +0800] "GET /shopxx/resources/shop/p_w_picpaths/common.gif HTTP/1.1" 200 5937 192.168.0.201 - - [29/Apr/2015:16:12:33 +0800] "GET /shopxx/resources/shop/p_w_picpaths/index.gif HTTP/1.1" 200 4972 192.168.0.201 - - [29/Apr/2015:16:13:30 +0800] "GET /product/list/1.jhtml HTTP/1.1" 200 6820 192.168.0.201 - - [29/Apr/2015:16:13:30 +0800] "GET /product/list/2.jhtml HTTP/1.1" 200 6674 192.168.0.201 - - [29/Apr/2015:16:13:31 +0800] "GET /product/list/3.jhtml HTTP/1.1" 200 5861
仔细观察日志,你会发现tomcat静态页面、动态页面都在处理,所以动静分离并没有成功。
再查看httpd的访问日志:
[root@master ~]# tail /var/log/httpd/test.shopxx.com-access.log 192.168.0.102 - - [29/Apr/2015:16:11:53 +0800] "GET /shopxx/resources/shop/css/common.css HTTP/1.1" 200 3603 192.168.0.102 - - [29/Apr/2015:16:11:53 +0800] "GET /shopxx/resources/shop/js/jquery.js HTTP/1.1" 200 33471 192.168.0.102 - - [29/Apr/2015:16:12:13 +0800] "GET /shopxx/resources/shop/slider/slider.js HTTP/1.1" 200 3033 192.168.0.102 - - [29/Apr/2015:16:12:13 +0800] "GET /shopxx/resources/shop/js/common.js HTTP/1.1" 200 3103 192.168.0.102 - - [29/Apr/2015:16:12:33 +0800] "GET /shopxx/resources/shop/p_w_picpaths/index.gif HTTP/1.1" 200 4972 192.168.0.102 - - [29/Apr/2015:16:12:33 +0800] "GET /shopxx/resources/shop/p_w_picpaths/common.gif HTTP/1.1" 200 5937 192.168.0.102 - - [29/Apr/2015:16:13:30 +0800] "GET /product/list/1.jhtml HTTP/1.1" 200 6820 192.168.0.102 - - [29/Apr/2015:16:13:30 +0800] "GET /resources/shop/js/common.js HTTP/1.1" 304 - 192.168.0.102 - - [29/Apr/2015:16:13:30 +0800] "GET /product/list/2.jhtml HTTP/1.1" 200 6674 192.168.0.102 - - [29/Apr/2015:16:13:31 +0800] "GET /product/list/3.jhtml HTTP/1.1" 200 5861
仔细查看httpd的日志,似乎发现哪里不对,在virtual.conf配置文件中"DocumentRoot /tomcat/webapps/shopxx",但日志中怎么访问资源时还在开头带了“/shopxx”,如果访问过程是这样,那我们在virtual.conf中配置的过虑规则就要有所修改才行。
修改virtual.conf文件:
[root@master ~]# vim /etc/httpd/conf.d/virtual.confDocumentRoot /tomcat/webapps #第一处修改 ServerName test.shopxx.com ErrorLog logs/test.shopxx.com-error.log CustomLog logs/test.shopxx.com-access.log common ProxyVia Off ProxyRequests Off ProxyPreserveHost On ProxyPass /shopxx/resources/shop/css ! #第二处修改 ProxyPass /shopxx/resources/shop/js ! #第三处修改 ProxyPass /shopxx/resources/shop/p_w_picpaths ! #第四处修改 ProxyPass /shopxx/resources/shop/slider ! #第五处修改 ProxyPass /shopxx/upload/p_w_picpath ! #第六处修改 ProxyPass / http://test.shopxx.com:8080/ ProxyPa***everse / http://test.shopxx.com:8080/
注意:这次修改的地方可不只是在各个静态资源路径前加上“/shopxx”,一定不要忘记把“DocumentRoot /tomcat/webapps/shopxx ”修改成“DocumentRoot /tomcat/webapps ”,为什么?因为如果不修改那httpd在处理静态页面时它会去“/tomcat/webapps/shopxx/shopxx/resources/shop/css......”这样的路径去找,显然路径是不对的。
再次重启httpd服务后去访问主页,再去验证动静是否已分离:
[root@master ~]# service httpd restart [root@master ~]# tail /usr/local/tomcat/logs/test_access_log.2015-04-29.txt 192.168.0.201 - - [29/Apr/2015:17:13:17 +0800] "GET /shopxx/product/hits/200.jhtml HTTP/1.1" 200 36 192.168.0.201 - - [29/Apr/2015:17:14:17 +0800] "GET /shopxx/ HTTP/1.1" 200 8432 192.168.0.201 - - [29/Apr/2015:17:14:20 +0800] "GET / HTTP/1.1" 200 8432 192.168.0.201 - - [29/Apr/2015:17:14:21 +0800] "GET / HTTP/1.1" 200 8432 192.168.0.201 - - [29/Apr/2015:17:14:21 +0800] "GET /upload/p_w_picpath/logo.gif HTTP/1.1" 200 3445 192.168.0.201 - - [29/Apr/2015:17:14:42 +0800] "GET /product/list/1.jhtml HTTP/1.1" 200 6820 192.168.0.201 - - [29/Apr/2015:17:14:42 +0800] "GET /product/list/2.jhtml HTTP/1.1" 200 6674 192.168.0.201 - - [29/Apr/2015:17:14:43 +0800] "GET /product/list/3.jhtml HTTP/1.1" 200 5861 192.168.0.201 - - [29/Apr/2015:17:14:43 +0800] "GET /product/list/4.jhtml HTTP/1.1" 200 4698 192.168.0.201 - - [29/Apr/2015:17:14:45 +0800] "GET /product/list/2.jhtml HTTP/1.1" 200 6674 #看上边的日志,网站的logo.gif这个图片还是发到tomcat上来处理了。 [root@master ~]# tail -15 /var/log/httpd/test.shopxx.com-access.log 192.168.0.102 - - [29/Apr/2015:17:14:21 +0800] "GET /shopxx/resources/shop/js/jquery.tools.js HTTP/1.1" 200 10663 192.168.0.102 - - [29/Apr/2015:17:14:21 +0800] "GET /shopxx/resources/shop/js/common.js HTTP/1.1" 200 9247 192.168.0.102 - - [29/Apr/2015:17:14:21 +0800] "GET /shopxx/resources/shop/slider/slider.js HTTP/1.1" 200 11561 192.168.0.102 - - [29/Apr/2015:17:14:21 +0800] "GET /shopxx/resources/shop/js/jquery.js HTTP/1.1" 200 93637 192.168.0.102 - - [29/Apr/2015:17:14:21 +0800] "GET /upload/p_w_picpath/logo.gif HTTP/1.1" 200 3445 192.168.0.102 - - [29/Apr/2015:17:14:21 +0800] "GET /shopxx/resources/shop/p_w_picpaths/index.gif HTTP/1.1" 200 4972 192.168.0.102 - - [29/Apr/2015:17:14:21 +0800] "GET /shopxx/resources/shop/p_w_picpaths/common.gif HTTP/1.1" 200 5937 192.168.0.102 - - [29/Apr/2015:17:14:17 +0800] "GET /shopxx/ HTTP/1.1" 200 8432 192.168.0.102 - - [29/Apr/2015:17:14:20 +0800] "GET / HTTP/1.1" 200 8432 192.168.0.102 - - [29/Apr/2015:17:14:21 +0800] "GET / HTTP/1.1" 200 8432 192.168.0.102 - - [29/Apr/2015:17:14:42 +0800] "GET /product/list/1.jhtml HTTP/1.1" 200 6820 192.168.0.102 - - [29/Apr/2015:17:14:42 +0800] "GET /product/list/2.jhtml HTTP/1.1" 200 6674 #看到“/upload/p_w_picpath/logo.gig”这一行了吧,好奇怪这个资源没有“/shopxx”开头,这样的话,那virtual.conf里的过虑规则就过虑不掉它了,如果过虑规则修改成“ProxyPass /upload/p_w_picpath ! ”,那logo.gif这个图片在主页上无法显示,这个问题一直没办法排除,但动静分离还是几乎实现了,除了这个logo.gif外。
2.3、网站以"proxy_ajp_module"实现反应代理
在以httpd来反向代理tomcat的架构中,除了支持http协议外,还支持ajp(apache jserv protocol)协议,默认时tomcat监听在ajp的8009端口上。
[root@master ~]# vim /etc/httpd/conf.d/virtual.confDocumentRoot /tomcat/webapps ServerName test.shopxx.com ErrorLog logs/test.shopxx.com-error.log CustomLog logs/test.shopxx.com-access.log common ProxyVia Off ProxyRequests Off ProxyPreserveHost On ProxyPass /shopxx/resources/shop/css ! ProxyPass /shopxx/resources/shop/js ! ProxyPass /shopxx/resources/shop/p_w_picpaths ! ProxyPass /shopxx/resources/shop/slider ! ProxyPass /shopxx/upload/p_w_picpath ! ProxyPass / ajp://test.shopxx.com:8009/ #修改一 ProxyPa***everse / ajp://test.shopxx.com:8009/ #修改二
重启httpd服务后,网站依然能够正常访问。
3、方案二:以mod_jk方式反向代理
mod_jk是一个工作于apache端基于AJP协议与Tomcat通信的连接器,它是apache的一个模块,是AJP协议的客户端(服务端是Tomcat的AJP连接器),这个模块默认没有被编译进系统自带的rpm包,所以要自己编译这个连接器。下载地址:http://tomcat.apache.org/download-connectors.cgi,而要把模块编译进httpd需要httpd-devel环境,如果没有安装此环境,请用“yum -y install httpd-devel”安装。
3.1、mod_jk模块编译安装
[root@master software]# tar xf tomcat-connectors-1.2.40-src.tar.gz [root@master software]# cd tomcat-connectors-1.2.40-src [root@master tomcat-connectors-1.2.40-src]# ls conf docs HOWTO-RELEASE.txt jkstatus LICENSE native NOTICE README.txt support tools xdocs [root@master tomcat-connectors-1.2.40-src]# cd native/ [root@master native]# ./configure --with-apxs=/usr/sbin/apxs [root@master native]# make && make install [root@master native]# ls /usr/lib64/httpd/modules/ | grep mod_jk #安装好后模块生成 mod_jk.so
3.2、基于mod_jk的配置
[root@master conf.d]# pwd /etc/httpd/conf.d [root@master conf.d]# mv virtual.conf virtual.conf.back #先把基于proxy_moduel反向代理tomcat的配置文件禁用掉
再去启用/etc/httpd/conf/http.conf主配置文件中的中心主机,即启用“DocumentRoot /var/www/html”
[root@master conf.d]# vim mod_jk.conf LoadModule jk_module modules/mod_jk.so JkWorkersFile /etc/httpd/conf.d/workers.properties JkMountFile /etc/httpd/conf.d/uriworkermap.properties JkLogFile logs/mod_jk.log JkLogLevel warn #在调试时可设置为debug [root@master conf.d]# vim workers.properties worker.list=TomcatA,statA worker.TomcatA.host=192.168.0.201 worker.TomcatA.port=8009 worker.TomcatA.type=ajp13 worker.TomcatA.lbfactor=1 worker.statA.type=status [root@master conf.d]# vim uriworkermap.properties /*=TomcatA /jkstatus=statA
编辑tomcat主配置文件:
[root@master conf.d]# vim /usr/local/tomcat/conf/server.xml #在Engine中最后加上“jvmRoute=TomcatA” ...略......略... [root@master conf.d]# service httpd restart [root@master conf.d]# service tomcat restart
重启服务后,网站也可正常访问,但这里没有涉及到站点动静分离。
访问http://test.shopxx.com/jkstatus即可访问到监控界面,如下图:
4、总结
用apache来做反向代理后端的tomcat,有两种方案三种方式,一种方案是利用proxy_module模块,这种方案又支持http和ajp两种协议,而另一种方案是单独采用mode_jk连接器实现采用ajp协议与后端的tomcat进行连接。shopxx这个webapp有点诡异,在访问日志中老是会发现“/shopxx”这样开头的路径,但在“DocumentRoot”中已指定到了“/tomcat/webapps/shopxx”,所以在做动静分离时会有一定的困难,上边在用mode_jk做反向代理时我没有实现网站的动静分离,得再研究一下。