Salutations amis!
Dans les deux articles précédents (
un ,
deux ), nous avons plongé dans la complexité du choix entre les technologies et recherché les paramètres optimaux pour notre solution dans
Ostrovok.ru . Quel sujet allons-nous aborder aujourd'hui?
Chaque service doit fonctionner sur un serveur, en communiquant avec le matériel via les outils du système d'exploitation. Il existe un grand nombre de ces outils, ainsi que des paramètres pour eux. Dans la plupart des cas, leurs paramètres par défaut seront plus que suffisants. Dans cet article, je voudrais parler de ces cas où les paramètres standard n'étaient toujours pas suffisants, et j'ai dû connaître un peu plus le système d'exploitation - dans notre cas avec
Linux .

Nous utilisons judicieusement les grains
Dans un
article précédent, j'ai parlé de l'
option cpu-map dans
Haproxy . Avec lui, nous lions les processus Haproxy aux threads d'un cœur sur un serveur à deux processeurs. Nous avons donné le deuxième noyau à la gestion des interruptions de carte réseau.
Voici un écran où vous pouvez voir une séparation similaire. A gauche, les noyaux sont occupés par Haproxy dans
user space
, et à droite, par le traitement des interruptions dans l'
kernel space
.

La liaison des interruptions à une carte réseau se fait automatiquement à l'aide de cette
Il existe de nombreux scripts simples et plus complexes sur Internet qui font le même travail, mais ce script est suffisant pour nos besoins.
Chez Haproxy, nous avons lié les processus aux noyaux, en commençant par le premier noyau. Le même script lie les interruptions, en commençant par la dernière. Ainsi, nous pouvons diviser les processeurs de serveur en deux camps.
Pour un aperçu plus approfondi des interruptions et du réseautage, je recommande fortement de lire cet
article .
Nous révélons les capacités des périphériques réseau
Il se trouve qu'un grand nombre de trames peuvent survoler le réseau à un moment donné, et la file d'attente de cartes peut ne pas être prête pour un tel afflux d'invités, même si elle en a la possibilité.
Parlons du tampon de la carte réseau. Le plus souvent, les valeurs par défaut n'utilisent pas tout le tampon disponible. Vous pouvez afficher les paramètres actuels à l'aide du puissant utilitaire ethtool.
Exemple d'utilisation de la commande:
> ethtool -g eno1 Ring parameters for eno1: Pre-set maximums: RX: 4096 RX Mini: 0 RX Jumbo: 0 TX: 4096 Current hardware settings: RX: 256 RX Mini: 0 RX Jumbo: 0 TX: 256
Maintenant, prenons tout de la vie:
> ethtool -G eno1 rx 4096 tx 4096 > ethtool -g eno1 Ring parameters for eno1: Pre-set maximums: RX: 4096 RX Mini: 0 RX Jumbo: 0 TX: 4096 Current hardware settings: RX: 4096 RX Mini: 0 RX Jumbo: 0 TX: 4096
Vous pouvez maintenant être sûr que la carte n'est pas restreinte et fonctionne au maximum de ses capacités.
Paramètres sysctl minimum pour un maximum d'avantages
Sysctl a une grande variété d'options dans toutes les couleurs et tailles que vous pouvez imaginer. Et, en règle générale, les articles sur Internet, abordant la question de l'optimisation, couvrent une partie assez impressionnante de ces paramètres. Je ne considérerai que ceux qui ont été vraiment utiles à changer dans notre cas.
net.core.netdev_max_backlog - la file d'attente où les trames de la carte réseau obtiennent, qui sont ensuite traitées par le noyau. Avec des interfaces rapides et un trafic important, il peut se remplir rapidement.
Par défaut : 1000.
Nous pouvons observer l'excès de cette file d'attente en consultant la deuxième colonne du fichier / proc / net / softnet_stat.
awk '{print $2}' /proc/net/softnet_stat
Le fichier lui-même décrit la structure de
netif_rx_stats par ligne pour chaque CPU du système.
Plus précisément, la deuxième colonne décrit le nombre de paquets à l'état abandonné. Si la valeur de la deuxième colonne augmente avec le temps, cela vaut probablement la peine d'augmenter la valeur de
net.core.netdev_max_backlog
ou de mettre le processeur plus rapidement.
net.core.rmem_default /
net.core.rmem_max &&
net.core.wmem_default /
net.core.wmem_max - ces paramètres indiquent la valeur par défaut / la valeur maximale pour les tampons de lecture et d'écriture de socket.
La valeur
par défaut peut être modifiée au niveau de l'application au moment de la création du socket (à propos, Haproxy a un
paramètre qui fait cela). Nous avons eu des cas où le noyau a lancé plus de paquets que Haproxy n'a réussi à ratisser, puis les problèmes ont commencé. Par conséquent, la chose est importante.
net.ipv4.tcp_max_syn_backlog - est responsable de la limite des nouvelles connexions non encore établies pour lesquelles un paquet
SYN
été reçu. S'il y a un grand flux de nouvelles connexions (par exemple, un grand nombre de requêtes HTTP de
Connection: close
), il est logique d'augmenter cette valeur afin de ne pas perdre de temps à envoyer des paquets transférés.
net.core.somaxconn - nous parlons ici de connexions établies, mais pas encore traitées par l'application. Si le serveur est monothread et que deux demandes lui sont parvenues, la première demande sera traitée par la fonction
accept()
et la seconde se bloquera dans le
backlog
, dont la taille est responsable de ce paramètre.
nf_conntrack_max est probablement le plus célèbre de tous les paramètres. Je pense que presque tous ceux qui ont traité avec iptables le savent. Idéalement, bien sûr, si vous n'avez pas besoin d'utiliser le masquage iptables, vous pouvez décharger le module conntrack et ne pas y penser. Dans mon cas,
Docker est utilisé, donc vous ne téléchargerez rien de spécial.
Suivi Évident et pas très
Afin de ne pas chercher aveuglément pourquoi «votre proxy ralentit», il sera utile de configurer quelques graphiques et de les superposer avec des déclencheurs.
nf_conntrack_count est la métrique la plus évidente. Sur celui-ci, vous pouvez surveiller le nombre de connexions présentes dans la
table conntrack . Lorsque la table déborde, le chemin d'accès aux nouvelles connexions sera fermé.
La valeur actuelle peut être trouvée ici:
cat /proc/sys/net/netfilter/nf_conntrack_count
Segments Tcp retransmis - le nombre de transferts de segments. La métrique est très volumineuse, car elle peut parler de problèmes à différents niveaux. L'augmentation des transferts peut indiquer des problèmes de réseau, la nécessité d'optimiser les paramètres système, ou même que le logiciel final (par exemple, Haproxy) ne fait pas son travail. Quoi qu'il en soit, la croissance anormale de cette valeur peut servir de motif à une procédure.

