Forum Discussion

Wade_Miller_113's avatar
Wade_Miller_113
Icon for Nimbostratus rankNimbostratus
Dec 11, 2007

Need persistance assistance

 

So I have a non-standard tcp protocol that I need to load balance with the following conditions.

 

 

1) multiple clients with the same "channel identifier" in the first part of the tcp payload need to persist to the same server.

 

 

2) if there are no active sessions for the "channel identifier" then load balance and populate a key in the session table.

 

 

3) If the "channel identifier" exists in the session table then persist the new session to the same nodes as the rest of the matching sessions.

 

 

4) once the the "channel identifier" is associated with a node, only that node can handle requests for that "channel identifier."

 

 

5) once a day, all session/persistance info for this vip/pool must be flushed. This can be done by fairly low session timeout value and stopping all nodes for a period greater than this timeout value.

 

 

The below irule seems to work ok in limited testing, but there are a couple scenerios that could cause it to fail.

 

 

What if a node fails and the 300-400 clients that were connected to the failed node all reconnect at the same time?

 

 

Since there could then be multiple requests at the same time and a few hundred milliseconds before the first connection populates the session table, could this result in load balancing multiple clients with the same "channel identifier" to different nodes?

 

 

Is there some sort of serialization or locking in the session table that could/would prevent this?

 

 

What can I do to make this work without rewriting the application?

 

 

Thanks/Wade

 

 

------------------------------------------------------

 

 

when CLIENT_ACCEPTED {

 

TCP::collect 44

 

}

 

when CLIENT_DATA {

 

set ConStr [TCP::payload 44]

 

set SessionID [substr [getfield $ConStr "@" 2] 0 " CHID" ]

 

log local0.info $SessionID

 

set PersistTo [session lookup uie $SessionID]

 

log local0.info $PersistTo

 

if { $PersistTo equals "" } {

 

pool [LB::server pool]

 

log local0.info "No session ID, load balancing the connection."

 

} else {

 

pool [LB::server pool] member $PersistTo

 

log local0.info "$SessionID sent to $PersistTo"

 

}

 

}

 

when SERVER_CONNECTED {

 

if { $PersistTo equals "" } {

 

session add uie $SessionID [IP::server_addr]:[serverside {TCP::remote_port}]

 

log local0.info "Added $SessionID to [IP::server_addr]:[serverside {TCP::remote_port}]"

 

} else {

 

log local0.info "$SessionID already exists to $PersistTo"

 

}

 

}
  • spark_86682's avatar
    spark_86682
    Historic F5 Account

    The below irule seems to work ok in limited testing, but there are a couple scenerios that could cause it to fail.

    Hm. I'm not sure I understand. Are you saying that you think these could cause it to fail, or are you actually seeing failure that you'd like to diagnose?

    What if a node fails and the 300-400 clients that were connected to the failed node all reconnect at the same time?

    Since there could then be multiple requests at the same time and a few hundred milliseconds before the first connection populates the session table, could this result in load balancing multiple clients with the same "channel identifier" to different nodes?

    Is there some sort of serialization or locking in the session table that could/would prevent this?

    iRule execution is single threaded, so all commands for a connection in an event will execute without being interrupted. You don't need to worry about a second connection's CLIENT_DATA event firing while you're in the middle of the first connection's event, for example. However, you could have multiple clients with the same "channel identifier" have their CLIENT_DATA events all fire before any of their SERVER_CONNECTED events do, so at the least you should probably change your test in SERVER_CONNECTED to check the persistence table and not the result from CLIENT_DATA that you stored in $PersistTo.

    What can I do to make this work without rewriting the application?

    Well, if what you posted is the entirety of your iRule, I *think* you just need a straightforward UIE persistence setup. I'm pretty sure that looks like:

    
    when CLIENT_ACCEPTED {
        TCP::collect 44   
    }
    when CLIENT_DATA {
       set ConStr [TCP::payload 44]
       set SessionID [substr [getfield $ConStr "@" 2] 0 " CHID" ]
       log local0.info $SessionID
       if { $SessionID equals "" } {
           No SessionID, just load balance as usual
          log local0.info "No session ID, load balancing the connection."  
          pool YOUR_DEFAULT_POOL_NAME
       } else {
           All clients with this SessionID go to this server
           timeout is 120 seconds
          persist uie $SessionID 120
       }
    }