[LINUX] Accélérez la commande netstat

introduction

C'est une histoire que la commande netstat devenait plus rapide si le noyau Linux et la commande netstat étaient légèrement modifiés.

Aperçu

environnement

$ uname -r
3.10.0-693.17.1.el7.x86_64
$ rpm -q kernel
kernel-3.10.0-693.11.6.el7.x86_64
kernel-3.10.0-693.17.1.el7.x86_64
$ rpm -q net-tools
net-tools-2.0-0.22.20131004git.el7.x86_64

$ cat /etc/redhat-release
CentOS Linux release 7.4.1708 (Core)
$ LANG=C lscpu
Architecture:          x86_64
CPU op-mode(s):        32-bit, 64-bit
Byte Order:            Little Endian
CPU(s):                2
On-line CPU(s) list:   0,1
Thread(s) per core:    2
Core(s) per socket:    1
Socket(s):             1
NUMA node(s):          1
Vendor ID:             GenuineIntel
CPU family:            6
Model:                 63
Model name:            Intel(R) Xeon(R) CPU E5-2673 v3 @ 2.40GHz
Stepping:              2
CPU MHz:               2394.456
BogoMIPS:              4788.91
Virtualization:        VT-x
Hypervisor vendor:     Microsoft
Virtualization type:   full
L1d cache:             32K
L1i cache:             32K
L2 cache:              256K
L3 cache:              30720K
NUMA node0 CPU(s):     0,1
Flags:                 fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx pdpe1gb rdtscp lm constant_tsc rep_good nopl xtopology eagerfpu pni pclmulqdq vmx ssse3 fma cx16 sse4_1 sse4_2 movbe popcnt aes xsave avx f16c rdrand hypervisor lahf_lm abm tpr_shadow vnmi ept vpid fsgsbase bmi1 avx2 smep bmi2 erms xsaveopt
$ free -m
              total        used        free      shared  buff/cache   available
Mem:           7966         416        6876           8         673        7205
Swap:             0           0           0

procédure

Préparation

--Installez et configurez divers éléments requis pour créer le package RPM

sudo useradd mockbuild
sudo yum -y install rpm-build
sudo yum -y groups install "Development Tools"

Débarrassez-vous du noyau Linux

Obtenez et installez SRPM du noyau

--Installez les packages requis au moment de la construction

yumdownloader --source kernel
rpm -ivh kernel-3.10.0-693.17.1.el7.centos.plus.src.rpm
sudo yum -y install m4 gcc xmlto asciidoc hmaccalc  python-devel newt-devel 'perl(ExtUtils::Embed)' pesign elfutils-devel zlib-devel binutils-devel bison audit-libs-devel  java-devel openssl-devel numactl-devel pciutils-devel ncurses-devel

Préparer le correctif et corriger le fichier SPEC

--Créez un patch avec le contenu suivant comme ~ / rpmbuild / SOURCES / proc-net-tcp.patch

--- a/net/ipv4/tcp_ipv4.c	2018-01-14 15:02:54.000000000 +0000
+++ b/net/ipv4/tcp_ipv4.c	2018-02-10 06:08:39.043951339 +0000
@@ -2382,10 +2382,21 @@
 	return 0;
 }
 
+static ssize_t tcp_seq_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
+{
+	struct seq_file *m = file->private_data;
+	if (!m->buf) {
+		m->buf = kmalloc( m->size = 16 * PAGE_SIZE, GFP_KERNEL);
+		if (!m->buf)
+			return -ENOMEM;
+	}
+	return seq_read(file, buf, size, ppos);
+}
+
 static const struct file_operations tcp_afinfo_seq_fops = {
 	.owner   = THIS_MODULE,
 	.open    = tcp_seq_open,
-	.read    = seq_read,
+	.read    = tcp_seq_read,
 	.llseek  = seq_lseek,
 	.release = seq_release_net
 };
