Forum Discussion

MaheshV_65076's avatar
MaheshV_65076
Icon for Nimbostratus rankNimbostratus
May 22, 2008

jsessionid persistence

We recently started to use F5 8800 & 6800 in our environment. But we aren’t able to make sticky sessions work.

 

I browsed through the dev central and found couple of solutions (

 

http://devcentral.f5.com/Default.aspx?tabid=53&forumid=5&tpage=1&view=topic&postid=60848691

 

http://devcentral.f5.com/default.aspx?tabid=53&view=topic&forumid=5&postid=8098 ) but it isn’t working or robust enough. For instance

 

a)how to delete entries from persistence hash

 

b)if browser is not closed for a long time and it sends an old stale jsessionid, this iRule should forward the request to the virtual server rather than rejecting the request.

 

 

In the following Universal persistence rule should we use set SessionId [findstr [[HTTP::header] Set-Cookie] "JSessionId" 11] ?

 

 

when HTTP_RESPONSE {

 

if { [HTTP::cookie exists "JSESSIONID"] } {

 

set trimID [lindex [split [HTTP::cookie "JSESSIONID"] "!" ] 0]

 

if { [persist lookup uie $trimID] equals "" } {

 

persist add uie $trimID 1800

 

log "added persistent entry $trimID for server [LB::server addr]"

 

} else { log "continued sessionID $trimID for server [LB::server addr]" }

 

}

 

}

 

when HTTP_REQUEST {

 

if { [active_members MyPool] == 0 } {

 

HTTP::redirect "http://[HTTP::header "X-Forwarded-Host"]/myUri.html"

 

}

 

if { [HTTP::header exists "X-Forwarded-Host"] } {

 

HTTP::header replace "Host" [HTTP::header "X-Forwarded-Host"]

 

}

 

if { not [HTTP::cookie exists "MyCookie"] } {

 

set jsess [findstr [HTTP::uri] "jsessionid" 11 "!"]

 

if { $jsess != "" } {

 

persist uie $jsess 1800

 

log "Used URI, value is $jsess, server [LB::server addr]"

 

}

 

} else {

 

log "used Cookie Insert, value is [HTTP::cookie "MyCookie"]"

 

}

 

}

 

Jsessionid is session cookie which does not have time stamp when it is received by F5 from the server.

 

In the above iRule, when a http request is received the F5 will route the request to the original physical node where the jsessionid was created?

 

Now how do I flush the persistence hash in F5?

 

 

You may be aware that jsessionid cookie is created by a Java Application server. The server also determines when the cookie is stale and generates a new session cookie. Since this is a session (inline) cookie, cookie expiration is not set. This is a standard Java implementation.

 

As a result both the browser and the F5 do not have the logic to determine when the jsessionid cookie has expired. This is particularly a problem where there is no explicit “user logout” call from the browser.

 

 

One more point is, that jsessionid expiration is an idle timeout value. This means it is renewed on the server side with every request.

 

 

Is there a more robust iRule to make the sticky session work?

 

 

Appreciate your help.

 

 

4 Replies

  • Hamish's avatar
    Hamish
    Icon for Cirrocumulus rankCirrocumulus

    JSESSIONID is a cookie... So I'd use hash cookie persistence on the cookie JSESSIONID myself rather than a custom iRule... It's quicker and less prone to issues unless you have something specific required that means you need more control (but as you're essentially doing what the hash does anyway, I can't see the irule would be better in this unstance)

     

    Also make sure your action on service down is set appropriately for when ghe node fails...

     

    H

     

  • Hi,

     

     

    Can you elaborate on what's not working with the iRule?

     

     

    To answer your questions:

     

     

    a) how to delete entries from persistence hash

     

     

    The persistence table entries are removed after the timeout expires. In the code you listed above, it's set to 1800 seconds. If you wanted to manually delete a persistence record from the iRule, you could use 'persist delete ' (Click here).

     

     

    b) if browser is not closed for a long time and it sends an old stale jsessionid, this iRule should forward the request to the virtual server rather than rejecting the request.

     

     

    Using the above rule, no request should ever get dropped or rejected. If a request contains a persistence token (either in the URI or the cookie) which has already expired and been removed from the BIG-IP persistence table, then the request will be load balanced to a new pool member.

     

     

    If you don't want to use session-based persistence, you could either configure the application or the iRule to set an expiration time on the cookie (Click here). This would instruct the client browser to not send the cookie after a certain amount of time.

     

     

    Aaron
  • Deb_Allen_18's avatar
    Deb_Allen_18
    Historic F5 Account
    As hoolio mentions, you can delete entries using the “session delete” or “persist delete” commands, but entries will expire out of the table with the idle timeout expiry. In your code, the timeout is set to 1800 seconds, or 30 minutes.

     

     

    That should happen by default unless your rule specifies otherwise. if the timeout is set to match the cookie timeout, or (the intended application idle timeout if using session cookies).

     

     

    There is actually a slightly more efficient example in the codeshare here (uses a bit simpler approach for the response): Click here

     

    (Note that for this version, timeouts are controlled by the persistence profile via which it is applied to the virtual server.)

     

     

    I’d change your request logic also so the logic after the redirect only runs if the redirect doesn’t.

     

     

    You also mentioned in email that this solution isn't working across http & https virtuals, and that requires a specific session command parameter "any virtual"

     

     

    I’d recommend using something more along these lines (although you might have to adjust what part of jsessionid value you are using):

     

     

     
     when HTTP_REQUEST { 
        if { [active_members MyPool] == 0 } { 
           HTTP::redirect "http://[HTTP::header "X-Forwarded-Host"]/myUri.html" 
        } else { 
           if { [HTTP::header exists "X-Forwarded-Host"] } { 
              HTTP::header replace "Host" [HTTP::header "X-Forwarded-Host"] 
           } 
           if { [HTTP::cookie exists "JSessionID"] } { 
              log "used Cookie, value is [HTTP::cookie "JSessionID"]" 
              persist uie {[HTTP::cookie "JSessionID"] any virtual} 
           } else {     
              set jsess [findstr [HTTP::uri] "JSessionID" 11 ";"]     
              if { $jsess != "" } {     
                 persist uie {$jsess any virtual} 
              } 
           }     
        } 
     } 
     when HTTP_RESPONSE {     
         if { [HTTP::cookie exists "JSessionID"] } {     
            persist add uie {[HTTP::cookie "JSessionID"] any virtual} 
         }     
     }     
     

     

     

    HTH

     

    /deb
  • Thanks Deb for your quick response. This solution works until the node where the session is persistent fails. At that point we see an F5 Proxy error. Any suggestions to help with this?

     

     

    Apart from this, it would be nice to add to a relative timer in the persist call. For instance, in the following persist call after 1800 seconds F5 will abruptly flush the jsessionid cookied from its cache.

     

    persist add uie {[HTTP::cookie "JSessionID"] any virtual} 1800

     

     

    Instead I would like to have a relative timer to simulate session cookie timer i.e the cookie expiration time should be current time + 1800.