Forum Discussion
Auto-failback irule, need help on optimisation
Hello experts,
I have implemented an auto-failback irule in order to bring a kind of high availability on a VMs pair that offers an NFS connector above Scality's SOFS. Because of cache coherency problem, both connectors must not be used at the same time for writing.
The irule makes sure any TCP connection is always directed toward the primary node. If it is not available, the connection is directed toward the backup node. When the main node is back online, open TCP connections are closed to force the client to open a new one.
The huge drawback is really high CPU usage (40% on one 10250v core for a 400 Mbps traffic) as it is fired upon each received TCP segment. How could I make it better ?
Here is the code, LTM version is 12.1 :
Nom : irule-failback-tcp
Date : 2017/09/26
Version : 1.0
Description : Mets en place une règle d'auto-failback sur un pool.
Si le membre principal est "up" les données lui seront
toujours envoyées, même s'il faut pour cela forcer la fin
d'une session TCP déjà établie.
Dans le cas contraire, la gestion est laissée au bigip.
N'a été testé que dans un pool de deux membres avec deux
"Priority Group".
En cas d'auto-failback, le client doit savoir gérer
correctement (silencieusement) un TCP reset et ré-établir tout
seul une connection.
Utilisation : Renseigner les trois variables s_mainMemberIP, s_backupMemberIP
et i_memberPort.
Si i_debug vaut 1 des messages de logs sont envoyés vers le
logger0, sévérité info. Par défault il sont alors stockés dans
le fichier /var/log/ltm.
Attention : Le debug est très verbeux, 5 lignes par segment TCP.
L'irule est exécutée à chaque segment reçu, l'utilisation CPU
est donc très importante, en moyenne 40% d'un coeur sur un
10250v pour un traffic de 400 Mbps.
Lors de la connection d'un client, initialisation de quelques variables et
+ activation de la collecte du payload.
when CLIENT_ACCEPTED {
Variables à adapter en fonction du pool conserné.
set s_mainMemberIP "x.y.z.1"
set s_backupMemberIP "x.y.z.2"
set i_memberPort 2049
Active des messages de debug si vaut 1
set i_debug 0
Récupération du payload et génération d'un évènement CLIENT_DATA.
TCP::collect
}
Une fois tout le payload du client collecté
when CLIENT_DATA {
Récupération du nom du pool.
set s_poolName [LB::server pool]
Récupération de l'IP du membre sélectionné.
set s_targetMemberIP [LB::server addr]
Récupération de l'état du membre principal.
set s_mainStatus [LB::status pool $s_poolName member \
$s_mainMemberIP $i_memberPort]
if { $i_debug == 1 } {
log local0.info "1-Pool Name : $s_poolName"
log local0.info "2-Member port : $i_memberPort"
log local0.info "3-Target member : $s_targetMemberIP"
log local0.info "4-Main member status : $s_mainStatus"
}
Si le membre principal est up...
if { $s_mainStatus eq "up" } {
...et si le membre sélectionné n'est pas le principal, la session TCP
+ est terminée pour lui permettre de basculer sur le membre principal.
if { $s_targetMemberIP != "" && $s_targetMemberIP != $s_mainMemberIP } {
log local0.info "5-Auto-failback : Active"
reject
} else {
Si aucun membre n'a été sélectionné ou si c'est le principal il n'y
+ a rien à faire.
if { $i_debug == 1 } {
log local0.info "5-Auto-failback : Non necessaire"
}
}
} else {
Dans tous les autres cas (down, force offline, disabled) on laisse le
+ big-ip gérer tout seul.
if { $i_debug == 1 } {
log local0.info "5-Auto-failback : Inactive"
}
}
Le payload collecté est transféré au serveur.
set i_bytesReleased [TCP::release]
if { $i_debug == 1 } {
log local0.info "6-Bytes released : $i_bytesReleased"
}
Réactivation de la collecte.
TCP::collect
}
Many thanks.
- Simon_Blakely
Employee
I see the issue that you have - I tried to think of a better approach, but I could not find one that meets all the requirements.
For your irule, the first suggestion is to separate out your constants into static variables, and set them in the rule INIT event. You are wasting time and memory by creating those per connection.
when RULE_INIT { Variables à adapter en fonction du pool conserné. set static::s_mainMemberIP "x.y.z.1" set static::s_backupMemberIP "x.y.z.2" set static::i_memberPort 2049 Active des messages de debug si vaut 1 set static::i_debug 0 }
Try that - I don't know how much CPU you will save, but it is worth a try.
A better (less CPU intensive) approach would be to use iCall
Add an event that detects when the primary pool member is marked up, then drop all connections to the standby pool member (with a tmsh delete sys conn ss-server ). All new connections will be balanced to the primary (assuming it has a higher priority setting).
Or on any pool member down event, swap the priority setting of the pool members so that the currently active pool member has the highest priority until it is marked down, so it will always get the connections.
Recent Discussions
Related Content
* 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