Learn F5 Technologies, Get Answers & Share Community Solutions Join DevCentral

Filter by:
  • Solution
  • Technology
Answers

Jsession persist with multiple cookie names

I'm trying to use the recommended method for persisting on JSESSION ID...

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

However, each of my 6 web server prefixs the Jsession cookie with it's own hostname. Therefore I have a rather ugly version of the above rule. Is there a smarter way of doing this? BTW, the rule doesn't actually work either yet!

Any advice for this newb much appreciated.


when CLIENT_ACCEPTED {
set add_persist 1
}

when HTTP_RESPONSE {
if { [HTTP::cookie exists "serverolw1-8010-PORTAL-JSESSIONID"] and $add_persist } {
persist add uie [HTTP::cookie "serverolw1-8010-PORTAL-JSESSIONID"]
set add_persist 0
}

if { [HTTP::cookie exists "serverolw2-8010-PORTAL-JSESSIONID"] and $add_persist } {
persist add uie [HTTP::cookie "serverolw2-8010-PORTAL-JSESSIONID"]
set add_persist 0
}

if { [HTTP::cookie exists "serverinw1-8030-PORTAL-JSESSIONID"] and $add_persist } {
persist add uie [HTTP::cookie "serverinw1-8030-PORTAL-JSESSIONID"]
set add_persist 0
}

if { [HTTP::cookie exists "serverinw2-8030-PORTAL-JSESSIONID"] and $add_persist } {
persist add uie [HTTP::cookie "serverinw2-8030-PORTAL-JSESSIONID"]
set add_persist 0
}

if { [HTTP::cookie exists "serverolw1-8030-PORTAL-JSESSIONID"] and $add_persist } {
persist add uie [HTTP::cookie "serverolw1-8030-PORTAL-JSESSIONID"]
set add_persist 0
}

if { [HTTP::cookie exists "serverolw2-8030-PORTAL-JSESSIONID"] and $add_persist } {
persist add uie [HTTP::cookie "serverolw2-8030-PORTAL-JSESSIONID"]
set add_persist 0
}

}
when HTTP_REQUEST {
if { [HTTP::cookie exists "serverolw1-8010-PORTAL-JSESSIONID"] } {
persist uie [HTTP::cookie "serverolw1-8010-PORTAL-JSESSIONID"]
}

if { [HTTP::cookie exists "serverolw2-8010-PORTAL-JSESSIONID"] } {
persist uie [HTTP::cookie "serverolw2-8010-PORTAL-JSESSIONID"]
}

if { [HTTP::cookie exists "serverolw1-8030-PORTAL-JSESSIONID"] } {
persist uie [HTTP::cookie "serverolw1-8030-PORTAL-JSESSIONID"]
}

if { [HTTP::cookie exists "serverolw2-8030-PORTAL-JSESSIONID"] } {
persist uie [HTTP::cookie "serverolw2-8030-PORTAL-JSESSIONID"]
}

if { [HTTP::cookie exists "serverinw1-8030-PORTAL-JSESSIONID"] } {
persist uie [HTTP::cookie "serverinw1-8030-PORTAL-JSESSIONID"]
}

if { [HTTP::cookie exists "serverinw2-8030-PORTAL-JSESSIONID"] } {
persist uie [HTTP::cookie "serverinw2-8030-PORTAL-JSESSIONID"]
}
}





0
Rate this Question

Answers to this Question

placeholder+image
USER ACCEPTED ANSWER & F5 ACCEPTED ANSWER
Not tested, but maybe something along these lines?
when CLIENT_ACCEPTED {
set add_persist 1
}
when HTTP_RESPONSE {
# pull out cookie name by searching thru list for matching pattern
set cname [lindex [HTTP::cookie names] [lsearch [HTTP::cookie names] "server*JSESSIONID"]]
# add persistence record if found
if {$cname != ""}{
persist add uie [HTTP::cookie $cname]
set add_persist 0
}
}
when HTTP_REQUEST {
# pull out cookie name by searching thru list for matching pattern
set cname [lindex [HTTP::cookie names] [lsearch [HTTP::cookie names] "server*JSESSIONID"]]
# then persist on it if found
if {$cname != ""}{
persist uie [HTTP::cookie $cname]
}
}


Let us know if that worked, feel free to post to the codeshare if you find it useful.

/d
0
placeholder+image
USER ACCEPTED ANSWER & F5 ACCEPTED ANSWER
Edited to correct syntax/conditions (really wish we had preview...!)
0
placeholder+image
USER ACCEPTED ANSWER & F5 ACCEPTED ANSWER
You know, the more I thought about it, the more I realized there may be some issues with this approach. Here are my thoughts:

