Apache Tomcat Cluster Principle
WEB应用集群的技术:
- 最大的难点就是如何能在集群中的多个节点之间保持数据的一致性,会话(Session)信息是这些数据中最重要的一块。
- 常见的平台或中间件都会提供对两种共享方式的支持,tomcat也是这样,但是一般采用第二种方式。
有两种实现方式:
- 一种是把所有Session数据放到一台服务器上或者数据库中,集群中的所有节点通过访问这台Session服务器来获取数据;
- 另一种就是在集群中的所有节点间进行Session数据的同步拷贝,任何一个节点均保存了所有的Session数据。
两种方式都各有优点:
- 第一种方式简单、易于实现,但是存在着Session服务器发生故障会导致全系统不能正常工作的风险;
- 第二种方式可靠性更高,任一节点的故障不会对整个系统对客户访问的响应产生影响,但是技术实现上更复杂一些。
Tomcat集群方式有三种:
- 使用DNS轮询.
- 使用Apache R-proxy方式
- 使用Apache mod_jk方式
优缺点:
- DNS轮询的缺点是,当集群中某台服务器停止之后,用户由于dns缓存的缘故,便无法访问服务,必须等到dns解析更新,或者这台服务器重新启动。还有就是必须把集群中的所有服务端口暴露给外界,没有用apache做前置代理的方式安全,并且占用大量公网IP地址,而且tomcat还要负责处理静态网页资源,影响效率。优点是集群配置最简单,DNS设置也非常简单。
- R-proxy的缺点是,当其中一台tomcat停止运行的时候,apache仍然会转发请求过去,导致502网关错误。但是只要服务器再启动就不存在这个问题。mod_jk方式的优点是,Apache 会自动检测到停止掉的tomcat,然后不再发请求过去。缺点就是,当停止掉的tomcat服务器再次启动的时候,Apache检测不到,仍然不会转发请求过去。
- R-proxy和mod_jk的共同优点是.可以只将Apache置于公网,节省公网IP地址资源。可以通过设置来实现Apache专门负责处理静态网页,让Tomcat专门负责处理jsp和servlet等动态请求。共同缺点是:如果前置Apache代理服务器停止运行,所有集群服务将无法对外提供。R-proxy和mod_jk对静态页面请求的处理,都可以通设置来选取一个尽可能优化的效果。
- 这三种Tomcat集群方式对实现最佳负载均衡都有一定不足,mod_jk相对好些,可以通过设置lbfactor参数来分配请求任务,但又因为mod_jk2方式不被推荐,mod_jk2已经不再被更新了。
模拟集群(集群采用默认配置,由t1和t2两个tomcat例程组成,场景按照时间顺序排列)
1. t1启动
t1按照标准的tomcat启动,当Host对象被创建时,一个Cluster对象(默认配置下是SimpleTcpCluster)也同时被关联到这个Host对象。当某个应用在web.xml中设置了distributable时,Tomcat将为此应用的上下文环境创建一个DeltaManager。SimpleTcpCluster启动membership服务和Replication服务(用于建立tcp连接)。
2. t2启动(待t1启动完成后)
首先t2会执行和t1一样的操作,然后SimpleTcpCluster会建立一个由t1和t2组成的membership。接着t2向集群中已启动的服务器即t1请求Session数据,如果t1没有响应t2的拷贝请求,t2会在60秒后time out。在Session数据拷贝完成之前t2不会接收客户端的http或mod_jk/ajp请求。
3. t1接收http请求,创建Session s1
t1正常响应客户请求,但是在t1把结果发送回客户端时,ReplicationValve会拦截当前请求(如果filter中配置了不需拦截的请求类型,这一步就不会进行,默认配置下拦截所有请求),如果发现当前请求更新了Session,调用Replication服务建立tcp连接把Session拷贝到membership列表中的其他节点即t2,返回结果给客户端(注意,如果采用同步拷贝,必须等拷贝完成后才会返回结果,异步拷贝在数据发送到tcp连接就返回结果,不等待拷贝完成)。在拷贝时,所有保存在当前Session中的可序列化的对象都会被拷贝,而不仅仅是发生更新的部分。
4. t1崩溃
当t1崩溃时,t2会被告知t1已从集群中退出,然后t2就会把t1从自己的membership列表中删除,发生在t2的Session更新不再往t1拷贝,同时负载均衡器会把后续的http请求全部转发给t2。在此过程中所有的Session数据不会丢失。
5. t2接收s1的请求
t2正常响应s1的请求,因为t2保存着s1的所有数据。
6. t1重新启动
按步骤1、2一样的操作启动,加入集群,从t2拷贝所有Session数据,拷贝完成后开放自己的http和mod_jk/ajp端口接收请求。
7. t1接收请求,s1失效
t1继续接收来自s1的请求,把s1设置为过期。这里的过期并非因为s1处于非活动状态超过设置的时间,而是执行类似注销的操作而引起的Session失效。这时t1并非发送s1的所有数据而是一个类似s1 expired的消息,t2收到消息后也会把s1设为过期。
8. t2接收请求,创建Session s2
和步骤3一样。
9. t1 s2过期
对于因超时引起的Session失效t1无需通知t2,因为t2同样知道s2已经超时。因此对于tomcat集群有一点非常重要,所有节点的操作系统时间必须一致!不然会出现某个节点Session已过期而在另一节点此Session仍处于活动状态的现象。
为什么引入 Apache 或者其他的一些专门的 HTTP 服务器呢?
- 提升对静态文件的处理性能
- 利用 Web 服务器来做负载均衡以及容错
- 无缝的升级应用程序
JK && http_proxy && ajp_proxy
相对于 JK 的连接方式,后两种在配置上是比较简单的,灵活性方面也一点都不逊色。
但就稳定性而言就不像 JK 这样久经考验,毕竟 Apache 2.2.3推出的时间并不长,采用这种连接方式的网站还不多,因此,如果是应用于关键的互联网网站,还是建议采用 JK 的连接方式。
JK提供了一个监控以及管理的页面 jkstatus,通过 jkstatus 监控 JK 目前的工作状态以及对 tomcat进行设置
在workers.properties里添加
worker.list=jk-watch
worker.jk-watch.type=status
worker.jk-watch.read_only=True
worker.jk-watch.mount=/user/status/jk // 只读
worker.list=jk-manage
worker.jk-manage.type=status
worker.jk-manage.mount=/admin/status/jk // 所有权限
浙公网安备 33010602011771号