Maison  >  Article  >  Opération et maintenance  >  Parlons de plusieurs technologies zéro copie et de scénarios applicables sous Linux

Parlons de plusieurs technologies zéro copie et de scénarios applicables sous Linux

青灯夜游
青灯夜游avant
2020-07-27 17:40:013370parcourir

Parlons de plusieurs technologies zéro copie et de scénarios applicables sous Linux

Cet article traite des principales technologies zéro copie et des scénarios dans lesquels la technologie zéro copie est applicable sous Linux. Afin d'établir rapidement la notion de zéro copie, nous introduisons un scénario couramment utilisé :

Citation ##

Ecriture d'un serveur Lors de l'exécution un programme (Serveur Web ou serveur de fichiers), le téléchargement de fichiers est une fonction de base. A ce moment, la tâche du serveur est : Envoyer les fichiers dans le disque hôte du serveur depuis le socket connecté sans modification Nous utilisons généralement le code suivant pour terminer :

while((n = read(diskfd, buf, BUF_SIZE)) > 0)
    write(sockfd, buf , n);

Opération de base. Il s'agit de lire le contenu du fichier du disque vers le tampon en boucle, puis d'envoyer le contenu du tampon à socket. Mais parce que l'opération I/O de Linux utilise par défaut la mise en mémoire tampon I/O. Les deux principaux appels système utilisés ici sont read et write Nous ne savons pas ce que le système d'exploitation y fait. En fait, dans l'opération I/O ci-dessus, plusieurs copies de données ont eu lieu.

Lorsqu'une application accède à un certain élément de données, le système d'exploitation vérifie d'abord si le fichier a été accédé récemment et si le contenu du fichier est mis en cache dans le tampon du noyau. Si tel est le cas, le système d'exploitation vérifie directement en conséquence. au système read Appelez l'adresse buf fournie pour copier le contenu du tampon du noyau dans le tampon de l'espace utilisateur spécifié par buf. Sinon, le système d'exploitation copie d'abord les données sur le disque dans le tampon du noyau. Cette étape repose actuellement principalement sur DMA pour la transmission, puis copie le contenu du tampon du noyau dans le tampon utilisateur.
Ensuite, l'appel système write copie le contenu du tampon utilisateur dans le tampon noyau lié à la pile réseau, et enfin socket envoie le contenu du tampon noyau à la carte réseau.
Cela dit, regardons l'image pour que ce soit clair :

Parlons de plusieurs technologies zéro copie et de scénarios applicables sous LinuxParlons de plusieurs technologies zéro copie et de scénarios applicables sous Linux


Comme on peut le voir sur l'image ci-dessus, un total de quatre copies de données ont été générées. Même si DMA est utilisé pour gérer la communication avec le matériel, le CPU doit toujours traiter deux copies de données en même temps, plusieurs changements de contexte se produisent entre le mode utilisateur et le mode noyau, ce qui est sans aucun doute. augmente la charge sur le processeur.

Au cours de ce processus, nous n'avons apporté aucune modification au contenu du fichier, donc copier des données dans les deux sens entre l'espace noyau et l'espace utilisateur est sans aucun doute un gaspillage, et zéro copie sert principalement à résoudre cette inefficacité.

Qu'est-ce que la technologie zéro copie ? ##

La tâche principale du zéro copie est d' empêcher le processeur de copier des données d'un stockage à un autre. L'objectif principal est d'utiliser divers zéro copie. technologies à éviter Le processeur effectue un grand nombre de tâches de copie de données pour réduire les copies inutiles, ou laisse d'autres composants effectuer ce type de tâches simples de transfert de données, libérant ainsi le processeur pour qu'il puisse se concentrer sur d'autres tâches. Cela permet une utilisation plus efficace des ressources système.

Reprenons l'exemple de la citation. Comment réduire le nombre de copies de données ? Un objectif évident est de réduire la copie des données entre l'espace noyau et l'espace utilisateur. Cela introduit également un type de copie nulle :

afin que la transmission des données n'ait pas besoin d'être effectuée. via l'espace utilisateur

Utiliser mmap#####

