Apache + Tomcat +mod_jk- win7与linux下实现负载均衡与集群-

来源:互联网 发布:你遇到尴尬的事 知乎 编辑:程序博客网 时间:2024/05/17 22:38

本文作者:陈超允chenchaoyun0

写在前面的知识:

1、关于mod_jk

mod_jk简称JK,是Apache服务器的一个可插入模块,用于为Apache服务器提供处理JSP/SERVLET的能力。Apache作为一个很强大的Web服

务器,本身缺乏处理JSP/SERVLET的能力,为了能够处理对JSP/SERVLET的请求,必须使用JSP/SERVLET容器,如Tomcat等。Tomcat本身

也可以作为Web服务器使用,但是他的能够远不及Apache强大,所以Tomcat往往作为JSP/SERVLET等容器的使用。mod_jk实质上是Apache与

Tomcat的连接器,并附带提供了集群和负载均衡的功能。

2、apache安装包中的“no ssl”和“openssl”是什么意思?

openSSL是表示带有OpenSSL模块,利用OpenSSL就可以给Apache配置SSL安全链接的,也就是使用https://方式进行访问;no ssl则表示不带

OpenSSL模块,无法用于SSL安全链接。Tomcat中的集群原理是通过组播的方式进行节点的查找并使用TCP连接进行会话的复制。实现效果:

用Apache分发请求到tomcat中对应的项目

操作环境:

操作系统:win7、虚拟机ubuntu15.04

jdk:1.7

Apache:2.2.22-下载地址:http://httpd.apache.org/download.cgi

Tomcat:7.0.67-选择自己的版本即可,我在本机上模拟展示3个节点

Mod_jk:1.2.40-这个很重要,一定要选择对自己的版本,不然apache启动不了。下载地

址:http://mirror.bjtu.edu.cn/apache/tomcat/tomcat-connectors/jk/binaries/windows/




安装步骤:

1、安装JDK,这不用说了吧,必须的。

2、安装Apache,使用默认配置,并且在安装路径中不要空格。我的是D:\Apache2.2

3、解压Tomcat-分别命名:tomcat-node1、tomcat-node2、tomcat-ubuntu(这是在虚拟上的一个tomcat,没有的话两个就可以了,我是放在D盘)

4、拷贝下载的mod_jk.so到Apache安装目录下的modules文件夹下。


配置步骤:

1、修改Apache配置文件httpd.conf(我的路径是:C:\Apache2.2\conf\httpd.conf),在最后一行默认添加:

[csharp] view plain copy
  1. include "C:\Apache2.2\conf\mod_jk.conf"  

2、在httpd.conf同目录新建mod_jk.conf,并添加以下内容:

[csharp] view plain copy
  1. #加载mod_jk Module   
[csharp] view plain copy
  1. LoadModule jk_module modules/mod_jk-1.2.31-httpd-2.2.3.so<span style="font-family: Arial, Helvetica, sans-serif;">#指定 workers.properties文件路径</span>  
[csharp] view plain copy
  1. JkWorkersFile conf/workers.properties  
[csharp] view plain copy
  1. #指定哪些请求交给tomcat处理,"controller"为在workers.propertise里指定的负载分配控制器名  
