goid:梦想照进现实 - BlogJava
在一个复杂的企业应用环境中,往往一个application server无法承担所有的服务请求,所以很多企业都为此架起了多个服务器实例。这些服务器实例结合在一起,可以组织成一个强健的企业运行环境,它易于扩展、支持load banlance, 支持fail over, 可以做到backend server的failure对于客户是透明的。这样的一个企业环境就是我们常说的Cluster。Weblogic Cluster提供了多种load banlance的可能, 比如web application请求处理,可以通过proxy来实现(e.g. apache, HttpClusterServlet, IIS), 不同的J2EE Component在Weblogic有不同的load banlance实现.下面我们来逐一看看,
1: Http请求通过proxy实现的load banlance
当客户端通过proxy访问Cluster中的业务页面时,proxy通过自身的算法(round-robin)来实现load banlance.当然这些请求要求是从不同的客户端(或者不带session的同一客户端的请求)发起的.对于同一客户端,如果页面中使用了session, 那么Weblogic 通过session粘连来实现同一客户端的请求会被dispatch到primary server上.如果primary server无法提供服务,那么请求会被dispatch到其他server上。session粘连可以通过以下几种方式实现:
1.1:browser支持cookie的话,Weblogic会把jsession id写入到cookie中,下次请求提交的时候jseeion id会被提交到proxy端,proxy通过jseeion id 来决定请求的dispatch。
1.2:browser不支持cookie,server端在处理返回页面时,调用response.encodeURL()来将session id附在url上。
1.3:post-data方式,直接将session作为数据,post到proxy端。
我们来看看Weblogic提供的HttpClusterServlet是如何实现load banlance的,
public synchronized Server next() {
if (list.size() == 0) return null;
if (index == -1) index = (int)(java.lang.Math.random() * list.size());
else index = ++index % list.size();
Object[] servers = list.values().toArray();
return (Server) servers[index];
}
HttpClusterServlet维护一个managed servlet list,每当一个请求被dispatch到某个managed server后,server list的index加1,这样在下次dispatch请求的时候,请求将会被dispatch到server list中的其他server上去。逻辑很简单,但基本也实现了load banlance功能。
2:InitialContext的load banlance
我们知道,每次我们需要获取jdbc connection, jms connection,ejb stub这类RMI Object的时候,我们都要初始化一个上下文,问题是我们初始化上下文的时候,连接的到底是哪个managed server?
初始化上下文的时候,我们需要提供一个provider url, 如下:
PROVIDER_URL = "t3://localhost:7011";
这种写法很简单,直接连接7001对应的server, 但如果写法如下呢?
CLUSTER_PROVIDER_URL="t3://localhost:7011,localhost:7021";
这时候,load banlance就又来了。10个客户端(Weblogic server或者thin client)new 10个InitialContext的话,这10个客户端将55分别连接到后端的两台server上去。实际上客户端在new InitialContext的时候,Weblogic会创建一个T3连接到对应的managed server上(RJVMConnection),注意这个RJVMConnection是个长连接,在同一个JVM中,连向同一managed server的连接只有一个。即如果一个客户端,连续new 10个 InitialContext, 这10个Context实际上是同一对象,Weblogic server这时根本不会和后端的server通讯,因为对象已经在client JVM中有了。
new InitialContext的load banlance算法基本和proxy的算法一样,都是维护一个server list, 通过index递增的方法实现。不同的是:在连接某个managed server的connection遇到peer gone的时候, proxy可以recover server list, 而jndi context的load banlance算法则不能。也就是说如果后端有三个managed server, server1, server2相继出现故障的话,所有客户端的context将都会连接到server3, 即使server1, server2能够恢复过来,后续请求也不会连接到他们,除非server3后来出现问题。
值得一提的是:context所有的相关操作时server affinity的,而非load banlance。比如:2个客户端分别new了个context, 分别连接到server1和server2上,连接到server1的context,做了10次lookup,那么这10次操作,都在server1上完成,不会在server2上作任何操作。所以说jndi级别的load banlance不是绝对均衡的。
3: JMS Distributed Queue的load banlance
Distributed Queue(简称DQ),顾名思义,分布式队列。在不同的JMS Server上,我们会创建不同的物理Queue, 按照传统方式,我们在发送消息(或者创建JMSSession)的时候,需要指定一个物理Queue, 这样我们可以将消息发送到固定的Queue上。 由于在Weblogic server上, JMS Server是一个pin service, 即只能运行于单个managed server上的服务实例。 如果我们发送消息的时候,指定Queue对应的jms server出现了问题,这样消息无法发送出去。基于这个原因, Weblogic上提出了DQ,DQ是个逻辑Queue,并没有时间的物理Queue与其对应,它用于管理多个、分布于不同jms server上的物理Queue, 这样客户发送、接受消息的时候,需要指定的是DQ,而不是物理Queue。客户端知道的只是将消息发送到了DQ,而无法知道到底发送到哪个具体的物理Queue上了。那么Weblogic是如何计算消息该发送到具体物理Queue呢?
JMS Connection Factroy的配置选项中load banlance参数:LoadBanlanceEnabled,ServerAffinityEnabled
Distributed Queue的配置选项中load banlance参数:LoadBanlancePolicy,默认为Round-Robin, 可选值包括:Round-Robin, Random
Load Balancing Enabled:
Specifies whether non-anonymous producers created through a connection factory are load balanced within a distributed destination on a per-call basis.
If enabled, the associated message producers are load balanced on every send() or publish() .
If disabled, the associated message producers are load balanced on the first send() or publish().
ServerAffinityEnabled:
Specifies whether a server instance that is load balancing consumers or producers across multiple members destinations of a distributed destination, will first attempt to load balance across any other physical destinations that are also running on the same server instance.
Load Balancing Policy:
Determines how messages are distributed to the members of this destination.
Round-Robin
- The system maintains an ordering of physical topic members within the set by distributing the messaging load across the topic members one at a time in the order that they are defined in the configuration file. Each Weblogic Server instance maintains an identical ordering, but may be at a different point within the ordering. If weights are assigned to any of the topic members in the set, then those members appear multiple times in the ordering.
Random
- The weight assigned to the topic members is used to compute a weighted distribution for the members of the set. The messaging load is distributed across the topic members by pseudo-randomly accessing the distribution. In the short run, the load will not be directly proportional to the weight. In the long run, the distribution will approach the limit of the distribution. A pure random distribution can be achieved by setting all the weights to the same value, which is typically set to 1.
JMS Connection Factroy在创建JMSConnection的时候,这一层是load banlance的, 即JMSConnection会连接到不同的后端managed server上。这个load banlance是基于round_robin的。一旦connection创建完成,所有通过该JMSConnection创建的consumer, producer会stick到JMSConnection对应的managed server上, 即所有的message会被dispatch到该managed server的物理Queue上(因为sub-type的jms对象不是RMI对象,他们和后端managed server的通讯是基于dispatcher的,通过invocable id来识别对象)。如果producer send了很多条message, 那么这些消息如何分发?这就是Load Balancing ,ServerAffinity要做的事儿。
Load Balancing Enabled被check的时候,消息分发是基于send()方法的,即send一条message, message都会被分发到不同的Queue上。如果Load Balancing Enabled没有被check,那么同一producer send的所有message会被分发到同一物理Queue上。而ServerAffinity则说明loadbalance Queue的范围,如果serverAffinity为true,那么说明load banlance的范围为处理send request那台managed server上的Queues,如果为false,则说明在所有的queue间作load balance。
4:EJB的load banlance
EJB的load banlance比较复杂,涉及到如下三个方面:
1:IntitialContext
关于InitialContext, 前面已经谈过,这里不再做讨论。
2:EJB Home
对于EJB Home,可以通过Weblogic-ejb-jar.xml中的home-load-algorithm 配置,可选项包括:round-robin | random | weight-based | RoundRobinAffinity | RandomAffinity | WeightBasedAffinity, default依赖于Weblogic.cluster.defaultLoadAlgorithm,如果没有对应的system property, 则为round-robin。
如果home-load-algorithm为round-robin,则说明客户端拿到initial context后,在做ejb home create的时候是round robin的(创建的的bean object位于不同的managed server上)。如果home-load-algorithm为RoundRobinAffinity ,则表明home create是round robin的,但后续的home的操作则是server affinity的,比如,home位于serverA上,则该home创建的所有bean object均位于serverA上。
其余算法基本类似,区别只是home create时候的算法不同而已。
3: EJB Object
对于Bean的load banlance,只有stateless session支持,可以通过stateless-bean-load-algorithm配置,可选项同EJB Home。因为stateful session bean及entity bean包含状态数据,所以无法作laod banlance,否则在数据同步方面,Weblogic需要付出的开销要远大于laod banlance带来的收益。
如果stateless-bean-load-algorithm为round-robin,则说明bean操作是round-robin的。如果为RoundRobinAffinity ,则business method是affinity的,即所有的method都在object对应的server上被执行。
5:JDBC
对于JDBC,如果要使用load banlance的话,我们需要配置multi pool,multi pool和jms 的distribute destination类似,是一个逻辑pool,用于管理一组物理pool(通常位于不同的managed server上)。Multi pool的算法包括: HA(用于fail over), Load banlance。前者只是在某个物理pool出现故障的时候,用于fail over,而不提供load banlance。而后者则是两种功能都提供,正常时作laod banlance,运行故障期间,fail over会起作用。