首先我們來看一下DynamicServerList 的具體解釋,默認(rèn)值是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實(shí)時(shí)獲取后端cluster中的server列表(比如cluster中的member增加、刪除,member狀態(tài)的變化(startup、shutdown)),這樣proxy在load balance request的時(shí)候可以避免去try dead server。同時(shí)可以將請(qǐng)求dispatch到cluster中的新增member上(比如預(yù)定義的cluster中有server1, server2,某時(shí)刻發(fā)現(xiàn)后端server load比較高,新增加一個(gè)server3,這時(shí)候,如果DynamicServerList 為on,你就不需要重新定義WeblogicCluster,當(dāng)然也不需要重起plugin)。順便提一下,DynamicServerList為on的時(shí)候,http.conf或HttpClusterServlet對(duì)應(yīng)的web.xml中的WeblogicCluster無需定義所有的cluster member,指定任意一個(gè)即可。
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狀態(tài)的變化,從而及時(shí)更新自己手里的server list以便提高dispatch request的速度。
1:plugin端(以HttpClusterServlet為例)
在plugin處理client端請(qǐng)求的時(shí)候,它在將請(qǐng)求dispatch到后端server的時(shí)候,會(huì)在http header中加上一個(gè)名為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 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端的時(shí)候,檢查當(dāng)前managed server是否位于一個(gè)cluster中及request的header中是否包含X_WEBLOGIC_REQUEST_CLUSTERINFO。如果上述條件成立,再去檢查當(dāng)前cluster的hash,如果cluster的hash發(fā)生變化(對(duì)比當(dāng)前cluster的hash和proxy傳遞過來的hash),則將cluster member的信息通知給proxy,這個(gè)通知也是通過http header來實(shí)現(xiàn),不同的是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 }
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的時(shí)候,它同時(shí)會(huì)解析inter header的信息。如果發(fā)現(xiàn)DynamicServerList為true,而且response的header中包含X_WEBLOGIC_CLUSTER_LIST、X_WEBLOGIC_CLUSTER_HASH等信息,它會(huì)據(jù)此更新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是一個(gè)請(qǐng)求范圍的變量,更新它其實(shí)無法更新到proxy中的server list。server list的更新發(fā)生在一個(gè)request結(jié)束的時(shí)候,就HttpServletRequest.service()的finally塊中。在finally塊中,檢查requestInfo中的dynamicServerList存在,如果存在則說明后端cluster發(fā)生了變化(否則managed server不會(huì)發(fā)送X_WEBLOGIC_CLUSTER_LIST信息到proxy端),那么它會(huì)將自己手里的serverlist, server hash信息設(shè)置為后端返回的值,如下: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 }
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 }
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 的實(shí)現(xiàn)流程基本能看明白了吧。而對(duì)于static server list,不建議大家使用,否則proxy的分發(fā)性能會(huì)在cluster不穩(wěn)定的時(shí)候發(fā)生下降。 但在cluster本身partition掉的時(shí)候,static server list會(huì)顯得更好。也就是說cluster出現(xiàn)問題了,cluster中的member不能看到所有其他的members(甚至只能看到自己),比如cluster中有4個(gè)server, A\B\C\D,如果某一時(shí)刻請(qǐng)求被dispatch到A上,而此時(shí)如果A只能看到B(即在A的眼中,只有它自己和B可以提供服務(wù)),這時(shí)候A會(huì)將只包含A\B的cluster server list返回給proxy,那么proxy在分發(fā)后續(xù)請(qǐng)求的時(shí)候,只會(huì)在A\B上做load balance(C\D不會(huì)接受到請(qǐng)求,雖然他們還在running),直到cluster恢復(fù)正常或發(fā)生變化。而這種情況下,如果static server list的話,A\B\C\D都會(huì)接受到proxy分發(fā)過來的請(qǐng)求。當(dāng)然這只是種非正常情況,出現(xiàn)這種情況的時(shí)候,我們首要任務(wù)應(yīng)該是解決cluster partition的問題,而不是依賴于static server list。