Forum Discussion

Erki_Märks_2779's avatar
Erki_Märks_2779
Icon for Nimbostratus rankNimbostratus
Nov 29, 2007

Bea Weblogic persistence

We are using bigip with Weblogic cluster. Since session is replicated only on 2 nodes, we had to find a solution that knew the additional server where the original session was replicated and if the primary node was down the irule had to switch over to the second node. I finally found a solotion that seems to work.

 

Any ideas how to improve/change it?

 

 

 

 

when RULE_INIT {

 

array set ::nodelist { }

 

array unset ::nodelist

 

}

 

 

when CLIENT_ACCEPTED {

 

set insert_wls_headers 1

 

set reselect 0

 

set retries 0

 

set node1 ""

 

set node2 ""

 

set lastServer ""

 

}

 

 

when HTTP_REQUEST {

 

 

set request [HTTP::request]

 

set uri [HTTP::uri]

 

set hostname [HTTP::header host]

 

 

if { $insert_wls_headers } {

 

HTTP::header insert WL-Proxy-SSL false

 

HTTP::header insert WL-PATH-PREPEND test

 

HTTP::header insert WL-Proxy-Client-IP [IP::client_addr]

 

HTTP::header insert Proxy-Client-IP [IP::client_addr]

 

HTTP::header insert X-WebLogic-Request-ClusterInfo true

 

set insert_wls_headers 0

 

}

 

 

switch -regexp $uri {

 

mainservlet {

 

set jss [findstr [HTTP::uri] "jsessionid" 11 "?"]

 

set jsess [getfield $jss "!" 1]

 

set jvmid1 [getfield $jss "!" 2]

 

set jvmid2 [getfield $jss "!" 3]

 

 

if { [ info exists ::nodelist($jvmid1) ] } {

 

set node1 $::nodelist($jvmid1)

 

}

 

if { [ info exists ::nodelist($jvmid2) ] } {

 

set node2 $::nodelist($jvmid2)

 

}

 

 

if { "$node1" != "" &&

 

[LB::status pool prelive_wls_pool member $node1 7001] != "down" &&

 

"$lastServer" != "$node1" && $reselect < 2 && $retries < 2 } {

 

 

pool prelive_wls_pool member $node1 7001

 

 

} elseif { "$node2" != "" &&

 

[LB::status pool prelive_wls_pool member $node2 7001] != "down" &&

 

"$lastServer" != "$node2" && $reselect < 2 && $retries < 2 } {

 

 

pool prelive_wls_pool member $node2 7001

 

} else {

 

pool prelive_wls_pool

 

 

} default {

 

pool prelive_wls_static_pool

 

}

 

}

 

}

 

 

when LB_FAILED {

 

LB::down

 

if { [matchclass $uri starts_with $::servlets] } {

 

set lastServer [LB::server addr]

 

incr reselect

 

if { [LB::server addr] == "" || $reselect > [active_members prelive_wls_pool ] } {

 

reject

 

return

 

} else {

 

LB::reselect pool prelive_wls_pool

 

if { "$lastServer" == "$node1" && "$node2" != "" && $reselect < 2 &&

 

[LB::status pool prelive_wls_pool member $node2 7001] != "down" } {

 

 

pool [LB::server pool] member $node2 7001

 

 

} elseif { "$lastServer" == "$node2" && "$node1" != "" && $reselect < 2 &&

 

[LB::status pool prelive_wls_pool member $node1 7001] != "down" } {

 

 

pool [LB::server pool] member $node1 7001

 

 

}

 

}

 

}

 

}

 

 

when HTTP_RESPONSE {

 

if { [HTTP::header exists "X-WebLogic-Cluster-List"] }{

 

set server_mappings [split [HTTP::header "X-WebLogic-Cluster-List"] "|" ]

 

HTTP::header remove "X-WebLogic-Cluster-List"

 

foreach servermap $server_mappings {

 

set jvmid [getfield $servermap "!" 1]

 

set ipp [getfield $servermap "!" 2]

 

set ip1 [expr {($ipp >> 24) & 0xff}]

 

set ip2 [expr {($ipp >> 16) & 0xff}]

 

set ip3 [expr {($ipp >> 8) & 0xff}]

 

set ip4 [expr {$ipp & 0xff}]

 

if { [ info exists ::nodelist($jvmid) ] } {

 

log "jvmid: $jvmid; ip: $ip1.$ip2.$ip3.$ip4"

 

} else {

 

set ::nodelist([getfield $servermap "!" 1]) "$ip1.$ip2.$ip3.$ip4"

 

log "jvmid: $jvmid; ip: $ip1.$ip2.$ip3.$ip4"

 

}

 

}

 

}

 

 

if { [matchclass $uri starts_with $::servlets] } {

 

set lastServer [LB::server addr]

 

switch -regexp [HTTP::status] {

 

50[0-3]$ {

 

LB::down

 

LB::detach

 

incr retries

 

if {$retries < 3 && [ info exists ::nodelist($jvmid2) ] } {

 

log "WARNING: $host retrying $retries"

 

HTTP::retry $request

 

}

 

}

 

}

 

}

 

}
  • If LB_FAILED or http errors direct the user to the mainservlet :

     

     

    else {

     

     

    if { $reselect > 1 || $retries > 1 } {

     

    HTTP::uri "/test/mainservlet"

     

    }

     

     

    pool prelive_wls_pool

     

    }

     

  • Yes, but with regex its simple, for example:

     

     

    ^/(files|lib|js|img|test|..)/(?!(.*)(servlet1|servlet2).*$) {

     

    pool1

     

    } default {

     

    pool2

     

    }
  • This irule should work fine, tested with wl8

     

     

    when RULE_INIT {

     

    array set ::nodelist { }

     

    array unset ::nodelist

     

    }

     

     

    when CLIENT_ACCEPTED {

     

    set insert_wls_headers 1

     

    set reselect 0

     

    set retries 0

     

    set node1 ""

     

    set node2 ""

     

    set lastServer ""

     

    }

     

     

    when HTTP_REQUEST {

     

     

    set request [HTTP::request]

     

    set uri [HTTP::uri]

     

    set hostname [HTTP::header host]

     

     

    if { $insert_wls_headers } {

     

    HTTP::header insert WL-Proxy-SSL false

     

    HTTP::header insert WL-PATH-PREPEND test

     

    HTTP::header insert WL-Proxy-Client-IP [IP::client_addr]

     

    HTTP::header insert Proxy-Client-IP [IP::client_addr]

     

    HTTP::header insert X-WebLogic-Request-ClusterInfo true

     

    set insert_wls_headers 0

     

    }

     

     

    switch -regexp $uri {

     

    mainservlet {

     

    set jss [findstr [HTTP::uri] "jsessionid" 11 "?"]

     

    set jsess [getfield $jss "!" 1]

     

    set jvmid1 [getfield $jss "!" 2]

     

    set jvmid2 [getfield $jss "!" 3]

     

     

    if { [ info exists ::nodelist($jvmid1) ] } {

     

    set node1 $::nodelist($jvmid1)

     

    }elseif { [ info exists ::nodelist($jvmid2) ] } {

     

    set node2 $::nodelist($jvmid2)

     

    }

     

     

    if { "$node1" != "" &&

     

    [LB::status pool prelive_wls_pool member $node1 7001] != "down" &&

     

    "$lastServer" != "$node1" && $reselect < 2 && $retries < 2 } {

     

     

    pool prelive_wls_pool member $node1 7001

     

     

    } elseif { "$node2" != "" &&

     

    [LB::status pool prelive_wls_pool member $node2 7001] != "down" &&

     

    "$lastServer" != "$node2" && $reselect < 2 && $retries < 2 } {

     

     

    pool prelive_wls_pool member $node2 7001

     

    } else {

     

    pool prelive_wls_pool

     

     

    } default {

     

    pool prelive_wls_static_pool

     

    }

     

    }

     

    }

     

     

    when LB_FAILED {

     

    LB::down

     

    if { [matchclass $uri starts_with $::servlets] } {

     

    set lastServer [LB::server addr]

     

    incr reselect

     

    if { [LB::server addr] == "" || $reselect > [active_members prelive_wls_pool ] } {

     

    reject

     

    return

     

    } else {

     

    LB::reselect pool prelive_wls_pool

     

    if { "$lastServer" == "$node1" && "$node2" != "" && $reselect < 2 &&

     

    [LB::status pool prelive_wls_pool member $node2 7001] != "down" } {

     

     

    pool [LB::server pool] member $node2 7001

     

     

    } elseif { "$lastServer" == "$node2" && "$node1" != "" && $reselect < 2 &&

     

    [LB::status pool prelive_wls_pool member $node1 7001] != "down" } {

     

     

    pool [LB::server pool] member $node1 7001

     

     

    }

     

    }

     

    }

     

    }

     

     

    when HTTP_RESPONSE {

     

    if { [HTTP::header exists "X-WebLogic-Cluster-List"] }{

     

    set server_mappings [split [HTTP::header "X-WebLogic-Cluster-List"] "|" ]

     

    HTTP::header remove "X-WebLogic-Cluster-List"

     

    foreach servermap $server_mappings {

     

    set jvmid [getfield $servermap "!" 1]

     

    set ipp [getfield $servermap "!" 2]

     

    set ip1 [expr {($ipp >> 24) & 0xff}]

     

    set ip2 [expr {($ipp >> 16) & 0xff}]

     

    set ip3 [expr {($ipp >> 8) & 0xff}]

     

    set ip4 [expr {$ipp & 0xff}]

     

    if { [ info exists ::nodelist($jvmid) ] } {

     

    log "jvmid: $jvmid; ip: $ip1.$ip2.$ip3.$ip4"

     

    } else {

     

    set ::nodelist([getfield $servermap "!" 1]) "$ip1.$ip2.$ip3.$ip4"

     

    log "jvmid: $jvmid; ip: $ip1.$ip2.$ip3.$ip4"

     

    }

     

    }

     

    }

     

     

    if { [matchclass $uri starts_with $::servlets] } {

     

    set lastServer [LB::server addr]

     

    switch -regexp [HTTP::status] {

     

    5 0 [ 0 - 3 ]$ {

     

    LB::down

     

    LB::detach

     

    incr retries

     

    if {$retries < 3 && [ info exists ::nodelist($jvmid2) ] } {

     

    log "WARNING: $host retrying $retries"

     

    HTTP::retry $request

     

    }

     

    }

     

    }

     

    }

     

    }
  • Deb_Allen_18's avatar
    Deb_Allen_18
    Historic F5 Account
    nice, thanks for the post.

    I've been noodling with this idea off & on for the last year without an environment to test in, looks like you may have nailed it.

    Regarding optimization:

    You probably want to take a look at this article Colin recently wrote about polymorphic operators (Click here) and replace some of them with the appropriate string operators where ever string-only comparisons take place.

    And I agree with Colin on eliminating the regex ops as much as possible. While it seems like a trivial choice, (especially if you are as comfortable with regex as you obviously are), the cost of firing up the regex engine is apparently obscenely expensive in comparison with the alternatives, especially the iRules native comparison operators, so you might consider using them in place of your 2 "switch -regex's"

    I'd replace:
    switch -regexp $uri {         
             mainservlet {
    with
    switch -glob $uri {     
             *mainservlet* {
    only if you need to match multiple URI's.

    Otherwise use the even more efficient
    if { $uri contains "mainservlet"} {
    for a single test like this.

    I'd also replace:
    switch -regexp [HTTP::status] {     
             50[0-3]$ {
    with
    if { [HTTP::status] starts_with "50"} {

    HTH

    /deb
  • Deb_Allen_18's avatar
    Deb_Allen_18
    Historic F5 Account
    corrected some syntax, but still looks like

    5 0 [ 0 - 3 ]

    (less the spaces)

    Is being replaced with

    5 0 Ύ - 3 ]
    (less the spaces)

    /deb