--- a/net/ipv6/tcp_ipv6.c	2018-01-14 15:02:54.000000000 +0000
+++ b/net/ipv6/tcp_ipv6.c	2018-02-10 06:10:39.910935928 +0000
@@ -1812,10 +1812,21 @@
 	return 0;
 }
 
+static ssize_t tcp_seq_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
+{
+	struct seq_file *m = file->private_data;
+	if (!m->buf) {
+		m->buf = kmalloc( m->size = 16 * PAGE_SIZE, GFP_KERNEL);
+		if (!m->buf)
+			return -ENOMEM;
+	}
+	return seq_read(file, buf, size, ppos);
+}
+
 static const struct file_operations tcp6_afinfo_seq_fops = {
 	.owner   = THIS_MODULE,
 	.open    = tcp_seq_open,
-	.read    = seq_read,
+	.read    = tcp_seq_read,
 	.llseek  = seq_lseek,
 	.release = seq_release_net
 };

--Fichier SPEC modifié pour appliquer le correctif ci-dessus au moment de la construction

$ diff ~/rpmbuild/SPECS/kernel.spec.org ~/rpmbuild/SPECS/kernel.spec
8c8
< %define buildid .centos.plus
---
> %define buildid .procnettcp
463a464,465
> Patch50000: proc-net-tcp.patch
>
832a835,836
>
> ApplyPatch proc-net-tcp.patch

Construire un package de noyau Linux

――Le temps requis dans l'environnement utilisé cette fois est supérieur à 1,5

rpmbuild -ba ~/rpmbuild/SPECS/kernel.spec
find ~/rpmbuild/ -name "*.rpm"

résultat

Confirmation avec commande cat

$ uname -r
3.10.0-693.17.1.el7.procnettcp.x86_64
$ LANG=C strace -e open,read cat /proc/net/tcp|wc -l
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
open("/lib64/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\20\35\2\0\0\0\0\0"..., 832) = 832
open("/proc/net/tcp", O_RDONLY)         = 3
read(3, "  sl  local_address rem_address "..., 65536) = 11700
read(3, "", 65536)                      = 0
78
+++ exited with 0 +++
$ uname -r
3.10.0-693.17.1.el7.x86_64
$ LANG=C strace -e open,read cat /proc/net/tcp|wc -l
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
open("/lib64/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\20\35\2\0\0\0\0\0"..., 832) = 832
open("/proc/net/tcp", O_RDONLY)         = 3
read(3, "  sl  local_address rem_address "..., 65536) = 4050
read(3, "  26: 0502010A:861A 10813FA8:005"..., 65536) = 1650
read(3, "", 65536)                      = 0
38
+++ exited with 0 +++

Confirmation avec la commande netstat

