Apache+Tomcat+mod_jk实现负载均衡
最近公司提出了负载均衡的新需求,以减轻网站的高峰期的服务器负担。趁空闲时间我就准备了一下这方面的知识,都说有备无患嘛。网上相关资料很多,但是太散。我希望可以通过这篇随笔,系统的总结。
一、Tomcat集群对负载均衡可以用以下几种实现方式:
- proxy
- proxy_blancer
- mod_jk
二、proxy、proxy_blancer和mod_jk的优缺点比较:
proxy的缺点:当其中一台tomcat停止运行的时候,apache仍然会转发请求过去,导致502网关错误。但是只要服务器再启动就不存在这个问题。
mod_jk方式的优点:Apache 会自动检测到停止掉的tomcat,然后不再发请求过去。缺点:当停止掉的tomcat服务器再次启动的时候,Apache检测不到,仍然不会转发请求过去。
proxy和mod_jk的共同优点是:可以只将Apache置于公网,节省公网IP地址资源。可以通过设置来实现Apache专门负责处理静态网页,让Tomcat专门负责处理jsp和servlet等动态请求。共同缺点是:如果前置Apache代理服务器停止运行,所有集群服务将无法对外提供。
proxy和mod_jk对静态页面请求的处理,都可以通设置来选取一个尽可能优化的效果。
mod_proxy_balancer和mod_jk都需要修改tomcat的配置文件配合<Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcat1">
这三种Tomcat集群方式对实现最佳负载均衡都有一定不足,mod_proxy_balancer和mod_jk相对好些,mod_jk的设置能力更强些。lbfactor参数来分配请求任务。
apache自带mod_proxy功能模块中目前只可以实现两种不同的负载均衡集群实现方式,第一种是分工合作的的形式,通过各台主机负责不同的任务而实现任务分工。第二种是不同的机器在担任同样的任务,某台机器出现故障主机可以自动检测到将不会影响到客户端,而第一种却不能实现但第一种实现方式的优点在于他是主服务器负担相应没第二种大因为台只是提供跳转指路功能,形象的说他不给你带路只是告诉你有条路可以到,但到了那是否可以看到你见的人他已经不会去管你了。相比之下第二种性能要比第一种会好很多;但他们都有个共同点都是一托N形式来完成任务的所以你的主机性能一定要好。
本文的例子是利用ApacheHttpServer2.2+tomcat6+mod_jk做负载均衡。
一、准备工作:
1、下载相关软件包:
ApacheHttpServer
Tomcat6.rar(复制两份)
mod_jk.so(可以看做ApacheHttpServer的一个插件吧,用来给tomcat分流)
2、下载解压后的文件,复制到C盘根目录,如图:
说明:如果apache是安装版的安装到指定目录(我的例子安装在了C盘更目录),如果是解压版直接解压到指定目录就OK。
注意:不论是安装板还是解压版,在安装或解压后,必须在cmd命令窗口下安装apache服务。
在安装后的apache下的bin目录,在地址栏输入cmd进入命令窗口,输入httpd -k install 安装服务成功后,可根据以下命令进行操作:
- /*
- * 安装apache服务
- * 默认服务名称为apache+版本号
- * 如果想自定义服务名称可在该命令后加" -n 自定义服务名 "
- */
- httpd -k install
- /*
- *开启服务
- */
- httpd -k start
- /*
- *停止服务
- */
- httpd -k stop
- /*
- *重启服务
- */
- httpd -k restart
- /*
- *卸载服务
- */
- httpd -k uninstall
- /*
- *测试服务配置
- */
- httpd -t
- /*
- *服务版本详情
- */
- httpd -v
- /*
- *命令行选项卡
- */
- httpd -h
安装apache服务成功后,开启服务,在浏览器输入locahost,看到如下页面说明安装成功:
接下来,解压Tomcat,复制一份,一个命名为tomcat1,另一个命名为tomcat2。