1) If the initial backend server goes down mid-session, by default the client will not be forced to re-handshake again on a Keep-Alive connection, which means the add_persist flag should NOT be set unless either of the following is true: no connections will be Keep-Alive (unlikely) OR the "Action on service down" setting on the virtual is set to "Reject", which will send a RESET to the client forcing a new handshake.

2) Since the "session add" command doesn't specify a timeout value, if this iRule is applied directly to the virtual server as a resource, the persistence entries will never time out, only going away when connections are cleared or TMM restarts, which means you are running a risk of memory exhaustion at some point.

3) Having a different cookie name set by each server sort of flies in the face of the cookie persistence concept, which, in a nutshell is: A single place to look for the last server with which the client connected. Again, if the initial backend server goes down mid-session, and the client is re-LB to a new server (which sets a new persistence cookie with a brand new name), the client now has *2* persistence cookies with different names for the same site/session. Since inbound cookies contain no timestamp info, there is no good way to determine which cookie is more current. If session cookies are used, multiple cookies may not interfere with persistence since the value of each session ID *should* be the same for the duration of the session, but in reality, some jsessionid implementations append serverIDs or other variable info to the actual sessionID. In that case, a new server would set a different cookie value, which it turn would create a new persistence record, and there's no guarantee which would be followed. On the other hand, for cookies with an expiry, there is a definite possiblility that the browser could end up with multiple cookies each with different name AND different values. Regardless of cookie type, yet another cookie would be set (and sent) each time the session/browser uses a new server, which isn't optimal.

Hope that made sense.

Bottom line, I'd recommend the following:

* Remove the "add_persist" flag logic OR set "Reject" as the Action on Service Down

* Apply the rule under a Universal persistence profile specifying an appropriate timeout OR add a timeout parameter to the "session add" command in the iRule

* Enable OneConnect on the virtual server to ensure new persistence data is looked up on Keep-Alive connections.

* Verify the actual content of the cookie value, and if necessary, parse out & persist on *only* the session ID portion of the cookie value

* Re-configure your servers to share the same cookie name, or if that's not possible, make sure they are sending session cookies.

HTH, and definitely post back if you want clarification on any of that.


/deb
0
placeholder+image
USER ACCEPTED ANSWER & F5 ACCEPTED ANSWER
Hi Deb,

Thanks for the detailed reply. Sorry it's taken a while to respond.

As per your suggestions , I have managed to convince our web server admin to remove the host prefix from all servers in the pool, so we now have the same JSESSION cookie name for all servers. :D

I wasn't sure where to remove the flag logic - this concern still applies to the single-cookie-name irule - correct?

So ultimately, the servers now have same cookie name, I have applied "reject on service down" for the relevent pool, and have set up a new Persistence Profile Hash, which specifies the timeout value and the simplified irule (below).

I'll let you know how testing goes.

Thanks again!


when CLIENT_ACCEPTED {
set add_persist 1
}
when HTTP_RESPONSE {
if { [HTTP::cookie exists "JSESSIONID"] and $add_persist } {
persist add uie [HTTP::cookie "JSESSIONID"]
set add_persist 0
}
}
when HTTP_REQUEST {
if { [HTTP::cookie exists "JSESSIONID"] } {
persist uie [HTTP::cookie "JSESSIONID"]
} else {
}
}
0
placeholder+image
USER ACCEPTED ANSWER & F5 ACCEPTED ANSWER
I'd recommend using this version from the codeshare: http://devcentral.f5.com/wiki/default.aspx/iRules/Weblogic_JSessionID_Persistence.html (Click here)

I actually edited the flag logic out of the original post from whence that iRule came, since from what I can tell, a server failure would result in failed persistence to the next-selected server.

Granted, this way seems less efficient, since the cookie will be evaluated & persistence record updated on each response, but I think it will produce a more palatable user experience and recovery upon a server failure.

Here's the scenario I pictured:
Clientside Keep-alive connection gets re-LB on the backend due to a server failure mid-connection (clientside connection is unaffected). New server sets new persistence token value, but due to the flag, persistence table is never updated with the new persistence value, and the new session on the new server flounders and may never succeed until keepalives expire or a new connection is otherwise triggered (like the user closing browser in frustration...)

I've been meaning to go chat w/unRuleY about that, but haven't gotten around to it. I guess it's about time...

