Forum Discussion
Tuomas_Jormola_
Nimbostratus
Apr 17, 2008Strange things happening while attempting universal persistence using JSESSIONID
Hi,
I'm setting up a Java web application behind a pair of F5 BIG-IP LTMs
running operating system version 9.3.1. The application is hosted on
a cluster of machines running Resin servlet container.
The backend nodes are not using any kind of shared session store,
so we need to direct each session to the same backend node that
served the initial request. Resin is configured to use JSESSIONID cookie
to store the session identifier. So based on documentation and
examples found here on DevCentral, I created a universal persistence
profile, and assigned that to the virtual server as the only
persistency profile. The iRule powering the profile is included below
(it also supports setting the session id in the request URI,
but cookies are preferred).
when RULE_INIT {
set ::debug 1
}
when CLIENT_ACCEPTED {
if { $::debug } {
set client [IP::client_addr]:[TCP::client_port]
}
}
when HTTP_RESPONSE {
if { [HTTP::cookie exists "JSESSIONID"] } {
set jsessionid [HTTP::cookie "JSESSIONID"]
persist add uie $jsessionid 3600
if { $::debug } {
log local0. "NEW PERSIST ENTRY client>$client< JSESSIONID>$jsessionid<"
}
}
}
when HTTP_REQUEST {
set jsessionid ""
set cookie_id ""
set uri [HTTP::uri]
set uri_id [findstr $uri "jsessionid=" 11 "?"]
if { [HTTP::cookie exists "JSESSIONID"] } {
set cookie_id [HTTP::cookie "JSESSIONID"]
}
if { $cookie_id ne "" } {
set jsessionid $cookie_id
} elseif { $uri_id ne "" } {
set jsessionid $uri_id
}
if { $jsessionid ne "" } {
persist uie $jsessionid 3600
}
if { $::debug } {
set table ""
if { $jsessionid ne "" } {
set table [persist lookup uie $jsessionid]
}
if { $table eq "" } {
log local0. "client>$client< uri>$uri< cookie_id>$cookie_id< uri_id>$uri_id< JSESSIONID>$jsessionid< table>null<"
} else {
log local0. "client>$client< uri>$uri< cookie_id>$cookie_id< uri_id>$uri_id< JSESSIONID>$jsessionid< table>[lindex $table 0] [lindex $table 1] [lindex $table 2]<"
}
}
}
when LB_SELECTED {
if { $::debug } {
set server [LB::server addr]:[LB::server port]
log local0. "client>$client< server>$server<"
}
}
when LB_FAILED {
if { $::debug } {
if { $jsessionid ne "" } {
if { $table ne "" } {
log local0. "client>$client< JSESSIONID>$jsessionid< table>[lindex $table 0] [lindex $table 1] [lindex $table 2]<"
} else {
log local0. "client>$client< JSESSIONID>$jsessionid< table>null<"
}
} else {
log local0. "client>$client< JSESSIONID>null< table>null<"
}
}
if { $jsessionid ne "" } { persist delete uie $jsessionid }
if { $table ne "" } { LB::reselect pool [lindex $table 0] }
}However, when this setup is in place, we noticed that requests of
a session were not actually always directed to the same node,
even though the logic seemed to work as sane values were printed in
the syslog by iRule debugging statements. I give an example using
the debug statements in the iRule and HTTP data captured using tcpdump
on the BIG-IP LTM when the web application was accessed with a browser.
Setup:
Client IP: 194.137.112.98
BE Nodes: 192.168.135.16:6889 and 192.168.135.17:6889
Here we have the first request from the client
(irrelevant HTTP headers omitted)
GET /littleredcap-demo/app/?lang=fi HTTP/1.1As you can see, we have no session cookie.
The request was served by 192.168.135.17 with response
HTTP/1.1 200 OK
Set-Cookie: JSESSIONID=abccmG4bh7OVaeO7KjCLr; path=/We now have the cookie. Corresponding debug log entries from the iRule:
Apr 17 14:30:24 tmm tmm[875]: Rule persist_jsessionid : client>194.137.112.98:8283< uri>/littleredcap-demo/app/?lang=fi< cookie_id>< uri_id>< JSESSIONID>< table>null<
Apr 17 14:30:24 tmm tmm[875]: Rule persist_jsessionid : client>194.137.112.98:8283< server>192.168.135.17:6998<
Apr 17 14:30:25 tmm tmm[875]: Rule persist_jsessionid : NEW PERSIST ENTRY client>194.137.112.98:8283< JSESSIONID>abccmG4bh7OVaeO7KjCLr<So the iRule logs that new universal persistence entry has been created
for this session id, and we're using 192.168.135.17:6998 as
the backend node for the session.
But then, with next request hitting the virtual server, things are
getting weird. The request that the browser sends in order to get some
CSS resource needed to render the front page looks like this.
GET /littleredcap-demo/css/app-layout.css HTTP/1.1
Cookie: JSESSIONID=abccmG4bh7OVaeO7KjCLrWe have the session id, as iRule log entry confirms
Apr 17 14:30:25 tmm tmm[875]: Rule persist_jsessionid : client>194.137.112.98:8276< uri>/littleredcap-demo/css/app-layout.css< cookie_id>abccmG4bh7OVaeO7KjCLr< uri_id>< JSESSIONID>abccmG4bh7OVaeO7KjCLr< table>test_pool 192.168.135.17 6998<This log entry finds the original backend node associated for
the session, 192.168.135.17. But the tcpdump capture and access log
on the backend 192.168.135.16 revealed that the actual request was
redirected to the node 192.168.135.16 instead! So persistency for
this esablished session was not honoured, and the default
scheduling algorithm that chooses the node from the pool was
applied instead.
Any idea why this happened? Can someone point out the flaw in
the iRule? Thanks.
10 Replies
- Kevin_Stewart
Employee
I may be missing something in your explanation, but is there a specific reason that you cannot use the BigIP builtin cookie persistence mechanism? With this the BigIP sends its own cookie to the client that indicates the LB node.
Kevin - Nicolas_Menant
Employee
Just one question: are you using oneconnect ?
If yes you should try to configure oneconnect with a mask of 255.255.255.255 or disable it. - Tuomas_Jormola_
Nimbostratus
Posted By nmenant on 04/17/2008 7:10 AM
Just one question: are you using oneconnect ?
If yes you should try to configure oneconnect with a mask of 255.255.255.255 or disable it.
oneconnect is not in use. - Tuomas_Jormola_
Nimbostratus
Hi,Posted By kevin.stewart on 04/17/2008 6:44 AM
I may be missing something in your explanation, but is there a specific reason that you cannot use the BigIP builtin cookie persistence mechanism? With this the BigIP sends its own cookie to the client that indicates the LB node.
Kevin
We want to minimize the number of cookies sent, and since a session id is already made available by the application, and the BIG-IP is supposed to be able to utilizie it, why not use that.
Also in the future, the requirements might change so that we can't use cookies at all,
in which case the application server is configured to deliver the session id in the request uri.
In order to support this, we would have to write a universal persistence profile anyway. - Tuomas_Jormola_
Nimbostratus
Looks like adding a OneConnect profile with mask 255.255.255.255 to the virtual server solved the problem. - Nicolas_Menant
Employee
Glad it works with oneconnect.
the reason is simple: Click here
By default persist command will work for when the TCP connection is established. Then it won't do any more loadbalacing for each HTTP request except if ordered to (pool pool1 member 10.0.0.1)
When you enable oneconnect each HTTP request is load balanced. Really useful when facing piplening !"When a OneConnect profile is enabled for a virtual server, and an HTTP client sends multiple requests within a single connection, the BIG-IP LTM is able to process each HTTP request individually. The BIG-IP LTM sends the HTTP requests to different destination servers if necessary. Without a OneConnect profile enabled for the virtual server, the BIG-IP system performs load-balancing for each TCP connection." - Andy_Herrman_22
Nimbostratus
Sounds like you got it working, but I think I saw a bug in your iRule that could cause some problems later on.
To get the session ID out of the URL you use the following:set uri_id [findstr $uri "jsessionid=" 11 "?"]
This will get the string after "jsessionid=' until a "?" is found. However, URL parameters are delimited by a "&", not a "?". So, if you have a url like this:http://somedomain.com/some/path?jsessionid=MYSESSIONID
it'll work fine, but if you have this:http://somedomain.com/some/path?jsessionid=MYSESSIONID&someotherparam=FOOBAR
it won't work, as the jsessionid string you get back will end up being "MYSESSIONID&someotherparam=FOOBAR"
If your application doesn't use other query params, or always puts jsessionid as the last query param then it will work, but if any other params are put after jsessionid then you'll get the wrong value. - hoolio
Cirrostratus
aherrman,
I think the logic is okay. The jsessionid is typically inserted in response redirects and content links before the query string:
http://somedomain.com/some/path;jsessionid=MYSESSIONID?param1=val1&someotherparam=FOOBAR
Aaron - Tuomas_Jormola_
Nimbostratus
Posted By hoolio on 04/25/2008 12:58 AM
aherrman,
I think the logic is okay. The jsessionid is typically inserted in response redirects and content links before the query string:
http://somedomain.com/some/path;jsessionid=MYSESSIONID?param1=val1&someotherparam=FOOBAR
Aaron
Yep, at least the environment we use (Resin 3.0 serving web applications created with Wicket framework) generates URLs containing the sessionid in this format, and the iRule copes with that. I did not have to change the iRule at all to get this working, all that was needed was the OneConnect profile. - dimka___104021
Nimbostratus
Hi,
We have exactly same problem, can you post here you oneconnect profile settings?
tia,
Help guide the future of your DevCentral Community!
What tools do you use to collaborate? (1min - anonymous)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