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.
/ proc / net / tcp
pour obtenir des informations sur une session TCP depuis le noyau./ proc / net / tcp
, et dans IPv6, il est divisé en / proc / net / tcp6
, mais il est compliqué de les écrire ensemble à chaque fois, donc il est écrit comme / proc / net / tcp
par la suite. Faire
[^ about-procfs]: Je n'entrerai pas dans les détails de procfs lui-même ici. Voir man proc
, etc. selon le cas.
--procfs utilise un mécanisme appelé système de fichiers seq en interne
--Le système de fichiers seq est résumé ici À propos du système de fichiers seq --Qiita
--Lorsque vous exécutez un appel système de lecture pour un fichier spécial qui utilise le système de fichiers seq, il passe par un tampon avec la même capacité que la valeur de PAGE_SIZE
(4096 octets dans de nombreux environnements) normalement réservé du côté du noyau. , Lire Copier les données dans la zone tampon côté espace utilisateur spécifiée dans l'appel systèmeman 2 read
etc. comme approprié pour les arguments de l'appel système read./ proc / net / tcp
peut être de plusieurs MiByte, mais l'appel système de lecture ne peut lire que les données d'une capacité de 4096Byte ou moins, et / Des centaines d'appels système de lecture doivent être exécutés pour lire tout le contenu de proc / net / tcp
--Dans / proc / net / tcp
, si une session TCP = 1 ligne équivaut à 150 octets et que 10000 sessions sont tenues (y compris TIME_WAIT), la taille du fichier sera d'environ 1,5 Mo et l'appel système lu sera de 300. Sera exécuté plus d'une fois
―― En fait, il est arrondi à une capacité bien séparée pour chaque ligne et ne peut lire qu'un peu moins de 4096 octets, de sorte que le nombre de fois augmentera encore./ proc / net / tcp
dans le noyau Linux et la commande netstat pour augmenter la quantité de données lues par un appel système de lecture, le nombre d'appels d'appel système de lecture diminue Et la commande netstat est plus rapide$ 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
--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"
--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
--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
――Le temps requis dans l'environnement utilisé cette fois est supérieur à 1,5
rpmbuild -ba ~/rpmbuild/SPECS/kernel.spec
find ~/rpmbuild/ -name "*.rpm"
/ proc / net / tcp
par incréments de 64 Ko./ proc / net / tcp
, utilisez la commande strace pour observer l'état de l'appel système de lecture.$ 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 +++
$ 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
yumdownloader --source net-tools
rpm -ivh net-tools-2.0-0.22.20131004git.el7.src.rpm
sudo yum -y install libselinux-devel
--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
--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
--Observez l'appel système de lecture avec la commande strace pour la commande netstat avant la modification.
/ proc / net / tcp
.$ 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
--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
/ proc / net / tcp
(utilise une socket spéciale". Le nombre de sessions TCP est acquis par netlink "), et il peut être traité plus rapidement que la commande netstat modifiée ci-dessus.[^ 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