Une façon de réduire le nombre de copies est pour appeler mmap() à la place, lisez call :

buf = mmap(diskfd, len);
write(sockfd, buf, len);

L'application appelle mmap(), les données sur le disque passeront par le tampon du noyau qui est copié par DMA, puis le système d'exploitation partagera cela tampon du noyau avec l'application, de sorte qu'il n'est pas nécessaire de copier le contenu du tampon du noyau dans l'espace utilisateur. L'application appelle à nouveau write() et le système d'exploitation copie directement le contenu du tampon du noyau dans le tampon socket. Tout cela se produit dans l'état du noyau. Enfin, le tampon socket envoie les données à la carte réseau.
De même, regarder l'image est très simple :

Parlons de plusieurs technologies zéro copie et de scénarios applicables sous Linux

L'utilisation de mmap au lieu de read réduit évidemment une copie. Lorsque la quantité de données copiées est importante, cela s'améliore sans aucun doute. efficacité. Mais utiliser mmap a un coût. Lorsque vous utilisez mmap, vous pouvez rencontrer des pièges cachés. Par exemple, lorsque votre programme map lit un fichier, mais que le fichier est tronqué (tronqué) par un autre processus, l'appel système d'écriture se terminera par le signal SIGBUS car il accède à une adresse illégale. Le signal SIGBUS tuera votre processus par défaut et générera un coredump Si votre serveur est arrêté de cette manière, cela entraînera une perte.

通常我们使用以下解决方案避免这种问题:

1、为SIGBUS信号建立信号处理程序
当遇到SIGBUS信号时,信号处理程序简单地返回,write系统调用在被中断之前会返回已经写入的字节数,并且errno会被设置成success,但是这是一种糟糕的处理办法,因为你并没有解决问题的实质核心。

2、使用文件租借锁
通常我们使用这种方法,在文件描述符上使用租借锁,我们为文件向内核申请一个租借锁,当其它进程想要截断这个文件时,内核会向我们发送一个实时的RT_SIGNAL_LEASE信号,告诉我们内核正在破坏你加持在文件上的读写锁。这样在程序访问非法内存并且被SIGBUS杀死之前,你的write系统调用会被中断。write会返回已经写入的字节数,并且置errno为success。

我们应该在mmap文件之前加锁,并且在操作完文件后解锁:

if(fcntl(diskfd, F_SETSIG, RT_SIGNAL_LEASE) == -1) {
    perror("kernel lease set signal");
    return -1;
}
/* l_type can be F_RDLCK F_WRLCK  加锁*/
/* l_type can be  F_UNLCK 解锁*/
if(fcntl(diskfd, F_SETLEASE, l_type)){
    perror("kernel lease set type");
    return -1;
}

使用sendfile#####

从2.1版内核开始,Linux引入了sendfile来简化操作:

#include<sys>
ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count);</sys>

系统调用sendfile()在代表输入文件的描述符in_fd和代表输出文件的描述符out_fd之间传送文件内容(字节)。描述符out_fd必须指向一个套接字,而in_fd指向的文件必须是可以mmap的。这些局限限制了sendfile的使用,使sendfile只能将数据从文件传递到套接字上,反之则不行。
使用sendfile不仅减少了数据拷贝的次数,还减少了上下文切换,数据传送始终只发生在kernel space

Parlons de plusieurs technologies zéro copie et de scénarios applicables sous Linux

在我们调用sendfile时,如果有其它进程截断了文件会发生什么呢?假设我们没有设置任何信号处理程序,sendfile调用仅仅返回它在被中断之前已经传输的字节数,errno会被置为success。如果我们在调用sendfile之前给文件加了锁,sendfile的行为仍然和之前相同,我们还会收到RT_SIGNAL_LEASE的信号。

目前为止,我们已经减少了数据拷贝的次数了,但是仍然存在一次拷贝,就是页缓存到socket缓存的拷贝。那么能不能把这个拷贝也省略呢?

借助于硬件上的帮助,我们是可以办到的。之前我们是把页缓存的数据拷贝到socket缓存中,实际上,我们仅仅需要把缓冲区描述符传到socket缓冲区,再把数据长度传过去,这样DMA控制器直接将页缓存中的数据打包发送到网络中就可以了。

