Explique la tecnología de copia cero en Linux en detalle, ¡y Xiaobai puede entenderla en segundos!

Prefacio

En lengua vernácula, copia cero significa que los datos no se copian de un área de almacenamiento a otra. Pero sin la duplicación de datos, ¿cómo es posible realizar la transmisión de datos?

De hecho, la copia cero que encontramos en java NIO, netty y kafka no es para no copiar datos, sino para reducir la cantidad de copias de datos innecesarias, mejorando así el rendimiento del código.

El contenido de este artículo:

1. Los beneficios de la copia cero:

2. "Espacio de usuario" y "espacio del kernel" del sistema Linux

3. Dirección de implementación de la tecnología de copia cero en Linux

4. El principio del mecanismo de copia cero

4.1. E / S tradicional

4.2 、 DMA

5. E / S de copia cero realizada por sendfile

6. E / S realizada por sendfile con función de recopilación y copia DMA

7. "E / S tradicional" VS "E / S de copia cero de archivo de envío"

8. E / S de copia cero a través de mmap

9. FileChannel y copia cero

10. Método de copia cero proporcionado por Java


 

1. Los beneficios de la copia cero:

  • Reduzca o incluso evite por completo las copias innecesarias de la CPU, liberando así la CPU para realizar otras tareas
  • Reducir el uso de ancho de banda de la memoria
  • Por lo general, la tecnología de copia cero también puede reducir el cambio de contexto entre el espacio del usuario y el espacio del kernel del sistema operativo
     

2. "Espacio de usuario" y "espacio del kernel" del sistema Linux

  • Espacio del kernel: el espacio utilizado por el propio Linux; proporciona principalmente funciones como la programación de procesos, la asignación de memoria y la conexión de recursos de hardware.

  • Espacio de usuario: el espacio proporcionado a cada proceso de programa; el espacio de usuario no tiene la autoridad para acceder a los recursos del espacio del kernel. Si la aplicación necesita usar los recursos del espacio del kernel, debe completarse mediante una llamada al sistema: cambiar del espacio del usuario al espacio del kernel, completar Cambiar del espacio del kernel al espacio del usuario después de las operaciones relacionadas

 

3. Dirección de implementación de la tecnología de copia cero en Linux

① E / S directa: para este método de transmisión de datos, el programa de aplicación puede acceder directamente al almacenamiento de hardware y el kernel del sistema operativo solo ayuda a la transmisión de datos. De esta manera, todavía hay un cambio de contexto entre el espacio del usuario y el espacio del kernel, pero los datos en el hardware no se copiarán al espacio del kernel, sino que se copiarán directamente al espacio del usuario, por lo que no hay un búfer de espacio del kernel y un usuario para E / S directa. Copia de datos entre búferes de espacio.

② En el proceso de transmisión de datos, evite la copia de datos de la CPU entre el búfer de espacio de usuario y el búfer de espacio del kernel del sistema, y ​​la copia de datos de la CPU en el espacio del kernel del sistema. Este artículo analiza principalmente el mecanismo de copia cero de esta manera.

③ copia en escritura (tecnología de copia en escritura): en algunos casos, el búfer de espacio del kernel del sistema operativo Linux puede ser compartido por varias aplicaciones, y el sistema operativo puede asignar la dirección del búfer de espacio de usuario al kernel En el búfer de espacio. Cuando la aplicación necesita modificar los datos compartidos, necesita copiar los datos al búfer de espacio de usuario de la aplicación, y la modificación de los datos en el búfer de espacio de usuario no afectará a otras aplicaciones de datos compartidos programa. Por lo tanto, si la aplicación no necesita modificar los datos, no habrá operación de copiar datos del búfer de espacio del núcleo del sistema al búfer de espacio de usuario.

Tenga en cuenta que si se pueden implementar varios mecanismos de copia cero depende de si el sistema operativo subyacente proporciona el soporte correspondiente.

 

4. El principio del mecanismo de copia cero