3、把tomcat2中一个conf文件夹里的server.xml,将所有的端口号(port)开头的80全部改为90,下面红色框圈出的三处都要改。
3、在tomcat1中大约102行处,添加jvmRoute="tomcat1",在tomcat2中server.xml大约102行处,添加jvmRoute="tomcat2",如下:
- <!--tomcat1中添加-->
- <Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcat1">
- <!--tomcat2中添加-->
- <Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcat2">
4、在tomcat2中大约第107~108行插入以下代码。
在tomcat1的server.xml里也插入以下代码,更改<Receiver>里的port为4000,以保证两个tomcat<Receiver>端口不重复。
- <Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster" channelSendOptions="8">
- <Manager className="org.apache.catalina.ha.session.DeltaManager" expireSessionsOnShutdown="false" notifyListenersOnReplication="true"/>
- <Channel className="org.apache.catalina.tribes.group.GroupChannel">
- <Membership className="org.apache.catalina.tribes.membership.McastService" bind="127.0.0.1" address="228.0.0.4" port="45564" frequency="500" dropTime="3000"/>
- <Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver" address="127.0.0.1" port="4002" autoBind="100" selectorTimeout="5000" maxThreads="6"/>
- <Sender className="org.apache.catalina.tribes.transport.ReplicationTransmitter">
- <Transport className="org.apache.catalina.tribes.transport.nio.PooledParallelSender" timeout="60000" keepAliveCount="120000"/>
- </Sender>
- <Interceptor className="org.apache.catalina.tribes.group.interceptors.TcpFailureDetector"/>
- <Interceptor className="org.apache.catalina.tribes.group.interceptors.MessageDispatch15Interceptor"/>
- <Interceptor className="org.apache.catalina.tribes.group.interceptors.ThroughputInterceptor"/>
- </Channel>
- <Valve className="org.apache.catalina.ha.tcp.ReplicationValve" filter=""/>
- <Valve className="org.apache.catalina.ha.session.JvmRouteBinderValve"/>
- <ClusterListener className="org.apache.catalina.ha.session.JvmRouteSessionIDBinderListener"/>
- <ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener"/>
- </Cluster>
5、复制下载好的mod_jk.so连接模块到apache安装目录下的modules文件夹。
6、打开apache安装目录下的conf文件夹,新建mod_jk.conf文件,新建workers.properties文件
- mod_jk.conf文件内容如下:
- #加载mod_jk Module
- LoadModule jk_module modules/mod_jk.so
- #指定 workers.properties文件路径
- JkWorkersFile conf/workers.properties
- #指定那些请求交给tomcat处理,"controller"为在workers.propertise里指定的负载分配控制器
- JkMount /*.jsp controller
- #指定jk的日志输出文件
- JkLogFile logs/mod_jk.log
- #指定日志级别
- JkLogLevel info
- #查询日志格式
- JkLogStampFormat "[%a %b %d %H:%M:%S %Y]"
- #Jk请求日志格式
- JkRequestLogFormat "%w %V %T"
- workers.properties文件内容如下:
- #server 列表
- worker.list = controller,tomcat1,tomcat2
- #========tomcat1========
- #ajp13 端口号,在tomcat下server.xml配置,默认8009
- worker.tomcat1.port=8009
- #tomcat的主机地址,如不为本机,请填写ip地址
- worker.tomcat1.host=localhost
- #指定协议类型为AJP13定向包协议
- worker.tomcat1.type=ajp13
- #server的权重,值越高,分得的请求越多
- worker.tomcat1.lbfactor = 1
- #========tomcat2========
- #ajp13 端口号,在tomcat下server.xml配置,默认8009,这里我们刚才改的是9009
- worker.tomcat2.port=9009
- #tomcat的主机地址,如不为本机,请填写ip地址
- worker.tomcat2.host=localhost
- #指定协议类型为AJP13定向包协议
- worker.tomcat2.type=ajp13
- #server的权重,值越高,分得的请求越多
- worker.tomcat2.lbfactor = 1
- #========controller,负载均衡控制器========
- worker.controller.type=lb
- #指定分担请求的tomcat
- worker.controller.balance_workers=tomcat1,tomcat2
- #是否为设置为黏着session,设置为1或true使用粘着session,设置为0或false不使用粘着session
- worker.controller.sticky_session=false
- #是否强制黏着
- worker.controller.sticky_session_force=false
- #需要注意的地方
- # sticky_session sticky_session_force 含义
- # true false SESSION会复制,有粘性
- # true true SESSION不复制,有粘性
- # false false SESSION会复制,无粘性
- # false true SESSION会复制,无粘性
7、打开apache目录下的conf文件夹下的httpd.conf配置文件,在最下方添加以下代码:
- #加载mod_jk.conf文件
- Include conf/mod_jk.conf
8、ok,配置完毕!可以进行测试了。以下是测试步骤:
- 新建一个web项目命名为test
- 在该项目下新建test.jsp和WEB-INFO文件夹
- test.jsp内容:
- <%@ page contentType="text/html; charset=UTF-8" %>
- <%@ page import="java.util.*" %>
- <html>
- <head>
- <title>Apache2+Tomcat+mod_jk测试负载均衡</title>
- <style>
- html { color:#000; background:#F5F5F5; font-family:"微软雅黑","Microsoft YaHei","黑体","SimHei","宋体"; font-size:12px;}
- form{ font-size: 14px;}
- body{margin-left:300px;margin-right:auto;margin-top: 30px;}
- h3{display: inline;}
- input{ border: 1px solid #D3D3D3;width: 200px;height: 30px;margin-bottom: 10px;margin-top: 10px; text-indent: 10px;font-family: "微软雅黑";font-size: 14px;}
- .btn{ border: 1px solid #D3D3D3;border-radius: 15px;outline: 0;background: #DB6D4C;font-family: "微软雅黑";font-weight: bold;font-size: 12px;color: white;width: 100px;height: 30px; margin: 0 auto;}
- .btn:hover{background: #3A3A3A;}
- .content{ border: 1px solid #D3D3D3; margin: auto 10px; margin-bottom: 10px; width:500px;height:auto;padding:10 10 10 10 ;}
- table{ border: 1px solid #D3D3D3;margin: auto 10px;}
- td div{margin:10 10 10 10 ; float: left;}
- </style>
- </head>
- <body>
- <form action="http://localhost/test/test.jsp" method="POST">
- <table cellpadding="0" cellspacing="0">
- <tr>
- <td>
- <div>
- session名:<input type="text" size=20 name="dataName"placeholder="请输入session名"><br/>
- session值:<input type="text" size=20 name="dataValue"placeholder="请输入session值"><br>
- <input type="submit" value="点击提交" class="btn">
- </div>
- </td>
- </tr>
- </table>
- </form>
- <div class="content">
- <h3>请求地址:</h3>
- <% out.println(request.getLocalAddr() + " : " + request.getLocalPort()+"<br>");%>
- <%
- out.println("<br><h3>Session ID:</h3> " + session.getId()+"<br/>");
- // 如果有新的 Session 属性设置
- String dataName = request.getParameter("dataName");
- if (dataName != null && dataName.length() > 0) {
- String dataValue = request.getParameter("dataValue");
- session.setAttribute(dataName, dataValue);
- }
- out.println("<br/><h3>Session 列表:</h3><br>");
- System.out.println("=========================================");
- System.out.println("Tomcat print session Info:");
- out.println("------------------------------------------<br/>");
- Enumeration e = session.getAttributeNames();
- while (e.hasMoreElements()) {
- String name = (String)e.nextElement();
- String value = session.getAttribute(name).toString();
- out.println("SessionName:"+ name + " | SessionValue:" + value + "<br>");
- System.out.println("SessionName:" + name + " | SessionValue:" + value);
- }
- out.println("------------------------------------------<br/>");
- %>
- </div>
- </body>
- </html>
- <%@ page contentType="text/html; charset=UTF-8" %>
- 在WEB-INFO下新建web.xml文件复制test项目到tomcat1、tomcat2文件夹的wabapp下分别部署
- web.xml内容:
- <?xml version="1.0" encoding="UTF-8"?>
- <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns="http://java.sun.com/xml/ns/javaee"
- xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
- xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
- <display-name>test</display-name>
- <distributable/>
- </web-app>
- <?xml version="1.0" encoding="UTF-8"?>
- web.xml内容:
- 依次启动apache、tomcat1、tomcat2;在浏览器输入http://localhost/test/test.jsp按页面填写数据、刷新浏览器、宕掉其中一个节点等测试,观察页面信息和tomcat后台打印信息进行测试!
- 测试页面如下:
好了,这篇随笔就介绍到这里,欢迎大家多多批评,有不足之处还望各位前辈斧正!
Apache+Tomcat+mod_jk实现负载均衡的更多相关文章
- Apache + Tomcat集群 + 负载均衡
Part I: 取经处: http://www.ramkitech.com/2012/10/tomcat-clustering-series-simple-load.html http://blog ...
- Linux中Apache+Tomcat+JK实现负载均衡和群集的完整过程
人原创,一个字一个字地码的,尊重版权,转载请注明出处! http://blog.csdn.net/chaijunkun/article/details/6987443 最近在开发的项目需要承受很高的并 ...
- ngnix apache tomcat集群负载均衡配置
http://w.gdu.me/wiki/Java/tomcat_cluster.html 参考: Tomcat与Apache或Nginx的集群负载均衡设置: http://huangrs.blog. ...
- Apache + Tomcat + mod_jk实现集群服务及session共享
实现效果:用apache 分发请求到tomcat中的对应的项目 原理:
- 2.Apache + Tomcat + mod_jk实现集群服务
转自:http://www.cnblogs.com/dennisit/p/3370220.html Tomcat中的集群原理是通过组播的方式进行节点的查找并使用TCP连接进行会话的复制. 实现效果:用 ...
- 搭建nginx+tomcat+Java的负载均衡环境
转载 未测 供参考 另外这篇文章也不错.http://blog.csdn.net/wang379275614/article/details/47778201 一.简介: Tomcat在高并发环境下 ...
- 【转】搭建nginx+tomcat+Java的负载均衡环境
一.简介: Tomcat在高并发环境下处理动态请求时性能很低,而在处理静态页面更加脆弱.虽然Tomcat的最新版本支持epoll,但是通过Nginx来处理静态页面要比通过Tomcat处理在性能方面好很 ...
- Nginx+Tomcat+Redis实现负载均衡、资源分离、session共享
Nginx+Tomcat+Redis实现负载均衡.资源分离.session共享 CentOS安装Nginx http://centoscn.com/CentosServer/www/2013/0910 ...
- Apache+Tomcat+mod_jk配置教程
0.说明 首先我们要弄明白mod_jk的作用是反向代理,而其实使用httpd.conf中的<VirtualHost>标签就可以实现反向代理,为什么还要多搞个mod_jk那么麻烦做反向代理. ...
随机推荐
- [百家号]华为:最强ARM服务器芯片,华为鲲鹏920处理器发布
华为:最强ARM服务器芯片,华为鲲鹏920处理器发布 泡泡网 百家号2019-01-0716:11 https://baijiahao.baidu.com/s?id=162198839753232 ...
- Windows 2019 下安装Oracle18c
1. 跟之前版本不一样 与linux 的版本一样 18c的DB 端的安装有区别. 首先需要 创建一个oracle的目录. 这里最简单的方法是 参照12c的目录来 创建 比如我创建的 然后将 db_ho ...
- no-referrer-when-downgrade什么意思
no referrer when downgrade的意思:降级时不推荐. 从一个网站链接到另外一个网站会产生新的http请求,referrer是http请求中表示来源的字段. no-referrer ...
- 洛谷SP16580 QTREE7 - Query on a tree VII(LCT,multiset)
洛谷题目传送门 思路分析 维护子树最值还是第一次写QwQ 因为子树的最值会变化,所以不能简单地把最值记下来,还要维护一个平衡树,把每个子树的最大值扔进去,来资磁插入.删除和查询最值. 然后我就懒得手写 ...
- HGOI20181029模拟题解
HGOI20181029模拟题解 /* sxn让我一定要谴责一下出题人和他的数据! */ problem: 给出十进制数a,b,然后令(R)10=(a)10*(b)10,给出c表示一个k进制数(1&l ...
- 进程和线程(4)-进程 vs. 线程
进程 vs. 线程 我们介绍了多进程和多线程,这是实现多任务最常用的两种方式.现在,我们来讨论一下这两种方式的优缺点. 首先,要实现多任务,通常我们会设计Master-Worker模式,Master负 ...
- Mysql(二)函数与连接
一.函数 1.if函数 if(exp1, exp2, exp3) 判断exp1是否为true(不为0,并且不为nlll),如果为true,返回 exp2的值,否则返回exp3的值. selec ...
- POJ 3268 Silver Cow Party (最短路径)
POJ 3268 Silver Cow Party (最短路径) Description One cow from each of N farms (1 ≤ N ≤ 1000) convenientl ...
- JDK自带线程池介绍及使用环境
1.newFixedThreadPool创建一个指定工作线程数量的线程池.每当提交一个任务就创建一个工作线程,如果工作线程数量达到线程池初始的最大数,则将提交的任务存入到池队列中. 2.newCach ...
- 浅谈使用NIO,AIO的感受
花了十多天的时间把原来的WEB服务由BIO(阻塞IO)模式改写成NIO(非阻塞IO)模式,然后在xp机子上用ab测试并发性能,确实提升了30%左右的并发性能,测试完成后,当时感觉还是挺满意的.几天前在 ...