几乎所有使用weblogic的大一点的企业环境中,都会使用到cluster, 使用cluster势必要采用proxy, proxy有很多,apache, iis及weblogic提供的HttpClusterServlet。plugin的配置参数有很多,可参考下面的链接,
http://e-docs.bea.com/wls/docs92/plugins/plugin_params.html#wp1157622。这篇文章中,我们主要看看DynamicServerList 内部实现是什么样子的。
首先我们来看一下DynamicServerList 的具体解释,默认值是enable的,
When set to
OFF
, the plug-in ignores the dynamic cluster list used for load balancing requests proxied from the plug-in and only uses the static list specified with the
WebLogicCluster parameter. Normally this parameter should remain set to
ON
. There are some implications for setting this parameter to
OFF
:
1:If one or more servers in the static list fails, the plug-in could waste time trying to connect to a dead server, resulting in decreased performance.
2:If you add a new server to the cluster, the plug-in cannot proxy requests to the new server unless you redefine this parameter. WebLogic Server automatically adds new servers to the dynamic server list when they become part of the cluster.
从上面的描述可以看出,DynamicServerList 用于使proxy实时获取后端cluster中的server列表(比如cluster中的member增加、删除,member状态的变化(startup、shutdown)),这样proxy在load balance request的时候可以避免去try dead server。同时可以将请求dispatch到cluster中的新增member上(比如预定义的cluster中有server1, server2,某时刻发现后端server load比较高,新增加一个server3,这时候,如果DynamicServerList 为on,你就不需要重新定义WeblogicCluster,当然也不需要重起plugin)。顺便提一下,DynamicServerList为on的时候,http.conf或HttpClusterServlet对应的web.xml中的WeblogicCluster无需定义所有的cluster member,指定任意一个即可。
WebLogicCluster 10.130.2.41:7021,10.130.2.42:7021,10.130.2.43:7021
WebLogicCluster 10.130.2.41:7021
上面两种写法是等效的,但DynamicServerList若为off,则必须采用上面的写法。
下面我们来看看proxy是如何感知后端cluster状态的变化,从而及时更新自己手里的server list以便提高dispatch request的速度。
1:plugin端(以HttpClusterServlet为例)
在plugin处理client端请求的时候,它在将请求dispatch到后端server的时候,会在http header中加上一个名为X_WEBLOGIC_REQUEST_CLUSTERINFO的internal header, 如下:
HttpClusterServlet.java
1 protected void addRequestHeaders(HttpServletRequest request, PrintStream headerOut, Object o1, Object o2) {
2 super.addRequestHeaders(request, headerOut, o1, o2);
3
4 headerOut.print(ServletResponseImpl.X_WEBLOGIC_REQUEST_CLUSTERINFO + ": true");
5 headerOut.print(EOL);
6 }
2: managed server端
managed server在处理完http request后,回写response到proxy端的时候,检查当前managed server是否位于一个cluster中及request的header中是否包含X_WEBLOGIC_REQUEST_CLUSTERINFO。如果上述条件成立,再去检查当前cluster的hash,如果cluster的hash发生变化(对比当前cluster的hash和proxy传递过来的hash),则将cluster member的信息通知给proxy,这个通知也是通过http header来实现,不同的是header名为:X_WEBLOGIC_CLUSTER_LIST及X_WEBLOGIC_CLUSTER_HASH,如下:
ServletResponseImpl.java
1 /*package*/ final void writeHeaders() throws IOException {
2
3 HttpServer httper = getHttpServer();
4 if (httper != null) {
5 boolean isPlugin = false;
6 ServerMBean serverMBean = ManagementService.getRuntimeAccess(
7 WebAppConfigManager.KERNEL_ID).getServer();
8 if (serverMBean.getCluster() != null &&
9 request.getHeader(X_WEBLOGIC_REQUEST_CLUSTERINFO) != null) {
10
11 String hash = request.getHeader(X_WEBLOGIC_CLUSTER_HASH);
12 String oldHash = hash == null ? "" : hash;
//MemberControllerImpl is a singlton instance and it's hash is changed when cluster changs
13 String currentHash = MembershipControllerImpl.getInstance().getHash();
14 String passedHash = headers.getHeader(X_WEBLOGIC_CLUSTER_HASH);
15 if (currentHash != null && !currentHash.equals(oldHash)) {
16 String[] servers =
17 MembershipControllerImpl.getInstance().getClusterList(
18 request.getConnection().getChannel());
19
20 headers.setHeader(X_WEBLOGIC_CLUSTER_HASH, currentHash);
21 headers.setHeader(X_WEBLOGIC_CLUSTER_LIST, sb.toString());//sb presents servers list string
22 }
23 }
24 }
25 }
3:proxy端,
回到proxy端,proxy读取managed server的response,将response写回到客户端。在读取response的时候,它同时会解析inter header的信息。如果发现DynamicServerList为true,而且response的header中包含X_WEBLOGIC_CLUSTER_LIST、X_WEBLOGIC_CLUSTER_HASH等信息,它会据此更新request info,如下:
HttpClusterServlet.java
1 public void addResponseHeaders(HttpServletResponse response, String name, String value, Object o) {
2 RequestInfo ri = (RequestInfo) o;
3 if (ri.needToUpdateDynamicList() &&
4 name.equals(ServletResponseImpl.X_WEBLOGIC_CLUSTER_LIST)) {
5 ri.setDynamicList(value);
6 return;
7 }
8 if (ri.needToUpdateDynamicList() &&
9 name.equals(ServletResponseImpl.X_WEBLOGIC_CLUSTER_HASH)) {
10 ri.setDynamicHash(value);
11 return;
12 }
13
14 }
而requestInfo是一个请求范围的变量,更新它其实无法更新到proxy中的server list。server list的更新发生在一个request结束的时候,就HttpServletRequest.service()的finally块中。在finally块中,检查requestInfo中的dynamicServerList存在,如果存在则说明后端cluster发生了变化(否则managed server不会发送X_WEBLOGIC_CLUSTER_LIST信息到proxy端),那么它会将自己手里的serverlist, server hash信息设置为后端返回的值,如下:
1 finally
2 {
3 String dynamicList = ri.getDynamicList();
4 if (dynamicList != null) {
5 ServerList servers = new ServerList(dynamicList, false);
6 if (!useDynamicList) {
7
8 } else {
9 servers.setHash(ri.getDynamicHash());
10 if (verbose) trace("Updating dynamic server list: " + dynamicList);
11 srvrList = servers;
12 servers.addToKnownServersList(allKnownServers);
13 }
14 }
至此,DynamicServerList 的实现流程基本能看明白了吧。而对于static server list,不建议大家使用,否则proxy的分发性能会在cluster不稳定的时候发生下降。 但在cluster本身partition掉的时候,static server list会显得更好。也就是说cluster出现问题了,cluster中的member不能看到所有其他的members(甚至只能看到自己),比如cluster中有4个server, A\B\C\D,如果某一时刻请求被dispatch到A上,而此时如果A只能看到B(即在A的眼中,只有它自己和B可以提供服务),这时候A会将只包含A\B的cluster server list返回给proxy,那么proxy在分发后续请求的时候,只会在A\B上做load balance(C\D不会接受到请求,虽然他们还在running),直到cluster恢复正常或发生变化。而这种情况下,如果static server list的话,A\B\C\D都会接受到proxy分发过来的请求。当然这只是种非正常情况,出现这种情况的时候,我们首要任务应该是解决cluster partition的问题,而不是依赖于static server list。
posted on 2008-11-13 13:48
走走停停又三年 阅读(2601)
评论(6) 编辑 收藏 所属分类:
Weblogic