A continuación, utilizamos un escenario de aplicación muy común en Java: enviar archivos en el sistema al extremo remoto (este proceso implica: archivos en el disco -> memoria (matriz de bytes) -> transmisión a usuarios / red) para expandir la tradición en detalle Operaciones de E / S y operaciones de E / S implementadas por copia cero.

4.1. E / S tradicional

#include <unistd>
ssize_t write(int filedes, void *buf, size_t nbytes);
ssize_t read(int filedes, void *buf, size_t nbytes);
  • Por ejemplo, java lee un archivo de disco en el sistema Linux y lo envía al servicio remoto.

  • 1) La ejecución de la llamada al sistema de lectura provocará un cambio de contexto del espacio del usuario al espacio del kernel, y luego leerá los datos en el archivo desde el disco al búfer del espacio del kernel a través de DMA

  • 2) Luego copie los datos en el búfer de espacio del kernel a la memoria de proceso del espacio de usuario, y luego regresa la llamada al sistema de lectura. La devolución de la llamada al sistema provocará un cambio de contexto del espacio del kernel al espacio del usuario.

  • 3) La llamada al sistema de escritura volverá a provocar un cambio de contexto del espacio del usuario al espacio del kernel, copiar los datos de la memoria en el proceso del espacio del usuario al búfer del socket en el espacio del kernel (también el búfer del kernel, pero para uso del socket), y luego La llamada al sistema de escritura regresa, activando el cambio de contexto nuevamente

  • 4) En cuanto a la transmisión de datos desde el búfer del socket a la tarjeta de red, es un proceso independiente y asíncrono, lo que significa que la devolución de la llamada al sistema de escritura no garantiza que los datos se transmitan a la tarjeta de red.

P: ¿Puede preguntar qué significa independiente y asincrónico? ¿Podría ser que la llamada regrese antes de que se transmitan los datos?
R: De hecho, la devolución de la llamada no garantiza que se transmitan los datos, ni siquiera garantiza el inicio de la transmisión. Simplemente significa que los datos que queremos enviar se colocan en una cola para ser enviados, y puede haber muchos paquetes en la cola antes que nosotros. A menos que el controlador o el hardware implementen un anillo o una cola de prioridad, los datos se transmiten de la manera primero en entrar, primero en salir.

En general, la operación de E / S tradicional realizó 4 cambios de contexto entre el espacio del usuario y el espacio del kernel, y 4 copias de datos. Entre las 4 copias de datos, se incluyen 2 copias DMA y 2 copias de CPU.

P: ¿Por qué el modo de E / S tradicional lee datos del disco al búfer de espacio del kernel y luego copia los datos del búfer de espacio del kernel al búfer de espacio de usuario? ¿Por qué no leer los datos directamente desde el disco al búfer de espacio del usuario?
R: La razón por la que el modo de E / S tradicional lee datos del disco al búfer de espacio del kernel en lugar de hacerlo directamente al búfer de espacio de usuario es para reducir las operaciones de E / S del disco para mejorar el rendimiento. Debido a que el sistema operativo leerá previamente más datos de archivo en el búfer de espacio del kernel durante una llamada al sistema read () de acuerdo con el principio de localidad, de modo que cuando la próxima llamada al sistema read (), los datos que se leerán ya existen Cuando esté en el búfer de espacio del kernel, simplemente copie los datos directamente en el búfer de espacio del usuario. No es necesario realizar una operación de E / S de disco ineficiente (nota: la velocidad de la operación de E / S de disco es varias veces más lenta que el acceso directo a la memoria Magnitud).
P: Dado que el búfer del núcleo del sistema puede reducir las operaciones de E / S del disco, ¿cuál es el búfer BufferedInputStream que usamos a menudo?
R: La función de BufferedInputStream es precargar automáticamente más datos para nosotros de acuerdo con la situación en un búfer de datos de bytes interno que mantiene. Esto puede reducir la cantidad de llamadas al sistema para mejorar el rendimiento.

En general, un gran uso del búfer de espacio del kernel es reducir las operaciones de E / S del disco, porque pre-leerá más datos del disco en el búfer. El uso de BufferedInputStream es para reducir las "llamadas al sistema".

4.2 、 DMA