Dans notre pays, une augmentation des valeurs indique le plus souvent des problèmes avec l'un des fournisseurs, bien qu'il y ait eu des problèmes avec les performances des serveurs et du réseau.
Exemple de vérification:
netstat -s|grep 'segments retransmited'
Socket Recv-Q - rappelez-vous, nous avons parlé de moments où une application peut ne pas avoir suffisamment de temps pour traiter les demandes, puis le
socket backlog
va augmenter? La croissance de cet indicateur montre clairement que quelque chose ne va pas avec l'application et qu'elle ne peut pas y faire face.
J'ai vu des montagnes dans les graphiques avec cette métrique, lorsque le paramètre maxconn dans Haproxy avait une valeur par défaut (2000), et il n'a tout simplement pas accepté de nouvelles connexions.
Et encore un exemple:
ss -lntp|awk '/LISTEN/ {print $2}'

Il ne sera pas superflu d'avoir un graphe avec une répartition par état des connexions TCP:

Et rendre séparément le
time-wait/established
, car leurs valeurs, en règle générale, sont très différentes des autres:

En plus de ces mesures, il y en a beaucoup d'autres, mais plus évidentes - par exemple, la charge sur l'interface réseau ou le CPU. Leur choix dépendra déjà davantage des spécificités de votre charge de travail.
Au lieu d'une conclusion
En général, c'est tout - j'ai essayé de décrire les points clés auxquels j'ai dû faire face lors de la configuration du proxy inverse http. Il semblerait que la tâche ne soit pas difficile, mais avec une augmentation de la charge, le nombre d'embûches qui surgissent toujours au mauvais moment augmente également. J'espère que cet article vous aidera à éviter les difficultés auxquelles j'ai dû faire face.
Toute paix