$ uname -r
3.10.0-693.17.1.el7.procnettcp.x86_64
$ LANG=C strace -e open,read netstat -atn |wc -l
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
open("/lib64/libselinux.so.1", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\300j\0\0\0\0\0\0"..., 832) = 832
open("/lib64/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\20\35\2\0\0\0\0\0"..., 832) = 832
open("/lib64/libpcre.so.1", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\360\25\0\0\0\0\0\0"..., 832) = 832
open("/lib64/libdl.so.2", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0`\16\0\0\0\0\0\0"..., 832) = 832
open("/lib64/libpthread.so.0", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\0m\0\0\0\0\0\0"..., 832) = 832
open("/proc/net/tcp", O_RDONLY)         = 3
read(3, "  sl  local_address rem_address "..., 4096) = 4096
read(3, "00000000 03:00001608 00000000   "..., 4096) = 4096
read(3, " 3 ffff880287e55d00             "..., 4096) = 4096
read(3, "           \n", 4096)          = 12
read(3, "", 4096)                       = 0
open("/proc/net/tcp6", O_RDONLY)        = 3
read(3, "  sl  local_address             "..., 4096) = 853
read(3, "", 4096)                       = 0
+++ exited with 0 +++
87

--À propos de la commande netstat dans l'environnement du noyau avant modification, l'état de l'appel système de lecture avec la commande strace est le suivant

$ uname -r
3.10.0-693.17.1.el7.x86_64
$ LANG=C strace -e open,read netstat -atn |wc -l
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
open("/lib64/libselinux.so.1", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\300j\0\0\0\0\0\0"..., 832) = 832
open("/lib64/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\20\35\2\0\0\0\0\0"..., 832) = 832
open("/lib64/libpcre.so.1", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\360\25\0\0\0\0\0\0"..., 832) = 832
open("/lib64/libdl.so.2", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0`\16\0\0\0\0\0\0"..., 832) = 832
open("/lib64/libpthread.so.0", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\0m\0\0\0\0\0\0"..., 832) = 832
open("/proc/net/tcp", O_RDONLY)         = 3
read(3, "  sl  local_address rem_address "..., 4096) = 4050
read(3, "  26: 0502010A:870C 10813FA8:005"..., 4096) = 4050
read(3, "  53: 0502010A:E488 19E57328:01B"..., 4096) = 900
read(3, "", 4096)                       = 0
open("/proc/net/tcp6", O_RDONLY)        = 3
read(3, "  sl  local_address             "..., 4096) = 676
read(3, "", 4096)                       = 0
+++ exited with 0 +++
64

Débarrassez-vous de netstat

Obtenez et installez SRPM de net-tools

yumdownloader --source net-tools
rpm -ivh net-tools-2.0-0.22.20131004git.el7.src.rpm
sudo yum -y install libselinux-devel

Préparer le correctif et corriger le fichier SPEC

--Créez un patch avec le contenu suivant comme ~ / rpmbuild / SOURCES / net-tools-netstat-proc-net-tcp-buffer-size.patch --Changé pour allouer une zone tampon avec 16 fois la taille de la page

--- a/lib/proc.c	2013-09-30 08:07:32.000000000 +0000
+++ b/lib/proc.c	2018-02-11 04:48:40.959339035 +0000
@@ -88,9 +88,9 @@
 
     if (!buffer) {
       pagesz = getpagesize();
-      buffer = malloc(pagesz);
+      buffer = malloc(16*pagesz);
     }
 
-    setvbuf(fd, buffer, _IOFBF, pagesz);
+    setvbuf(fd, buffer, _IOFBF, 16*pagesz);
     return fd;
 }

--Fichier SPEC modifié pour appliquer le correctif ci-dessus au moment de la construction

$ diff ~/rpmbuild/SPECS/net-tools.spec.org  ~/rpmbuild/SPECS/net-tools.spec
67a68,69
> Patch100: net-tools-netstat-proc-net-tcp-buffer-size.patch
>
104a107,108
>
> %patch100 -p1 -b .proc-net-tcp

Construire le package net-tools

--Pour comparaison avec la commande netstat avant modification, le package RPM obtenu par compilation n'est pas installé.

rpmbuild -bb ~/rpmbuild/SPECS/net-tools.spec
ls -l ~/rpmbuild/BUILD/net-tools/netstat 

résultat

--Observez l'appel système de lecture avec la commande strace pour la commande netstat avant la modification.

$ LANG=C strace -e open,read netstat -atn  |wc -l
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
open("/lib64/libselinux.so.1", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\300j\0\0\0\0\0\0"..., 832) = 832
open("/lib64/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\20\35\2\0\0\0\0\0"..., 832) = 832
open("/lib64/libpcre.so.1", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\360\25\0\0\0\0\0\0"..., 832) = 832
open("/lib64/libdl.so.2", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0`\16\0\0\0\0\0\0"..., 832) = 832
open("/lib64/libpthread.so.0", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\0m\0\0\0\0\0\0"..., 832) = 832
open("/proc/net/tcp", O_RDONLY)         = 3
read(3, "  sl  local_address rem_address "..., 4096) = 4096
read(3, "00000000 03:0000022B 00000000   "..., 4096) = 4096
read(3, " 3 ffff8802c43a7d00             "..., 4096) = 3508
read(3, "", 4096)                       = 0
open("/proc/net/tcp6", O_RDONLY)        = 3
read(3, "  sl  local_address             "..., 4096) = 853
read(3, "", 4096)                       = 0
+++ exited with 0 +++
83
$ LANG=C strace -e open,read ~/rpmbuild/BUILD/net-tools-2.0/netstat -atn  |wc -l
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
open("/lib64/libselinux.so.1", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\300j\0\0\0\0\0\0"..., 832) = 832
open("/lib64/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\20\35\2\0\0\0\0\0"..., 832) = 832
open("/lib64/libpcre.so.1", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\360\25\0\0\0\0\0\0"..., 832) = 832
open("/lib64/libdl.so.2", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0`\16\0\0\0\0\0\0"..., 832) = 832
open("/lib64/libpthread.so.0", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\0m\0\0\0\0\0\0"..., 832) = 832
open("/proc/net/tcp", O_RDONLY)         = 3
read(3, "  sl  local_address rem_address "..., 65536) = 11700
read(3, "", 65536)                      = 0
open("/proc/net/tcp6", O_RDONLY)        = 3
read(3, "  sl  local_address             "..., 65536) = 853
read(3, "", 65536)                      = 0
+++ exited with 0 +++
83

Comparaison de comportement avec de nombreuses sessions TCP

--Utilisez Apache et la commande ab de l'outil de référence fourni avec Apache pour augmenter le nombre de sessions TCP

sudo yum -y install httpd
sudo systemctl start  httpd.service
while : ; do ab -n 100000 -c 1000 127.0.0.1/test; done

--Dans la mesure avec la commande time, lorsque le nombre de sessions TCP est supérieur à 16000, cela a pris plus de 300 millisecondes avec la commande netstat conventionnelle, mais avec la commande netstat modifiée, cela prend moins de la moitié du temps à 100 millisecondes. C'est devenu ainsi

$ time  netstat -atn |wc -l
16528

real    0m0.355s
user    0m0.110s
sys     0m0.254s
$ time  ~/rpmbuild/BUILD/net-tools-2.0/netstat  -atn |wc -l
16202

real    0m0.133s
user    0m0.115s
sys     0m0.027s

finalement

[^ ss-using-procfs]: Si l'acquisition d'informations par netlink échoue, les informations seront acquises en utilisant procfs.

$ time  ss -atn |wc -l
15922

real    0m0.046s
user    0m0.033s
sys     0m0.021s

Étant donné que la commande netstat ou net-tools est considérée comme obsolète, il est préférable d'utiliser la commande ss avec obéissance.

Recommended Posts

Accélérez la commande netstat
À propos de la commande de service
Installez la commande pip
python3 Mesurez la vitesse de traitement.
Ce que j'ai fait pour accélérer la tâche de recherche de chaînes
Cloner à l'aide de la commande dd
Jusqu'à ce que le shell trouve la commande
Une commande pour vérifier facilement la vitesse du réseau sur la console
Numba pour accélérer en Python
Plongez dans la commande Django Custom [1]
commande mv Monter d'un niveau
Dans la commande python, python pointe vers python3.8
[linux] commande kill pour tuer le processus
Demandez à python de lire la sortie de la commande
Accélérez grossièrement Python avec numba
Projet Euler 4 Tentative d'accélération
Comment accélérer les calculs Python
La commande hostname peut être multifonctionnelle
Frappez la commande supérieure avec htop
[DRF] Extrait pour accélérer PrimaryKeyRelatedField
Accélérer la compilation C / C ++ avec ccache
Commande pour le répertoire courant Python
Recherchez le nom du réseau Wi-Fi (SSID) de votre Mac sur la ligne de commande