DMA (acceso directo a la memoria): acceso directo a la memoria: DMA permite que los componentes periféricos transfieran directamente datos de E / S a la memoria principal y la transferencia no requiere la participación de la CPU, lo que libera a la CPU para completar otras cosas .
La transmisión de datos entre el espacio de usuario y el espacio del kernel no tiene una herramienta de transmisión como DMA que no requiera la participación de la CPU, por lo que la transmisión de datos entre el espacio de usuario y el espacio del kernel requiere la participación total de la CPU. Por lo tanto, hay tecnología de copia cero para reducir y evitar el proceso de copia de datos de la CPU innecesario.
 

5. E / S de copia cero realizada por sendfile

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

  • 1) Emita la llamada al sistema sendfile, provocando un cambio de contexto del espacio del usuario al espacio del kernel, y luego copie el contenido del archivo de disco al búfer del espacio del kernel a través del motor DMA, y luego copie los datos del búfer del espacio del kernel al búfer relacionado con el socket Zona

  • 2) La llamada al sistema sendfile regresa, lo que resulta en un cambio de contexto del espacio del kernel al espacio del usuario. DMA transfiere de forma asincrónica los datos en el búfer del socket del espacio del kernel a la tarjeta de red

En general, la E / S de copia cero implementada por sendfile solo usa dos cambios de contexto entre el espacio del usuario y el espacio del kernel, y tres copias de datos. Entre las 3 copias de datos, se incluyen 2 copias DMA y 1 copia de CPU.

P: Pero todavía hay una operación de copia de CPU aquí, es decir, búfer del núcleo ——> búfer de socket. ¿Existe alguna forma de cancelar la operación de copia?
A: si. Pero esto requiere el soporte del sistema operativo subyacente. A partir de Linux 2.4, la capa inferior del sistema operativo proporciona dispersión / recopilación como método DMA para leer datos directamente desde el búfer de espacio del kernel al motor de protocolo sin tener que copiar los datos en el búfer de espacio del kernel. Al búfer asociado con el socket del espacio del kernel.
 

6. E / S realizada por sendfile con función de recopilación y copia DMA

  • A partir de la versión 2.4 de Linux, el sistema operativo proporciona métodos de dispersión y recopilación SG-DMA, que leen datos directamente desde el búfer de espacio del kernel a la tarjeta de red sin copiar los datos del búfer de espacio del kernel al búfer de socket.

  • 1) Emita la llamada al sistema sendfile, provocando un cambio de contexto del espacio del usuario al espacio del kernel. Copie el contenido del archivo de disco en el búfer de espacio del kernel a través del motor DMA
  • 2) Los datos no se copian en el búfer del conector, sino que se copia la información del descriptor correspondiente en el búfer del conector. El descriptor contiene dos tipos de información: A) la dirección de memoria del búfer del kernel, B) el desplazamiento del búfer del kernel

  • 3) La llamada al sistema sendfile regresa, lo que resulta en un cambio de contexto del espacio del kernel al espacio del usuario. DMA copia directamente los datos en el búfer del núcleo a la tarjeta de red de acuerdo con la dirección y el desplazamiento proporcionados por el descriptor del búfer de socket

En general, la E / S implementada por sendfile con la función de recopilación y copia de DMA utiliza dos conmutadores de contexto entre el espacio del usuario y el espacio del kernel, y dos copias de datos, y estas dos copias de datos son copias sin CPU. De esta manera, hemos logrado la transmisión de E / S de copia cero ideal, sin ninguna copia de CPU única y un cambio de contexto mínimo.

Acerca de sendfile:

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

Antes de la versión linux2.6.33, sendfile se refiere al archivo de soporte para transferir datos entre el socket, es decir, in_fd es equivalente a un archivo que admite mmap, y out_fd debe ser un socket. Pero a partir de la versión linux2.6.33, out_fd puede ser cualquier tipo de descriptor de archivo. Entonces, desde la versión linux2.6.33, sendfile puede soportar la transmisión de datos entre "archivo a archivo" y "archivo a socket".
 

