Load-Balancing des connexions côté serveur : Un problème évident que j'avais juste raté

J’ai toujours l’impression quand j’écris un post sur ce blog que c’est tellement évident que je dois vraiment passer pour un neu-neu. Un peu comme le coyote qui tombe toujours dans ses propres pièges qu’il tend au roadrunner. Et bien cette fois encore, c’était tellement évident que je me demande comment j’ai pu faire cette erreur si grossière ; j’explique.

L’année dernière, j’ai écrit ce post qui tentait d’expliquer succinctement le B.A-BA des configurations réseaux d’Oracle. Malgré une explication maladroite et qui est loin de couvrir toutes les possibilités dans ce domaine, ça reste un des hits de ce blog(*) ; le top 6 des visites ce mois, si on enlève la page d’accueil… Mais je m’égare encore !

Toujours est-il que dans ce post, j’explique, sans parler du paramétrage des services en 10g avec DBMS_SERVICE, comment les services sont enregistrés dans les listeners par PMON(**). Le post présente également la manière dont les connexions clientes sont dirigées sur, disons pour simplifier, le serveur moins utilisé, grâce aux informations envoyées par ce même PMON. En me répétant :

  • Grâce au paramètre local_listener qui contient une chaîne de connexion réseau, le plus souvent un alias TNS mais possiblement n’importe quelle chaîne de description réseau du client OCI, l’instance connaît son listener local capable de « spawner » un serveur dédié par exemple. Si ce paramètre est vide, PMON considère qu’il doit adresser le listener sur `hostname` et le port 1521 ce qui dans la plupart des configurations y compris RAC fonctionne (ou du moins semble-t-il !)…
  • Grâce au paramètre remote_listener qui contient une chaîne de connexion réseau avec le plus souvent plusieurs adresses de listeners, PMON envoie des informations aux listeners distants. Ces informations permettent au listener de repartir la charge selon l’activité des serveurs de bases de donnees ; PMON envoie donc
    • l’emplacement du listener local,
    • les informations relatives aux dispatchers
    • les services de l’instance positionnés avec service_names et DBMS_SERVICES
    • Un ensemble d’informations de charges (C’est plus vague pour moi : uptime et nombre de connexions)
  • Le client, lorsqu’il fait une demande de connexion à un listener est dirigé selon les informations CLB_GOAL associé au service vers l’instance du serveur le « moins » chargé et pour cela est envoyé au listener local associé à cette instance.

Vous me direz, c’est pas simple ! En fait si : C’est juste moi qui ne suit pas clair. J’ai mis en gras la source de mon problème du jour ; vous êtes dirigés vers le listener local tel qu’envoyé par PMON ; Autrement dit :

  • Si PMON envoie l’adresse publique de votre serveur, vous vous connectez à l’adresse publique de votre serveur ; Il est plus que conseillé de se connecter via la VIP, non ?
  • Si PMON envoie l’adresse VIP de votre serveur, vous vous connectez via la VIP
  • Si PMON envoie l’alias réseau de votre machine, vous vous connectez via l’alias reseau
  • Si PMON n’envoie rien, parce que remote_listener n’est pas positionné par exemple, et bien vous vous connectez a l’instance locale ou à rien du tout si l’instance locale ne publie pas le service. C’est avec ce dernier cas qu’on arrive à configurer le load balancing client ou de maniere plus banale connexion par round-robin.

Mais pourquoi PMON enverrait-il l’adresse public, l’alias réseau ou la VIP ? Et bien parce que PMON est loin d’avoir le génie de T.Kyte ou J.Lewis; il envoie bêtement ce qu’il trouve dans local_listener, c’est à dire :

  • Ce que vous écrivez si vous écrivez quelque chose (alias vip, alias public, adresse public ou vip)
  • `hostname` qui correspond à l’alias publique si vous n’écrivez rien !

Pour vérifiez, tapez la commande suivante :

lsnrctl service

L’exemple ci-dessous est un extrait du résultat dans le cas d’une configuration où local_listener est vide :

Service "ORCL" has 2 instance(s).
Instance "ORCL2", status READY, has 2 handler(s) for this service...
Handler(s):
"DEDICATED" established:3 refused:0 state:ready
LOCAL SERVER
"DEDICATED" established:0 refused:0 state:ready
REMOTE SERVER
(ADDRESS=(PROTOCOL=TCP)(HOST=arkzoyd2)(PORT=1521))

Dans ce cas, arkzoyd2 est l’alias public et pas l’alias de la VIP. Ce qui fait encore plus drôle c’est que comme le client n’a pas accès aux alias réseau et n’avait que l’adresse du noeud 1 dans sa config, il ne se connectait tout simplement pas à ce deuxième noeud.

Moralité 1 :

  • Non seulement mettez les VIP dans l’alias de connexion de votre client
  • Mais en plus, mettez-les dans la description de connexion utilisé dans local_listener
  • Si vous travaillez avec les alias et pas les adresses, vérifiez qu’ils sont accessibles de tous vos clients (i.e. dans les DNS)

Moralité 2 :

  • Pour dire vrai, ce n’est pas moi qui ai fait la configuration mais j’aurais sûrement fait la même bêtise si j’avais procédé pareillement. C’est pour ça que j’évite de jouer au plus malin (je perds tout le temps) et donc je laisse la configuration générée par défaut par DBCA ou runInstaller; C’est pour ça que ça me gêne vraiment que la page la plus visitée sur ce blog, après la page d’accueil, soit celle qui parle des créations manuelles de bases de données ! (*)

(*) Pour information, le hits #1 du blog est « Comment créer une base de données sans DBCA » comme quoi les gens aiment encore se compliquer la vie ; c’est quand même 100x plus simple de lancer dbca en mode silent. Je vous conseille donc plutôt cet article sur les installations silencieuses. Et le post que j’utilise le plus fréquemment, c’est « Comment créer une standby physique avec Recovery Manager »
(**) positionnez l’event 10257 au niveau 16 pour avoir le détail du trafic généré par PMON. Il faut redémarrer l’instance mais, la magie de RAC, pas l’indisponibilité pour cette opération.