[csharp] view plain copy
  1. JkMount /* controller  


3、在httpd.conf同目录新建workers.properties

[csharp] view plain copy
  1. #这里可以配置任意多个Tomcat,此处配置了2个Tomat服务器.  
  2. #host和port根据自己实际配置.实例配置的是本机两个tomcat,分别使用不同的端口.避免冲突  
  3. #如果Tomcat不再同一机器上,没必要改端口的。  
  4.  
  5.  
  6.  
  7.  
  8. #server 列表  
  9. worker.list=controller,tomcat1,tomcat2,tomcat3,tomcat4  
  10.  
  11.  
  12.  
  13.  
  14. #========tomcat1========  
  15.   
  16.   
  17. worker.tomcat1.port=8888       #ajp13 端口号,在tomcat下server.xml配置,默认8009  
  18. worker.tomcat1.host=localhost        #tomcat的主机地址,如不为本机,请填写ip地址  
  19. worker.tomcat1.type=ajp13  
  20. worker.tomcat1.lbfactor=1        #server的加权比重,值越高,分得的请求越多  
  21.  
  22.  
  23. #========tomcat2========  
  24.   
  25.   
  26. worker.tomcat2.port=9999        #ajp13 端口号,在tomcat下server.xml配置,默认8009  
  27. worker.tomcat2.host=localhost        #tomcat的主机地址,如不为本机,请填写ip地址  
  28. worker.tomcat2.type=ajp13  
  29. worker.tomcat2.lbfactor=1        #server的加权比重,值越高,分得的请求越多   
  30.  
  31.  
  32. #========tomcat3========  
  33.  
  34.  
  35. #worker.tomcat3.port=7777   #ajp13 端口号,在tomcat下server.xml配置,默认8009  
  36. #worker.tomcat3.host=192.168.0.45  #tomcat的主机地址,如不为本机,请填写ip地址  
  37. #worker.tomcat3.type=ajp13#这是在局域网下另一台机器的配置  
  38. #worker.tomcat3.lbfactor=1       #server的加权比重,值越高,分得的请求越多   
  39.  
  40.  
  41. #========tomcat4========  
  42.   
  43.   
  44. worker.tomcat4.port=8787   #ajp13 端口号,在tomcat下server.xml配置,默认8009  
  45. worker.tomcat4.host=192.168.0.124   #tomcat的主机地址,如不为本机,请填写ip地址  
  46. worker.tomcat4.type=ajp13#这是在ubuntu下的配置  
  47.   
  48. worker.tomcat4.lbfactor=1#server的加权比重,值越高,分得的请求越多   
  49.  
  50. #========controller,负载均衡控制器========  
  51. worker.controller.type=lb  
  52.  
  53.  
  54.  
  55.  
  56. #指定此负载平衡器负责的Tomcat应用节点。  
  57.   
  58.   
  59. worker.controller.balanced_workers=tomcat1,tomcat2,tomcat3,tomcat4#指定分担请求的tomcat  
  60.  
  61.  
  62. #此处指定集群是否需要会话复制,如果设为true,则表明为会话粘性,不进行会话复制,当某用户的请求第一次分发到哪台  
  63. #Tomcat后,后继的请求会一直分发到此Tomcat服务器上处理;如果设为false,则表明需求会话复制。  
  64.  
  65.  
  66. #worker.controller.sticky_session=false    #设为false,则表明需求会话复制。  
  67.   
  68.   
  69. worker.controller.sticky_session=0    #  
  70. worker.controller.sticky_session_force=1  #这里session黏性与session复制  




Tomcat配置:

说明:如果修改了tomcat配置文件,最好将文件编码转换成UTF-8,我这里两个在win7下,还有一个在虚拟机里的ubuntu下

因为实例中我们定义了两个tomcat处理分发,所以我们将tomcat的解压版本格式复制一份。Tomcat6和tomcat7的配置方式一样,下面是两个没修改前一样的tomcat。

以tomcat_node1为例:

1、修改分发tomcat对应的service.xml文件,保证Apache对应的workers.properties中的AJP13的connector的port。

[csharp] view plain copy
  1. <!--定义一个AJP 1.3 连接端口为888 ,默认值为8009,这里我们改成我们自己定义的9988端口 -->  
[csharp] view plain copy
  1. <Connector port="8888" protocol="AJP/1.3" redirectPort="8443" />  

2、增加jvmRoute的值,保证同worders.properties里面的配置一致。

[csharp] view plain copy
  1. <!--增加jvmRoute,值为在Apache中配置的list集群结点中的值,这里定义为tomcat1结点-->  
  2. <Engine name="Catalina"defaultHost="localhost"jvmRoute="tomcat1">  

3、去掉默认注释掉的集群配置

[csharp] view plain copy
  1. <!--取消集群结点相关的注释,该句默认值注释掉的,我们需要配置集群所以去掉注释,让其起作用-->  
  2. <Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/>  

如果我们的tomcat节点分布在不同机器上,那么我们的集群至此已经配置完成。去掉多余注释,显示做了修改的部位。修改前的tomcat-node1:

[csharp] view plain copy
  1. <!--Define an AJP 1.3 Connector on port 8009 -->  
  2. <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />  
  3. <!--You should set jvmRoute to support load-balancing via AJP ie :<Engine name="Catalina" defaultHost="localhost" jvmRoute="jvm1">-->  
  4. <Engine name="Catalina" defaultHost="localhost">  
  5. <!--For clustering-->  
  6. <!--   <Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/>-->  

修改后的tomcat-node1

[csharp] view plain copy
  1. <!--定义一个AJP 1.3 连接端口为9988 ,默认值为8009,这里我们改成我们自己定义的9988端口 -->  
  2. <Connector port="8888" protocol="AJP/1.3" redirectPort="8443" />  
  3. <!--增加jvmRoute,值为在Apache中配置的list集群结点中的值,这里定义为tomcat1结点-->  
  4.  <Engine name="Catalina" defaultHost="localhost"  jvmRoute="tomcat1">  
  5. <!--取消集群结点相关的注释,该句默认值注释掉的,我们需要配置集群所以去掉注释,让其起作用-->    
  6. <Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/>  

修改后的tomcat-node2

[csharp] view plain copy
  1. <!--Define an AJP 1.3 Connector on port 8009 -->  
  2. <Connector port="9999" protocol="AJP/1.3" redirectPort="8443" />  
  3. <!--You should set jvmRoute to support load-balancing via AJP ie :  
  4. <Engine name="Catalina" defaultHost="localhost" jvmRoute="jvm1">-->  
  5. <Engine name="Catalina" defaultHost="localhost"  jvmRoute="tomcat2">  
  6. <!--For clustering-->  
  7. <Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/>  


修改后的tomcat-ubuntu

说明:这里的protocol=”AJP/1.3”,连接以及jvmRoute需要保证同我们Apache服务器中配置的works.properties一致。修改完后最好将service.xml文件的编码方式设置为utf-8。否则可能tomcat启动报错。

4、实例中我们的两个tomcat节点在同一台机器上,所以我们还需要保证protocol=”HTTP/1.1”的端口不一致,不然本地的两个tomcat会起冲突。

下面是本实例中解决同一台机器上多个tomcat服务器之间端口冲突做的修改:

图片参考至 http://www.tuicool.com/articles/feABvu

Tomcat-node2做的修改

[java] view plain copy
  1. <pre name="code" class="html"><Server port="9995" shutdown="SHUTDOWN">  
  2. <!--…略…-->  
  3. <Connector port="9990"   
  4. protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />  
  5. <!--…略…-->  

说明:这里的protocol=”HTTP/1.1”配置相关端口之间不能冲突,而且也不能同本机其他应用程序占用的端口冲突,否则可能

报错。

测试:

1、需要注意的是,项目的实体类需要实现serializable接口,

(1)当你想把的内存中的对象状态保存到一个文件中或者数据库中时候;
(2)当你想用套接字在网络上传送对象的时候; java对象序列化不仅保留一个对象的数据,而且递归保存对象引用的每个对            象的数据。可以将整个对象层次写入字节流中,可以保存在文件中或在网络连接上传递。利用对象序列化可以进行对象            的"深复制",即复制对象本身及引用的对象本身。序列化一个对象可能得到整个对象序列。
(3)当你想通过RMI传输对象的时候; RMI要利用对象序列化运行远程主机上的服务,就像在本地机上运行对象时一样。在            创建的WEB工程的web.xml文件中增加

[html] view plain copy
  1. <distributable/>  

2、修改工程中index.jsp页面的代码,修改的结果如下:

[html] view plain copy
  1. <%@ page contentType="text/html; charset=gbk"%>  
  2. <%@ page import="java.util.*"%>  
  3. <html>  
  4. <head>  
  5. <title>Cluster App Test</title>  
  6. </head>  
  7. <body>  
  8.     Server Info:  
  9.     <%  
  10.     out.println(request.getLocalAddr() + " : " + request.getLocalPort()  
  11.             + "<br>");  
  12.     %>  
  13.     <%  
  14.         out.println("<br> ID " + session.getId() + "<br>");  
  15.         // 如果有新的 Session 属性设置  
  16.         String dataName = request.getParameter("dataName");  
  17.         if (dataName != null && dataName.length() > 0) {  
  18.             String dataValue = request.getParameter("dataValue");  
  19.             session.setAttribute(dataName, dataValue);  
  20.         }  
  21.         out.println("<b>Session 列表</b><br>");  
  22.         System.out.println("============================");  
  23.         Enumeration e = session.getAttributeNames();  
  24.         while (e.hasMoreElements()) {  
  25.             String name = (String) e.nextElement();  
  26.             String value = session.getAttribute(name).toString();  
  27.             out.println(name + " = " + value + "<br>");  
  28.             System.out.println(name + " = " + value);  
  29.         }  
  30.     %>  
  31.       
  32. </body></html>  



3、测试负载均衡与session分发

将项目部署到每个集群节点中,即实例中的tomcat_node1和tomcat_node2,依次启动Apache,和Tomcat服务器,两个Tomcat服务器的启动顺序随意。这里Apache的端口使用安装的时候选择的8080.


这是tomcat1的


这是tomcat2的



这是在ubuntu里的



相信都能看出来,这两个sesssion斌不一样。

下面说说session的复制问题


关于session的复制讨论

sticky_session           sticky_session_force           结论

0                                   0                                            session无黏性,session会复制

0                                   1                                            session无黏性,session会复制

1                                   0                                            session有粘性(非强制)session会复制

1                                   1                                            session有粘性(强制)session没必要再复制(此处有争议,待深入研究

常见问题:

1、  如果同一台机器上的节点之间session能够同步,但是不同机器间的session无法同步,可能的原因是机器间的时钟不同步,需要进行同步操作。

2、  关于Cluster
此实验中对Cluster的配置如下:
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/>
其实这只是对Cluster的最简单的一种配置,该配置下tomcat使用的是all-to-all方式的session同步,这种方式只适用于小规模的集群。文章开头列举了三种session同步策略,all-to-all属于第二种,tomcat也支持第三种,只需为Cluster配置BackupManager即可

3、  关于jvmRoute
前面实验中的sessionid由两部分组成(前缀+后缀),而其后缀名就是jvmRoute配置的名称,mod_jk需要根据这个后缀名进行请求转发:当sticky_session=1时,mod_jk根据这个后缀名来判断该会话应该始终由哪个tomcat进行处理。

总结:


worker.controller.sticky_session=false,提交页面,将按照负载均衡的规则切换服务器,实现“完全的负载均衡”,代价是
Tomcat不停交换session数据,慢;
worker.controller.sticky_session=true,提交页面将仍使用同一服务器(session建立在哪就用哪台),不能保证完完全全的负
载均衡,但相对能省频繁切换服务器的代价。可能会变上面的快一些。
worker.controller.sticky_session_force=true,始终转发到session创建的服务器上。

我一直很纠结这个,如果说sticky_session=true的话,一个浏览器的请求就都是由一个tomcat去处理。=false的话,就按照负

载均衡去处理但是这个就得tomcat间一直来回复制会话了,性能上也有损失吧。我觉得session不复制是不是应该好一些,不

然如果很多用户登录了,session就得在多个tomcat间来回复制了。sticky_session=true的话,不进行session复制,按照用户

浏览器去实现负载均衡,这样应该好一点~~~其实好像就是,一个是按照请求去负载均衡,就必须得来回复制会话;另一个是

按照用户浏览器去实现的负载均衡,那就不需要了。应该是后者,一开始理解错了 ,现在改成1,0测试。




但结果并非那么乐观,还是一样,可能是因为不同的机子而session不一样。日后找到解决的办法再来补充

参考文档:http://www.tuicool.com/articles/feABvu 、http://blog.csdn.net/lubiaopan/article/details/8936443


阅读全文
0 0
原创粉丝点击