7. "E / S tradicional" VS "E / S de copia cero de archivo de envío"

  • La E / S tradicional usa dos instrucciones del sistema de lectura y escritura para completar las operaciones de lectura y transmisión de datos, de modo que la sobrecarga de cambio de contexto entre el espacio del usuario y el espacio del kernel se genera cuatro veces; y el archivo de envío solo usa una instrucción para completar los datos Por lo tanto, solo ocurrieron dos cambios de contexto entre el espacio del usuario y el espacio del kernel.
  • La E / S tradicional ha producido 2 copias de CPU inútiles, es decir, la copia de los datos en la caché del espacio del kernel y los datos en el búfer del espacio del usuario; mientras que sendfile solo produce una copia de la CPU como máximo, es decir, la copia de datos entre el espacio del kernel, o incluso Con el soporte del sistema operativo subyacente, sendfile puede lograr E / S sin copia de CPU.
  • Debido a que los datos se almacenan en el búfer de espacio de usuario de E / S tradicional, la aplicación puede modificar los datos y otras operaciones; y la copia cero del archivo de envío elimina todo el proceso de copia de datos entre el búfer de espacio del kernel y el búfer de espacio de usuario, por lo que La realización de la E / S de copia cero del archivo de envío se completa en el espacio del kernel, lo que hace imposible que la aplicación opere sobre los datos.

P: Con respecto al tercer punto anterior, ¿qué debemos hacer si necesitamos manipular los datos?
R: Linux proporciona mmap zero copy para satisfacer nuestras necesidades.
 

8. E / S de copia cero a través de mmap

mmap (mapeo de memoria) es un método más caro que sendfile pero mejor que la E / S tradicional.

#include <sys/mman.h>
void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset)

  • 1) Emita la llamada al sistema mmap, provocando un cambio de contexto del espacio del usuario al espacio del kernel. Luego, copie los datos del archivo de disco en el búfer de espacio del kernel a través del motor DMA

  • 2) La llamada al sistema mmap regresa, lo que resulta en un cambio de contexto del espacio del kernel al espacio del usuario

  • 3) No es necesario copiar datos del espacio del kernel al espacio del usuario, porque el espacio del usuario y el espacio del kernel comparten este búfer

  • 4) Emita la llamada al sistema de escritura, lo que da como resultado un cambio de contexto del espacio del usuario al espacio del kernel. Copie los datos del búfer del espacio del kernel al búfer del socket del espacio del kernel; la llamada al sistema de escritura regresa, lo que resulta en un cambio de contexto del espacio del kernel al espacio del usuario

  • 5) Asíncrono, el motor DMA copia los datos en el búfer del socket a la tarjeta de red

En general, la E / S de copia cero implementada por mmap realizó 4 cambios de contexto entre el espacio del usuario y el espacio del kernel, y 3 copias de datos. Entre las 3 copias de datos, se incluyen 2 copias DMA y 1 copia de CPU.
 

9. FileChannel y copia cero

La tecnología de copia cero que mencionamos anteriormente se usa ampliamente en FileChannel.
El método de mapa de FileChannel devuelve un MappedByteBuffer. MappedByteBuffer es un búfer de bytes directo, la memoria del búfer es un área mapeada en memoria de un archivo. La capa inferior del método del mapa se realiza mediante mmap, por lo que después de leer la memoria del archivo desde el disco al búfer del kernel, el espacio del usuario y el espacio del kernel comparten el búfer.
El archivo mapeado en memoria MappedByteBuffer es un archivo especial que permite a los programas Java acceder directamente desde la memoria. Podemos mapear todo el archivo o una parte de todo el archivo a la memoria, luego el sistema operativo hará la solicitud de página relevante y escribirá la modificación de la memoria en el archivo. Nuestra aplicación solo necesita procesar datos en la memoria, de modo que se puedan lograr operaciones de E / S muy rápidas.

Tres modos de mapa FileChannel

  • Modo de solo lectura
/**
 * Mode for a read-only mapping.
 */
public static final MapMode READ_ONLY = new MapMode("READ_ONLY");

Para el modo de solo lectura, si el programa intenta escribir, lanzará una ReadOnlyBufferException

  • Modo de lectura y escritura
