一. 负载均衡:根据 uri 表达式把请求分发给各个服务器处理。如:/*.jsp = lb_s 就是说把所有jsp请求交给lb_s , 当然它是个Tomcat。
二. 安装配置mod_jk
mod_jk模块的总体功能
由于tomcat的HTTP处理部分都由Java所写(5.5.12版本以后出现了native库,用以提高其I/O和SSL的性能[1]),在高并发的情况下负载较高。而apache对于静态文件的处理能力比tomcat强,所以tomcat开发组开发了与apache结合使用的mod_jk模块。该协议由apache作请求代理,将HTTP协议的请求转化为AJP协议包,并传给后端的tomcat。mod_jk和apache现在普遍使用AJP1.3协议[2]。它是一个二进制格式的协议,比字符格式的HTTP协议解析速度要快。除了性能的提升,mod_jk另外的一个作用可以实现apache与tomcat一对多的对应,使后端tomcat负载均衡。mod_jk也提供apache与tomcat链接情况的监控。mod_jk模块的典型工作流程是这样的:一个HTTP请求过来,mod_jk模块根据其URI选择合适的worker来进行处理。如果是lb_worker(负载均衡的worker),就再根据各种条件选择后台合适的ajp_worker(处理AJP协议的worker)。ajp_worker将HTTP协议的包,组装成AJP协议格式的包,然后选取一条空闲的链接,发送给后台的tomcat服务器。等到后台将数据发送过来时,接收并解析AJP协议,重新组装成HTTP协议,然后把结果发送给客户端。
mod_jk模块的框架2.1
线程从宏观上来讲,mod_jk由一个watchdog线程和一组worker线程(进程)组成。watchdog线程是在apache内部新创建的线程,它是一个维护线程。每隔JkWatchdogInterval的时间(当然,所有worker线程也有一个统一的worker.maintain 时间,JkWatchdogInterval应该至少大于worker.maintain),它会扫描所有worker线程。watchdog线程会检查每个worker线程的空闲链接、负载情况、与后端的链接情况,并使共享内存同步。worker线程是就是一些ajp13,ajp14,jni,lb或status类型的线程,负责所有实际的工作。在mod_jk中,线程内(外)的同步均是通过线程锁(pthread_mutex_lock)来实现的。而进程之间的全局同步,是用文件记录锁(flock或fcntl)来实现。进程间的数据共享是用这样做的:进程启动时,创建一个JkShmSize 大小的文件,然后mmap到内存,由于各进程mmap到内存的是相同的镜像,所以可以实现数据的共享,但是写入共享内存时,要做好互斥。由于apache的基本处理方式(prefork和worker模式)就是一个线程/进程负责一个连接,所以mod_jk各线程中对于网络IO处理都是阻塞的。
2.2 worker对象
从具体的worker对象的角度来讲,mod_jk由ajp_worker、jni_worker、lb_worker和status_worker组成。这些对象参考了设计模式中factory的模型。每类worker都有生产workers的factory。在mod_jk中,其中的worker主要在worker.list中列出。其中,lb_worker可以含有balance_workers,以lb_sub_worker的形式存储于lb_worker中。lb_sub_worker可以是各种类型的ajp_worker。所以真正工作的ajp_worker既可以“单干”,也可以由lb_worker来分配任务。这主要取决于URI到底映射到哪个worker上以及该worker是否在worker.list配置。lb_worker,lb_sub_worker和ajp_worker一些配置信息都位于其结构体中,而状态信息或在运行中可变的参数则位于共享内存中的对应结构体中,当然也并不绝对,有些参数是冗余的。从正在运行的某个线程的角度上来讲,ajp_worker就是对应了一个线程
[root@web-server ~]# wget http://mirror.bit.edu.cn/apache/tomcat/tomcat-connectors/jk/tomcat-connectors-1.2.42-src.tar.gz
[root@web-server ~]#tar zxf tomcat-connectors-1.2.-src.tar.gz
[root@web-server ~]#cd tomcat-connectors-1.2.-src/native/
[root@web-server ~native]#./configure --with-apxs=/usr/sbin/apxs //如果找不到路径;请 httpd-devel
[root@web-server ~]#make && make install
三.复制到apache的modules
把 native/apache-2.0中到mod_jk.so 拷贝到 /usr/lib64/httpd/modules ;没错Apache的库改了;64位软件到库都是放在/usr/Lib64的;如果是6.3版本,或者不是用yum安装的apache,则是/usr/local/apache2/modules
.
[root@web-server ~]# cp apache-2.0/mod_jk.so /usr/lib64/httpd/modules/
修改http.conf
[root@web-server conf]# cat httpd.conf | grep Include
Include conf.d/*.conf
Include conf/mod_jk.conf
在apache conf目录下新建modules
touch /etc/httpd/conf/mod_jk.conf
#加载moldules下mod_jk.so文件
loadModule jk_module modules/mod_jk.so
#加载集群中的工作的tomcat配置文件
JkWorkersFile conf/workers.properties
#共享内存的配置和运行时信息文件名
JkShmFile logs/mod_jk.shm
#加载请求处理分配文件
JkMountFile conf/uriworkermap.properties
#指定jk的日志输出文件
JkLogFile logs/mod_jk.log
#日志输出文件的级别
JkLogLevel error
[root@web-server conf]# cat mod_jk.conf
LoadModule jk_module modules/mod_jk.so
JkLogLevel info
JkOptions +ForwardKeySize +ForwardURICompat -ForwardDirectories
JkLogStampFormat "[%a %b %d %H:%M:%S %Y]"
JkRequestLogFormat "%w %V %T"
JkWorkersFile conf/workers.properties
#JkMountFile conf/uriworkermap.properties
JkLogFile logs/mod_jk.log
JkLogLevel info
JkMount /*.action worker1
JkMount /*.jsp worker1
JkMount /servlet/* worker1
JkMount /*.do worker1
JkMount /application/* worker1
JkMount /struts/* worker1
#JkMount /*.action ajp13
JkMount /*.html worker1
JkMount /*.java worker1
JkMount /WEB-INF/* worker1
JkMount /* worker1
然后接着在创建tomcat负载配置属性文件
touch /etc/httpd/conf/workers.properties
#workers.properties
#配置格式为worker.<worker name>.<directive>=<value>
#
# worker列表
worker.list=lb_s,status # 第一个tomcat
# ------------------------
#port 为配置tomcat ajp监控端口,不是http的端口
worker.s1.port=
#tomcat的主机地址,如不为本机,请填写ip地址
worker.s1.host=localhost
worker.s1.type=ajp13
#负载的权重值,越高表示负载越大
worker.s1.lbfactor= # 第二个tomcat
# ------------------------
worker.s2.port=
worker.s2.host=localhost
worker.s2.type=ajp13
worker.s2.lbfactor= # 第N个tomcat
# ------------------------
#worker.sN.port=
#worker.sN.host=localhost
#worker.sN.type=ajp13
#worker.sN.lbfactor= #用于负载均衡分发的控制器,名称为lb_s
worker.lb_s.type=lb
#失败时重试转发次数
worker.lb_s.retries=
#加入负载均衡的tomcat worker,上面定义如要加载在这里
worker.lb_s.balanced_workers=s1,s2
#配置session会话是否为粘性
#这样负载均衡器lb就会尽量保持一个session,也就是使用户在一次会话中跟同一个Tomcat进行交互
#不建议配置为1(or true)
#worker.lb_s.sticky_session=false
#worker.lb_s.sticky_session_force=true
#设置运行状态的控制器
worker.status.type=status
我们分别将两个Tomcat配置文件中的jvmRoute设置为s1、s2
[root@web-server conf]# cat workers.properties
# Defining a worker named worker1 and of type ajp13
worker.list=worker1
#Set properties for worker1
worker.worker1.type=ajp13
worker.worker1.host=localhost
worker.worker1.port=
worker.worker1.lbfactor=
worker.worker1.socket_keepalive=
worker.worker1.socket_timeout=300a
worker.worker1.cache_timeout=
touch /etc/httpd/conf/uriworkermap.properties 我没用这个文件
#这个后面配置的value要在worker.properties文件里面存在对应的worker
#所有请求都交给lb_s这个worker处理
/*=lb_s
#所有包含status请求的都由名称叫status的这个worker处理
/status=status
#感叹号表示接下来的 URI 不要由 JK 进行处理
#静态文件都不通过jk处理,直接由apache处理
!/*.gif=lb_s
!/*.jpg=lb_s
!/*.png=lb_s
!/*.css=lb_s
!/*.js=lb_s
tomcat配置
Tomcat配置文件Service.xml主要注意两个地方,一个是Engine节点需要增加节点标识jvmRoute,一个是将原本注释掉的Session复制节点改为有效。具体如下: <!--jvmRoute在各个Tomcat配置中不能重复且要与worker.properties文件中的名称一致-->
<Engine name="Catalina" defaultHost="localhost" jvmRoute="test1">
<!--session复制内容-->
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"
channelSendOptions="">
<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"
address="228.0.0.4"
port=""
frequency=""
dropTime=""/>
<Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver"
address="auto"
port=""
autoBind=""
selectorTimeout=""
maxThreads=""/>
<!-- timeout=""-->
<Sender className="org.apache.catalina.tribes.transport.ReplicationTransmitter">
<Transport className="org.apache.catalina.tribes.transport.nio.PooledParallelSender" />
</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=".*.gif;.*.js;.*.jpg;.*.png;.*.htm;.*.html;.*.css;.*.txt;"/>
<Valve className="org.apache.catalina.ha.session.JvmRouteBinderValve"/>
<Deployer className="org.apache.catalina.ha.deploy.FarmWarDeployer"
tempDir="/tmp/war-temp/"
deployDir="/tmp/war-deploy/"
watchDir="/tmp/war-listen/"
watchEnabled="false"/>
<ClusterListener className="org.apache.catalina.ha.session.JvmRouteSessionIDBinderListener"/>
<ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener"/>
</Cluster>
<!--session复制内容--> <!—Host节点增加一下内容表示站点根路径-->
<Context path="/sc" docBase="." privileged="true"/>
我们分别将两个Tomcat配置文件中的jvmRoute设置为tomcat1、tomcat2,Server节点
端口分别配置为8005和9005,
Connector节点端口分别配置为8080和9090,AJPConnector端口分别配置为8009和9009,Connector端口配置参照单主机多站点场景。请注意两个Tomcat配置文件Host节点的域名配置必须一样,Server.xml中的jvmRoute名称必须和worker.properties中的tomcat实例名称一致,不然无法实现session_stricky。 *****************************************************************************
如果需要实现session 复制 需要在Tomcat 下conf/web.xml 中加上<distributable/>
<?xml version="1.0" encoding="ISO-8859-1"?>
省略N多代码。。。。。。
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<distributable/>
</web-app>
*****************************************************************************