在上一篇使用Apache+Tomcat实现集群的博文中,只是简单的搭建了一个集群测试用例,并没有太多原理及实现上的分析。那么集群搭建完了之后,
有很多问题值得思考:
为什么要采用Apache+Tomcat架构?
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等效,但对静态页面的处理不太理想。
这种架构的内部流程或者一次请求的流程?
Session到底是如何实现共享的?
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仍处于活动状态的现象。