/deb
0
placeholder+image
USER ACCEPTED ANSWER & F5 ACCEPTED ANSWER
Hi. I implemented the codeshare irule with a Universal Persistence Profile & TTL set, OneConnect turned on in HTTP profile...

when HTTP_REQUEST {
if { [HTTP::cookie exists "JSESSIONID"] } {
persist uie [HTTP::cookie "JSESSIONID"]
}
}
when HTTP_RESPONSE {
if { [HTTP::cookie exists "JSESSIONID"] and $add_persist } {
persist add uie [HTTP::cookie "JSESSIONID"]
}
}

It worked ok for any existing "live" sessions, but if I cleared cookies and tried a new connection, I just got a 503 error each time. I haven't traced to see if that's coming from F5 or backend server, but I suspect it's F5. Is there anything obviously wrong with the irule? If traffic doesn't match anything in the irule, by default it should go to the configured pool shouldn't it?

Anyway, I then used the old irule with persist flags, using same Universal Persistence Profile, TTL & OneConnect setup. Then tested what happened when the backed server went down. Here's that irule...

when CLIENT_ACCEPTED {
set add_persist 1
}
when HTTP_RESPONSE {
if { [HTTP::cookie exists "JSESSIONID"] and $add_persist } {
persist add uie [HTTP::cookie "JSESSIONID"]
set add_persist 0
}
}
when HTTP_REQUEST {
if { [HTTP::cookie exists "JSESSIONID"] } {
persist uie [HTTP::cookie "JSESSIONID"]
} else {
}
}

So I set up a session, then shutdown the relevant backend server. The next client HTTP request had the current JSESSIONID cookie in it, but the response from (new) backend server had a new set-cookie header. The app servers are not "clustered" in any way, so we did get logged out of the existing session and have to re-auth on the application. But this is expected behaviour, and it persisted fine on the new server, with the updated JSESSIONID cookie. No need to close browser, or do anything special to break the TCP session.

Hope this is useful - if you think I should try other scenarios, then let me know. Should have a model setup for this all week.

Thanks again
0
placeholder+image
USER ACCEPTED ANSWER & F5 ACCEPTED ANSWER

Nice job testing.
I was sort of expecting to to come back with such a report...

Results are at least partially dependent on the keepalive behaviour of your clients. I have at least one field report of the add_persist flag causing trouble with connections coming thru proxies that are using Keepalives and aggregating multiple sessions on the same connection, so it's better to discretely update the persistence value from the cookie on each response. (or just keep that in your back pocket if anybody says at the end of a meeting "You know, this really weird thing happens, but only every once in a while...")

ps: I just edited the codeshare version to remove a reference to a non-existent variable. Not sure if that could have caused a 503, but it's possible, since it would cause the rule throw a a runtime error & abort processing.

/d


0
placeholder+image
USER ACCEPTED ANSWER & F5 ACCEPTED ANSWER

ps: I just edited the codeshare version to remove a reference to a non-existent variable. Not sure if that could have caused a 503, but it's possible, since it would cause the rule throw a a runtime error & abort processing.


Yes, this fixed the irule - it's all working ok now.

Proxy problems is the reason for us looking at this JSESSION irule. We were using cookie-insert persistence, but our bluecoat proxies didn't like it. So we were advised to try this irule. Unfortunately, none of the irules we've tested works with the default proxy settings. We isolated the problem to the pipelining function of the proxy (as you mention in your last reply!). If you disable this, the JSESSION irule works ok.

As we delved deeper, it appeared to be the pre-fetch pipelining functionality which was causing all the problems. Here's what we did...

1) Clear proxy cache, browser cache and browser cookies.
2) Connect & Login to app server (via proxy and then LTM) and get html page.
3) Proxy returns html page to client, along with set-cookie (JSESSIONID)
4) Proxy then tries to "pre-fetch" static objects listed in the html (gif's, jpeg's etc) but doesn't send the client cookie. Get's LB-ed to different web server, and a 403 error as not authenticated.
5) Client sends HTTP requests for same objects listed in html to proxy. Proxy sends 403 error from cache.
6) Client get's logged out from session (not entirely sure why if 403 is delivered from cache)

We only really got to the bottom of this when we cleared the proxy cache each time. Without this, the problem was a lot more difficult to generate, as many objects were succesfully delivered from cache.

Anyway, we are happy with our solution now, using the codeshare irule, and disabling pipelining on the bluecoat (for this app). I don't really have time to try and fix this pre-fetch issue purely with an irule - much as I'd like to try!

Thanks again for your help.
0