总结一下,sendfile系统调用利用DMA引擎将文件内容拷贝到内核缓冲区去,然后将带有文件位置和长度信息的缓冲区描述符添加socket缓冲区去,这一步不会将内核中的数据拷贝到socket缓冲区中,DMA引擎会将内核缓冲区的数据拷贝到协议引擎中去,避免了最后一次拷贝。

Parlons de plusieurs technologies zéro copie et de scénarios applicables sous Linux

不过这一种收集拷贝功能是需要硬件以及驱动程序支持的。

使用splice#####

sendfile只适用于将数据从文件拷贝到套接字上,限定了它的使用范围。Linux在2.6.17版本引入splice系统调用,用于在两个文件描述符中移动数据:

#define _GNU_SOURCE         /* See feature_test_macros(7) */
#include <fcntl.h>
ssize_t splice(int fd_in, loff_t *off_in, int fd_out, loff_t *off_out, size_t len, unsigned int flags);</fcntl.h>

splice调用在两个文件描述符之间移动数据,而不需要数据在内核空间和用户空间来回拷贝。他从fd_in拷贝len长度的数据到fd_out,但是有一方必须是管道设备,这也是目前splice的一些局限性。flags参数有以下几种取值:

  • SPLICE_F_MOVE : Essayez de déplacer des données au lieu de copier des données. Ceci est juste un petit rappel au noyau : si le noyau ne peut pas déplacer les données de pipe ou si le cache de pipe n'est pas une page complète, il doit quand même copier les données. Il y a quelques problèmes avec l'implémentation initiale de Linux, donc cette option ne fonctionne pas à partir de 2.6.21 et elle devrait être implémentée dans les versions ultérieures de Linux.
  • ** SPLICE_F_NONBLOCK** : L'opération splice ne sera pas bloquée. Cependant, si le descripteur de fichier n'est pas configuré pour des E/S non bloquantes, l'appel de splice peut toujours bloquer.
  • ** SPLICE_F_MORE** : les appels splice suivants contiendront plus de données.

L'appel splice utilise le mécanisme de tampon de canal proposé par Linux, donc au moins un descripteur doit être un canal.

Les technologies sans copie ci-dessus sont toutes mises en œuvre en réduisant la copie des données entre l'espace utilisateur et l'espace noyau. Cependant, parfois, les données doivent être copiées entre l'espace utilisateur et l'espace noyau. Pour le moment, nous ne pouvons travailler que sur le timing de la copie des données dans l’espace utilisateur et dans l’espace noyau. Linux utilise généralement la copie en écriture (copie en écriture) pour réduire la surcharge du système. Cette technologie est souvent appelée COW.

Pour des raisons d'espace, cet article ne présente pas la copie sur écriture en détail. Une description approximative est la suivante : si plusieurs programmes accèdent au même élément de données en même temps, alors chaque programme dispose d'un pointeur vers cet élément de données. Du point de vue de chaque programme, il possède cet élément de données indépendamment lorsque le programme. doit Lorsque le contenu des données est modifié, le contenu des données sera copié dans le propre espace d'application du programme. À ce moment, les données deviendront les données privées du programme. Si le programme n'a pas besoin de modifier les données, il n'a jamais besoin de copier les données dans son propre espace d'application. Cela réduit la copie des données. Le contenu copié lors de la rédaction peut être utilisé pour rédiger un autre article. . .

De plus, il existe certaines technologies sans copie. Par exemple, l'ajout de la balise O_DIRECT aux E/S Linux traditionnelles peut directement I/O éviter la mise en cache automatique, et il existe également des fbufstechnologies immatures. , cet article n'a pas encore couvert toutes les technologies sans copie, mais n'en présente que quelques-unes courantes. Si vous êtes intéressé, vous pouvez l'étudier vous-même. Généralement, les projets de serveur matures modifieront également les parties du noyau liées aux E/S. améliorer leur propre taux de transmission de données.

Tutoriel recommandé : "Exploitation et maintenance Linux"

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer