Forum Discussion
JRahm
Admin
Aug 02, 2006WebLogic information extraction
Our weblogic servers will give me an active list of servers in the X-WebLogic-Cluster-List header if I supply the X-Weblogic-Request-ClusterInfo header with a value of true. This is the missing piece I've been trying to identify since weblogic stopped encoding the real server IP in network byte order in version 8. I'd like to populate an array with the servername and the unique arbitrary number it is assigned. By utilizing the rule
when HTTP_REQUEST {
HTTP::header insert "X-Weblogic-Request-ClusterInfo" "true"
}
when HTTP_RESPONSE {
if { [HTTP::header exists "X-WebLogic-Cluster-List"] } {
log "Cluster list: [HTTP::header "X-WebLogic-Cluster-List"]"
HTTP::header remove "X-WebLogic-Cluster-List"
}
}
I receive the information below:
-306262974!server_a-93!65535!-1 |
-572170000!server_c-93!65535!-1 |
-851958269!server_b-91!65535!-1 |
-896443913!server_d-93!65535!-1 |
-937189304!server_b-90!65535!-1 |
1685710619!server_c-92!65535!-1 |
1717517013!server_d-90!65535!-1 |
1720885579!server_d-91!65535!-1 |
1949732605!server_b-93!65535!-1 |
296784837!server_c-90!65535!-1 |
324405524!server_c-91!65535!-1 |
472005059!server_d-92!65535!-1 |
534925464!server_b-92!65535!-1 |
548600573!server_a-90!65535!-1 |
82670729!server_a-92!65535!-1 |
894452575!server_a-91!65535!-1
I'm looking for advice on the best way (read: efficient) to extract the servername and the leading arbitrary number associated to it. I know the real IP address for each of those server names, so what I'd like to do is evaluate the JSESSIONID information arriving (jsessionid!primary_server!secondary_server) and send connections to primary_server based on information in the array, and in the LB_FAILED event, send connections to the secondary_server. I'm struggling with getting persistence to behave nicely in failure scenarios and I am looking at alternatives. Any help would be appreciated.
- Deb_Allen_18Historic F5 AccountYou can use "getfield" to extract the first 3 fields in the header like this:
Is that what you were looking for...?set jsess [getfield [HTTP::header "X-WebLogic-Cluster-List"] "!" 1] set server1 [getfield [HTTP::header "X-WebLogic-Cluster-List"] "!" 2] set server2 [getfield [HTTP::header "X-WebLogic-Cluster-List"] "!" 3]
- JRahm
Admin
partially...I would like to first split the content by server: - Deb_Allen_18Historic F5 AccountOK, how about something like this?:
which would create the following ServerList array:when HTTP_RESPONSE { if { [HTTP::header exists "X-WebLogic-Cluster-List"] }{ set server_mappings [split [HTTP::header "X-WebLogic-Cluster-List"] "|" ] init array if non-existent array set ::ServerList { } clear pre-existing array entries (re-initializing as blank array doesn't seem to do it) array unset ::ServerList foreach server $server_mappings { set ::ServerList($server) [getfield [findclass $server $::server_name_to_IP] " " 2] } } }
then once you've extracted the jsession string (i.e. Gsfsafavlaeruae!-306262974!-851958269) from cookie or URI, you can extract the primary & secondary server IP from the array using the WL server IDs like this:{ -306262974 10.1.1.10 -572170000 10.1.1.11 -851958269 10.1.1.12 -896443913 10.1.1.13 -937189304 10.1.1.14 }
HTHarray get ::ServerList [getfield $jsessionstring "!" 2] array get ::ServerList [getfield $jsessionstring "!" 3]
- JRahm
Admin
Still trying to wrap my head around exactly what is transpiring in the array population...I'm a big dummy. - Deb_Allen_18Historic F5 AccountYikes, I see your confusion -- I left out the extraction of the server details needed to build the array. Sorry about that. I think this is more what you are after:
or to eliminate setting those 2 extra variables, inline substitution gives you:when HTTP_RESPONSE { if { [HTTP::header exists "X-WebLogic-Cluster-List"] }{ set server_mappings [split [HTTP::header "X-WebLogic-Cluster-List"] "|" ] init array if non-existent array set ::ServerList { } clear pre-existing array entries (re-initializing as blank array doesn't seem to do it) array unset ::ServerList foreach servermap $server_mappings { set serverID [getfield $servermap "!" 1] set serverName [getfield $servermap "!" 2] set ::ServerList($serverID) [getfield [findclass $serverName $::server_name_to_IP] " " 2] } } }
Clear as mud, now, eh?when HTTP_RESPONSE { if { [HTTP::header exists "X-WebLogic-Cluster-List"] }{ set server_mappings [split [HTTP::header "X-WebLogic-Cluster-List"] "|" ] init array if non-existent array set ::ServerList { } clear pre-existing array entries (re-initializing as blank array doesn't seem to do it) array unset ::ServerList foreach servermap $server_mappings { set ::ServerList([getfield $servermap "!" 1]) [getfield [findclass [getfield $servermap "!" 2] $::server_name_to_IP] " " 2] } } }
- Deb_Allen_18Historic F5 Account(edited to correct line-wrapping error)
- JRahm
Admin
I finally had some time to work through the rule logic. I think it would have taken me a very long time to figure out that fancy array footwork, thanks for that. I haven't done the failure or load testing against this yet, but here is the working rule. Basically it makes use of the cluster information provided by Weblogic to map the WebLogic locally significant serverID to an IP address so I can send all connection requests directly to the appropriate primary server without using persistence. It will evaluate the JSESSIONID cookie if present, and the URI for the jsessionid if the cookie is not present.when CLIENT_ACCEPTED { set get_server_mappings 1 } when HTTP_REQUEST { Insert WebLogic Header to retrieve active servers if new client connection if { $get_server_mappings } { Inserting this header instructs Weblogic to return cluster information HTTP::header insert "X-Weblogic-Request-ClusterInfo" "true" Reset variable to zero to prevent header insert on every request set get_server_mappings 0 } If all servers are inactive, redirect to sorry page on Apache if { [active_members myPool] == 0 } { HTTP::redirect "http://[HTTP::header "X-Forwarded-Host"]/unavailable/index.html" } Replace Host header with X-Forwarded-Host header contents if { [HTTP::header exists "X-Forwarded-Host"] } { HTTP::header replace "Host" [HTTP::header "X-Forwarded-Host"] } If JSESSIONID cookie exists, use the contents to extract jsession server reference if { [HTTP::cookie exists "JSESSIONID"] } { set serverIP_fromCookie [lindex [ array get ::ServerList [getfield [HTTP::cookie "JSESSIONID"] "!" 2 ] ] 1] If an IP was found in the array if { $serverIP_fromCookie ne "" } { Send the connection to the primary server pool myPool member $serverIP_fromCookie log "From Cookie: Server $serverIP_fromCookie is primary for jsessionID [getfield [HTTP::cookie "JSESSIONID"] "!" 1 ]" } else { log "Couldn't extract pool member from array, connection will be load-balanced!" } } else { NO COOKIE, need to extract from URI if jsessionid is found in the uri AND in the absense of the jsessionid cookie if { [string tolower [HTTP::uri]] contains "jsessionid" } { Set IP from list item 1 of the array by extracting jsession server reference from URI set serverIP_fromURI [lindex [ array get ::ServerList [lindex [split [findstr [HTTP::uri] "jsessionid" 11 "?"] "!" ] 1 ] ] 1] If an IP was found in the array if { $serverIP_fromURI ne "" } { Send the connection to the primary server pool myPool member $serverIP_fromURI log "From URI: Server $serverIP_fromURI is primary for jsessionID [lindex [split [findstr [HTTP::uri] "jsessionid" 11 "?"] "!" ] 0 ]" } else { log "Couldn't extract pool member from URI, connection will be load-balanced!" } } } } when HTTP_RESPONSE { if { [HTTP::header exists "X-WebLogic-Cluster-List"] }{ Set indexed variable with server cluster information set server_mappings [split [HTTP::header "X-WebLogic-Cluster-List"] "|" ] Remove header before returning to client HTTP::header remove "X-WebLogic-Cluster-List" init array if non-existent array set ::ServerList { } clear pre-existing array entries by re-initializing as blank array doesn't seem to do it array unset ::ServerList foreach servermap $server_mappings { set ::ServerList([getfield $servermap "!" 1]) [getfield [findclass [getfield $servermap "!" 2] $::intres_servers] " " 2] } } } when LB_FAILED { log "LB_FAILED: Server [LB::server addr] failed!" set lbfailed 1 Turn off least connections, set for round robin LB::mode rr Reselect another pool member. It might be failed server(s) once, but it won’t occur continuously with round robin LB::reselect pool myPool log "LB_FAILED: New server is [LB::server addr] " }
- Deb_Allen_18Historic F5 AccountNo problem, glad I could help.
- JRahm
Admin
I was going to wait until we get through our failure testing as there may be some enhancements on the way... - JRahm
Admin
Well, good news and bad news. Good news is everything works great under normal conditions. Bad news is this logic doesn't seem to do anything:when LB_FAILED { set failed_server [LB::server addr] log local0. "Connection to server $failed_server failed! Reselecting..." LB::mode rr LB::reselect pool MyPool for {set x 0} {$x<4} {incr x} { if { [LB::server addr] eq $failed_server } { LB::mode rr LB::reselect pool MyPool log local0. "Attempt $x ==>New server is [LB::server addr]" } } }
Recent Discussions
Related Content
DevCentral Quicklinks
* Getting Started on DevCentral
* Community Guidelines
* Community Terms of Use / EULA
* Community Ranking Explained
* Community Resources
* Contact the DevCentral Team
* Update MFA on account.f5.com
Discover DevCentral Connects