pgBouncer fonctionne très bien mais devient parfois indisponible

9

J'exécute pgBouncer devant une base de données Postgres 9 occupée. Pour la plupart du temps, cela fonctionne bien. Mais toutes les quelques heures, je recevrai un e-mail d'erreur de mon application, à l'exception de psycopg2:

OperationalError ('impossible de se connecter au serveur: impossible d'attribuer l'adresse demandée Le serveur fonctionne-t-il sur l'hôte "neo-hulk" et accepte-t-il les connexions TCP / IP sur le port 6432?')

Il s'agit d'une application python avec un tas de travailleurs céleri exécutant des tâches. Lorsque ces erreurs arrivent, je vérifie la base de données pgbouncer et la taille du pool est dans les limites. Après quelques expérimentations, j'ai défini la taille maximale du pool sur 400 et la taille du pool sur 200. Le mode pool est "session" (les demandes sont principalement auto-validées, presque aucune transaction).

Qu'est-ce qui fait que pgBouncer «disparaît» ainsi? ce n'est que pour de courtes périodes de temps (et au total, nous parlons d'une petite quantité de demandes par rapport au volume de demandes qu'elle traite), mais les demandes qui échouent sont importantes.

Merci!

Harel
la source
Système d'exploitation et version? Version du noyau si Linux? Versions exactes de PostgreSQL et PgBouncer? Avez-vous exécuté PgBouncer au niveau du journal de débogage et vu s'il signale quelque chose d'utile?
Craig Ringer
Debian 6. Linux version 2.6.32-5-amd64 (Debian 2.6.32-48squeeze1) pgbouncer version 1.5.4 Postgres 9.1. Le journal ne journalise pas la connexion / déconnexion car je pensais que c'était un peu trop, mais il n'y a pas d'erreurs présentes lorsque ces erreurs d'application sont levées. L'erreur vient de psycopg2 pensant qu'il n'y a pas de serveur db à qui parler, bien que ce problème n'existait pas pré pgbouncer
Harel
1
Hm, donc PgBouncer actuel, et le noyau est ancien mais assez stable. Je pense que vous devez activer une journalisation plus détaillée dans PgBouncer avec -vvvet voir si vous pouvez faire correspondre la sortie de journal anormale avec vos erreurs dans le temps.
Craig Ringer
J'ai fait un "set verbose = 1; reload;" dans le shell pgbouncer et n'a rien trouvé d'extraordinaire dans le journal. il s'agit d'un système de production qui ne peut donc pas empêcher le service de fonctionner en tant que non démon avec -vvv. J'espère que j'ai le même résultat. notez que l'erreur suggère qu'il ne pouvait pas du tout se connecter à pgbouncer, c'est-à-dire qu'il ne pouvait pas le trouver à l'écoute dans ce port. Il y a des milliers de connexions établies tout le temps et c'est étrange qu'un petit nombre d'entre elles échouent comme ça.
Harel
Rusé; cela ressemble à une condition de course potentielle, mais dans quoi / où ...
Craig Ringer

Réponses:

15

La partie " Impossible d'attribuer l'adresse demandée " dans le message d'erreur provient de la pile TCP du noyau. Lorsqu'il est rencontré par intermittence, cela signifie généralement que l'espace des sockets disponibles est épuisé en raison de trop de sockets en état d'attente ( TIME_WAIT, ou moins probablement FIN_WAIT_1ou FIN_WAIT_2)

La plage de ports de socket peut être sortie par cat /proc/sys/net/ipv4/ip_local_port_range. La valeur par défaut sur un noyau Linux stock est généralement 32768 61000.

Vous pouvez vérifier le résultat de netstat -ton|grep WAITsur le (s) client (s) et sur l'hôte pgBouncer lorsque le système est occupé. L' -oindicateur affichera les compteurs de délai d'attente liés aux états d'attente.

Si le nombre total de sockets TCP est proche, l' 61000-32768=28232épuisement de cette plage est probablement votre problème. Puisqu'un socket fermé passe 60 secondes à l' TIME_WAITétat normal, si un hôte client se connecte plus de 28232 fois en une minute, les nouvelles connexions échoueront avec l'erreur mentionnée jusqu'à ce que les ports soient libérés.

Comme première solution, la plage de ports TCP peut être étendue:

 # echo "1025 65535" >/proc/sys/net/ipv4/ip_local_port_range

Si ce n'est pas satisfaisant, vérifiez les drapeaux tcp_tw_recycleet tcp_tw_reuse, également réglables via /proc/sys/net/ipv4et sysctl.

Ils sont définis comme (de man tcp):

       tcp_tw_recycle (Boolean; défaut: désactivé; depuis Linux 2.4)
              Activez le recyclage rapide des sockets TIME_WAIT. Activer ceci
              n'est pas recommandée car cela pose des problèmes lors du travail
              avec NAT (Network Address Translation).

       tcp_tw_reuse (Boolean; défaut: désactivé; depuis Linux 2.4.19 / 2.6)
              Permet de réutiliser les sockets TIME_WAIT pour de nouvelles connexions quand il est
              à l'abri du point de vue du protocole. Il ne doit pas être modifié sans
              avis / demande d'experts techniques.

Personnellement, j'ai eu du succès tcp_tw_recycleface à ce problème avec une application cliente MySQL, mais ne prenez pas cela comme une recommandation, ma compréhension de TCP étant au mieux superficielle.

Daniel Vérité
la source
1
Cette réponse montre quoi que ce soit une compréhension superficielle des bogues de TCP. Merci pour ça. J'ai augmenté la plage de ports et je l'ai laissé fonctionner pendant un certain temps pour voir si cela a un effet. (Dois-je redémarrer après l'avoir configuré?)
Harel
Je pense que l'augmentation du port l'a fait. Jusqu'à présent, je n'ai reçu aucune erreur. Un décompte approximatif des lignes netstat montre près de 20 Ko dans le client, de sorte que la limite par défaut de 28 Ko n'est pas longue. Merci pour ça!
Harel
1
Bien! Vous souhaitez définir le paramètre de /etc/sysctl.confmanière net.ipv4.ip_local_port_range = 1025 65535à ce qu'il persiste lors des redémarrages.
Daniel Vérité
Merci. J'ai reçu des erreurs depuis mais pas celle-là donc c'est toujours bon. Le laisser fonctionner pendant quelques jours et fera le changement de perm. Je suis content que cela semble fonctionner jusqu'à présent parce que les autres changements me font peur :)
Harel