zoukankan      html  css  js  c++  java
  • Apache Tomcat AJP 实现负载均衡

    大部分一开始接触WEB服务器的人可能和我一样对为什么有Apache又有Tomcat服务器感到奇怪(它们还都是Apache开发的呵呵),其实他们不是冗余的服务器,虽然他们都能对外提供WEB服务器,但总的来说还是各有侧重点。下面做个简单介绍。

     

    1.       Apache是世界排名第一的Web服务器;在Apache基金会里其永远被第一支持。而开源的Apache Tomcat也非常关注,由于开源,用户最支持。

    2.       Apache支持静态页面,Tomcat支持动态页面(servlet, JSP);一般在使用Apache + Tomcat的配置下,Apache都是实现对JSP的转发,交给Tomcat来处理。Apache可以支持PHP,但如果要支持JAVA,就需要Tomcat来处理。

    3.       Apache是Web服务器,Tomcat是应用(Java)服务器,它只是一个servlet容器,是Apache的扩展,但可以独立于Apache运行;如果以独立方式运行,功能与Apache等效,但对静态页面的处理不太理想。

    通过上面分析,可以知道:

    1.       Apache能有很好的静态页面处理能力,如果搭配Tomcat能同时支持静态和动态页面

    2.       Tomcat能够承担性能要求较低的WEB应用。

    负载均衡

     

    为了提高整个系统的可用性和性能,常常会用到负载均衡,而Apache和Tomcat经常联合在一起来实现负载均衡技术。

    主机Apache作为前段负载平衡服务器对用户进行分配,后端不同的Tomcat服务器最终处理请求,其中根据侧重点不同可以有两种不同的配置。

    1.       增加系统可用性

    保证多台Tomcat服务器之间会话的同步,确保任何一台当机都不会影响系统的运行,从而提高系统的可用性。

    2.       提高系统性能

    在负责负载平衡的Apache主机上记录每个请求的Session ID(这个ID是由Tomcat分配的)及回应Session的Tomcat Server对应关系,在下一个请求到来时先判断每个Session ID,如果有标识连接已经建立,那么转到对应服务器;负责就是新的连接,根据每个后台Tomcat服务器的状态分配一个服务器并记录Session ID.

    如下图:



    Apache + Tomcat配置

    正如上面中看到的可以通过Apache +Tomcat来配置来达到较高WEB服务器同时,也能高正较高的可用性和系统性能。这些是通过Apache与Tomcat之间的通讯来完成的。Apache和Tomcat之间的通讯基本有三种方式:

    1.       Mod_Jk

    2.       HTTP_Proxy

    3.       AJP_Proxy

    这里主要介绍Mod_JK方式,其也是最流行的方式,并且官方的文档也非常全。

    Mod_JK

    Mod_JK是Apache的一个模块,其通过AJP协议实现Apache与Tomcat之间的通讯,而Tomcat默认监听AJP连接器的8009端口来接受AJP的连接请求;一般这些请求来自前端的Apache服务器。

    由于Mod_JK已经被设计成Apache的一个模块,因此可以通过一些相对简单的配置就能达到Apache和Tomcat之间通讯的目的;同样包含负载均衡。

    配置步骤安装

    1.       安装Apache HTTP服务器,从Apache官方网站下载;我安装的是Apache2.0.64

    2.       安装Apache Tomcat,可以安装在Apache同一个机器,也可以在其他的机器,版本要与Mod_JK匹配

    3.       下载Mod_Jk;这里注意要与Apache Tomcat匹配。

    配置加在Mod_Jk

    Mod_Jk是在Apache HTTP服务器上被加载的,需要将下载下来的Mod_Jk.so放到Apache/Modules目录下,并修改httpd.conf,增加下面一行:

    Include conf/mod_jk.conf

     

    使用include命令包含mod_jk.conf,这个是我们自己添加的关于mod_jk的配置文件。

     

    新建Mod_jk.conf,并添加如下内容:

    #Load mod_jk module.

    LoadModule jk_module modules/mod_jk.so

     

    #Where to find workers.properties

    JkWorkersFile conf/workers2.properties

    JkMountFile conf/urimap.properties

     

    #Where to put jk logs

    JkLogFile logs/mod_jk.log

     

    #Set the jk log level[debug/error/info]

    JkLogLevel info

     

    #Select the log format

    JkLogStampFormat "[%a %b %d %H:%M:%S %Y]"

     

    #JkRequestLogFormat set the request format

    JkRequestLogFormat "%w %V %T"

     

    JkMount /* loadbalancer

     

    上面包含了两个properties文件,分别是workers2.properties和urimap.properties。

    Workers2.properties用于说明Tomcat服务器的负载均衡配置方法,具体如下:#worker.list=loadbalancer

    worker.list=loadbalancer,tomcat1,tomcat2  #server 列表

     

    #define the first node

    worker.tomcat1.port=8009

    worker.tomcat1.host=10.224.70.57

    worker.tomcat1.type=ajp13

    worker.tomcat1.lbfactor=1

     

    #define the first node

    worker.tomcat2.port=8009

    worker.tomcat2.host=10.224.70.57

    worker.tomcat2.type=ajp13

    worker.tomcat2.lbfactor=1

     

    #Now we define the load-balancing behavior

    worker.loadbalancer.type=lb

    worker.loadbalancer.balance_workers=tomcat1, tomcat2

     

    worker.loadbalancer.sticky_session=true

     

    worker.loadbalancer.sticky_session_force=true

    在Mod_jk.conf中有JkMount /* loadbalancer,这个loadbalancer正好对应上面worker.list一行的loadbalancer。

    另外tomcat1和tomcat2是配置的后台tomcat服务器;当然这里只有一台服务器,所以两个worker都是同样的地址。lbfactor表示在负载均衡算法中采用的权重。

     

    另外在urimap.properties文件中说明了哪些请求会转交给Tomcat服务器,配置项为:

    !/*.htm=loadbalancer

    注意这里的表示*.htm的请求都到loadbalancer;这个loadbalancer是上文中的loadbalancer。

    至此Apache和Tomcat之间的负载均衡已经被配置好了。

     

    运行时观察

    这里主要观察session的stickiness是如何被实现的;已经Apache服务器如何了解到关于Session ID相关的信息。
    实际上对于负载均衡来说,如果上面的例子中你配置了两个Tomcat,那么关闭sticky_session的情况下,每个Tomcat服务器将轮流收到请求。

     

    其实在试验的时候发现session ID是Tomcat服务器分配创建的,Apache服务器只是用来管理其与Tomcat服务器之间的关系;当然Apache服务器需要检查每次请求中的Session ID。这个ID是由Tomcat分配的;Tomcat对于每个第一次请求的动态页面都会生成JSESSIONID;而对于静态页面是不会生成JESSIONID的。

    具体运行过程:

    1.       Apache服务器接收到来自client的请求,检查HTTP请求是否包含SESSIONID

    2.       如果不包含,采用负载均衡算法选择一个Tomcat服务器

    3.       Apache服务器将这个client请求转发到选定Tomcat服务器的8009端口,数据包的格式是AJP协议

    4.       Tomcat解析AJP协议,生成SESSION ID并且取得响应,将结果发送给Apache服务器,这个是通过之前的8009连接过来的链接发送回去的。

    5.       Apache服务器解析AJP包,并得到SESSION ID信息,并将其与对应的服务器(和会话)关联起来。

    6.       Apache将SESSION ID转发给client

    7.       Client将Session ID保存到Cookie中用于下次使用。

    Packet No

    Apache

    Tomcat:8009

    1

    2:REQ:GET /index.jsp HTTP/1.1 à

     

    2

     

    ß2:RSP:send headers:200 OK

    3

     

    ß2:RSP:SEND BODY CHUNK

    4

     

    ß2:RSP:END RESPONSE

     

    通常这个连接建立好了之后短时间是不会断,不过这是可以通过参数来配置的。

    在上面的包交互过程中:第2个包包含了SESSION ID的信息;内容类似于下面:

    Set-Cookie..3JSESSIONID=955AAE2AA22B074BD1824395B6E4835A; Path=/...Content-Type...text/html...Content-Length...141.AB.....

    AJP(Apache JServer Protocol)

    AJPv13协议是面向包的。WEB服务器和Servlet容器通过TCP连接来交互;为了节省SOCKET创建的昂贵代价,WEB服务器会尝试维护一个永久TCP连接到servlet容器,并且在多个请求和响应周期过程会重用连接。

    一旦一个连接被分配给特定的请求,在请求处理周期结束之前这个连接不能被重用;换句话说,请求不是连接多工的。这样编码比较简单。

    一旦连接被分配给特定的请求,基本请求信息(HTTP头)以压缩的个性(通常字符串会编码为整数);如果有请求实体,会随后立即发送。

    这个时候,servlet容器已经准备好了处理请求并发送西面的信息回WEB服务器:

    1.       SEND_HEADERS:发回浏览器的响应头

    2.       SEND_BODY_CHUNK:将实体发送给浏览器

    3.       GET_BODY_CHUNK:获取更多的请求数据,这些数据没有被发送。

    4.       END_RESPONSE:表示请求处理周期结束。

     

    WEB服务器发送给Servlet容器的请求包括:

    1.       转发请求开始

    2.       关闭

    3.       Ping

    4.       CPing

     

    AJP13_FORWARD_REQUEST的格式

    AJP13_FORWARD_REQUEST :=

        Magic:            (word)

        Length:           (word)

        prefix_code      (byte) 0x02 = JK_AJP13_FORWARD_REQUEST

        method           (byte)       HTTP请求方法的字节编码

        protocol         (string)

        req_uri          (string)

        remote_addr      (string)

        remote_host      (string)

        server_name      (string)

        server_port      (integer)

        is_ssl           (boolean)

        num_headers      (integer)

        request_headers *(req_header_name req_header_value)

        attributes      *(attribut_name attribute_value)

        request_terminator (byte) OxFF

    AJP13_SEND_HEADERSAJP13_SEND_HEADERS :=  prefix_code       4  http_status_code  (integer)  http_status_msg   (string)  num_headers       (integer)  response_headers *(res_header_name header_value) 

    更多信息,参见:http://tomcat.apache.org/connectors-doc/ajp/ajpv13a.html#header_encoding

  • 相关阅读:
    Binary Search Tree Iterator 解答
    Invert Binary Tree 解答
    Min Stack 解答
    Trapping Raining Water 解答
    Candy 解答
    Jump Game II 解答
    Implement Hash Map Using Primitive Types
    Gas Station 解答
    Bucket Sort
    HashMap 专题
  • 原文地址:https://www.cnblogs.com/daichangya/p/12958735.html
Copyright © 2011-2022 走看看