/**
 * Mode for a read/write mapping.
 */
public static final MapMode READ_WRITE = new MapMode("READ_WRITE");

El modo de lectura-escritura indica que los cambios realizados en el búfer eventualmente se transmitirán al archivo. Pero esta modificación puede ser visible o no por otros programas que mapean el mismo archivo.

  • Modo dedicado
/**
 * Mode for a private (copy-on-write) mapping.
 */
public static final MapMode PRIVATE = new MapMode("PRIVATE");

En el modo privado, los cambios en el búfer de resultados no se transmitirán al archivo y no serán visibles para otros programas que mapeen el mismo archivo. En cambio, hará que la parte modificada del búfer se copie solo en el espacio del usuario. Este es el principio de "copia en escritura" del sistema operativo.

FileChannel 的 transferTo 、 transferFrom

Si la capa inferior del sistema operativo lo admite, transferTo y transferFrom también utilizarán la tecnología de copia cero relacionada para realizar la transmisión de datos. Por lo tanto, el uso de copia cero aquí debe depender de la implementación del sistema subyacente.
 

10. Método de copia cero proporcionado por Java

  • La implementación de copia cero de java NIO se basa en mmap + write

  • El MappedByteBuffer generado por el método de mapa de FileChannel FileChannel proporciona el método map (), que puede establecer una asignación de memoria virtual entre un archivo abierto y MappedByteBuffer. MappedByteBuffer hereda de ByteBuffer; la memoria de este búfer es el área de asignación de memoria de un archivo . La capa inferior del método del mapa se realiza mediante mmap, por lo que después de leer la memoria del archivo desde el disco al búfer del kernel, el espacio del usuario y el espacio del kernel comparten el búfer. El uso es el siguiente

public void main(String[] args){
    try {
        FileChannel readChannel = FileChannel.open(Paths.get("./cscw.txt"), StandardOpenOption.READ);
        FileChannel writeChannel = FileChannel.open(Paths.get("./siting.txt"), StandardOpenOption.WRITE, StandardOpenOption.CREATE);
        MappedByteBuffer data = readChannel.map(FileChannel.MapMode.READ_ONLY, 0, 1024 * 1024 * 40);
        //数据传输
        writeChannel.write(data);
        readChannel.close();
        writeChannel.close();
    }catch (Exception e){
        System.out.println(e.getMessage());
    }
}
  • Si transferTo y transferFrom de FileChannel son compatibles con la capa inferior del sistema operativo, transferTo y transferFrom también utilizarán la tecnología de copia cero relacionada para realizar la transmisión de datos. El uso es el siguiente
public void main(String[] args) {
    try {
        FileChannel readChannel = FileChannel.open(Paths.get("./cscw.txt"), StandardOpenOption.READ);
        FileChannel writeChannel = FileChannel.open(Paths.get("./siting.txt"), StandardOpenOption.WRITE, StandardOpenOption.CREATE);
        long len = readChannel.size();
        long position = readChannel.position();
        //数据传输
        readChannel.transferTo(position, len, writeChannel);
        //效果和transferTo 一样的
        //writeChannel.transferFrom(readChannel, position, len, );
        readChannel.close();
        writeChannel.close();
    } catch (Exception e) {
        System.out.println(e.getMessage());
    }
}

 

11. Finalmente

Este artículo es un conocimiento muy superficial del mecanismo de copia cero a través del aprendizaje por video y una gran cantidad de consultas de datos, al menos personalmente. A través de este estudio, aprendí más sobre el sistema operativo Linux. Todos son bienvenidos a dar indicaciones sobre las deficiencias y errores en el artículo ~

  • Finalmente, comparta los materiales de aprendizaje con todos, ¡ todo gratis !

Materiales de aprendizaje: Haga clic aquí para recibirlo gratis, contraseña: CSDN , ¡y hay más materiales de entrevistas y videos de las principales empresas!

 

 

 

 

 

Supongo que te gusta

Origin blog.csdn.net/qq_43080036/article/details/109290905
Recomendado
Clasificación