Artículos de Java IO: ¿qué es la copia cero?

Primero, el modo IO tradicional:

  • (1) La aplicación del espacio del usuario emite la llamada del sistema de lectura, lo que provocará un cambio de contexto del espacio del usuario al espacio del kernel, y luego leerá los datos en el archivo del disco al búfer del espacio del kernel a través de DMA
  • (2) Luego, copie los datos del búfer de espacio del kernel en el búfer de datos del espacio del usuario, y luego la llamada del sistema de lectura regresa, y el regreso de la llamada del sistema provocará un cambio de contexto del espacio del kernel al espacio del usuario.
  • (3) La llamada al sistema de escritura, el contexto del espacio del usuario al espacio del núcleo se cambia nuevamente; luego, los datos del búfer del espacio del usuario se copian al búfer del zócalo del espacio del núcleo (también el búfer del núcleo, pero solo para uso del zócalo) , y luego el sistema de escritura La llamada regresa, activando un cambio de contexto nuevamente
  • (4) Finalmente, transmita de forma asíncrona los datos del búfer de socket a la tarjeta de red, es decir, el retorno de la llamada al sistema de escritura no garantiza que los datos se transmitan a la tarjeta de red.

        En el modo de E/S de datos tradicional, para leer un archivo de disco y enviarlo al servicio remoto, hay cuatro cambios de contexto entre el espacio del usuario y el espacio del núcleo, cuatro copias de datos, dos copias de datos de la CPU y dos tiempos de DMA. Pero la copia de datos de dos CPU es el proceso que consume más recursos y tiempo. Este proceso también requiere alternar entre el modo kernel y el modo de usuario, y los recursos de la CPU son muy valiosos. Para copiar una gran cantidad de datos, también necesita para procesar una gran cantidad de tareas.Si se pueden eliminar las dos copias de la CPU, lo que no solo puede ahorrar recursos de la CPU, sino también evitar cambiar entre el modo kernel y el modo de usuario. Y la tecnología de copia cero es para resolver este problema.

Método DMA (acceso directo a la memoria, acceso directo a la memoria): una tecnología en la que los dispositivos externos intercambian datos directamente con la memoria del sistema sin pasar por la CPU

 

En segundo lugar, qué es la copia cero:

        Copia cero significa que cuando se realiza la E/S o la transmisión de datos, los datos han sufrido cero copias en el modo de usuario, y no es que los datos no se copien. Al reducir la cantidad innecesaria de copias de datos de la CPU entre el búfer del kernel y el búfer del proceso del usuario y la cantidad de cambios de contexto entre el modo de usuario y el modo del kernel durante el proceso de transmisión de datos, se reduce la sobrecarga de la CPU en estos dos aspectos, y la La CPU queda libre para realizar otras tareas, que se pueden utilizar de forma más eficaz: recursos del sistema, mejora la eficiencia de la transmisión, reduce el uso de la memoria y mejora el rendimiento de las aplicaciones.

        Dado que la copia cero completa todas las copias de memoria en el espacio del kernel, el espacio disponible del búfer del socket se puede maximizar, lo que aumenta la cantidad de datos procesados ​​en una llamada al sistema y reduce aún más la cantidad de cambios de contexto. La tecnología de copia cero se basa en PageCache, y PageCache almacena en caché los datos a los que se accedió recientemente, lo que mejora el rendimiento del acceso a los datos en caché. Al mismo tiempo, para resolver el problema del direccionamiento mecánico lento del disco, también ayuda al algoritmo de programación de E/S a logre la combinación de E/S y la lectura previa (esta es también la razón por la que las lecturas secuenciales tienen un mejor rendimiento que las lecturas aleatorias), lo que mejora aún más el rendimiento de la copia cero.

Tercero, el método de copia cero en Linux:

1. Copia cero implementada por mmap + escribir:

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

        Entre las cuatro copias de memoria en el modo IO tradicional, dos copias relacionadas con el dispositivo físico (copiar el contenido del disco a la memoria y copiar la memoria a la tarjeta de red) son esenciales. Sin embargo, las dos copias relacionadas con el búfer del usuario no son necesarias.Si el núcleo copia directamente el contenido del búfer del núcleo al búfer del zócalo después de leer el archivo y notifica al proceso después de enviar la tarjeta de red, de modo que los datos de una CPU la copia se puede reducir. El mapeo de memoria mmap realiza una copia cero a través del método descrito anteriormente. Su núcleo es que el sistema operativo compartirá el búfer del kernel con el programa de aplicación, y un segmento de la memoria del espacio del usuario se puede mapear al espacio del kernel. Cuando el mapeo es exitosa, el usuario La modificación del área de memoria del segmento se puede reflejar directamente en el espacio del kernel; de manera similar, la modificación de esta área en el espacio del kernel también se refleja directamente en el espacio del usuario. Debido a esta relación de mapeo, no hay necesidad de copiar datos entre el espacio del usuario y el espacio del núcleo, lo que mejora la eficiencia de la transmisión de datos.Esta es la tecnología de mapeo de memoria directa. El diagrama esquemático específico es el siguiente:

  • (1) Emita la llamada al sistema mmap, lo que resulta en un cambio de contexto del espacio del usuario al espacio del kernel; luego copie los datos en el archivo del disco al búfer del espacio del kernel a través de 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 núcleo al espacio del usuario, porque el espacio del usuario y el espacio del núcleo comparten este búfer.
  • (4) Emita la llamada del 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 del sistema de escritura regresa, lo que provoca un cambio de contexto del espacio del kernel al espacio del usuario
  • (5) DMA copia de forma asíncrona los datos en el búfer del zócalo a la tarjeta de red

        La E/S de copia cero de mmap realiza 4 cambios de contexto entre el espacio del usuario y el espacio del kernel, y 3 copias de datos; las 3 copias de datos incluyen 2 copias de DMA y 1 copia de CPU

2. Copia cero implementada por sendfile:

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

        Siempre que nuestro código ejecute llamadas al sistema, como leer o escribir, definitivamente ocurrirán dos cambios de contexto: primero, cambiar del modo de usuario al modo de kernel, y cuando el kernel termine de ejecutar la tarea, vuelva al modo de usuario y transfiéralo a el código del proceso para su ejecución. Por lo tanto, si desea reducir la cantidad de cambios de contexto, debe reducir la cantidad de llamadas al sistema. La solución es combinar las llamadas al sistema de lectura y escritura en una sola, y completar el intercambio de datos entre el disco y la tarjeta de red en el núcleo. El archivo de envío introducido en el kernel de la versión 2.1 de Linux implementa la copia cero de esta manera. El diagrama de flujo específico es el siguiente:

  • (1) Emita la llamada del sistema sendfile, lo que resulta en un cambio de contexto del espacio del usuario al espacio del kernel; luego copie el contenido del archivo del disco al búfer del espacio del kernel a través de DMA,
  • (2) Luego copie los datos del búfer de espacio del núcleo al búfer del zócalo
  • (3) La llamada del sistema sendfile regresa, lo que resulta en un cambio de contexto del espacio del kernel al espacio del usuario
  • (4) DMA transfiere de forma asíncrona los datos en el búfer del socket del espacio del kernel a la red

        La E/S de copia cero implementada por sendfile utiliza 2 cambios de contexto entre el espacio del usuario y el espacio del núcleo, y 3 copias de datos. Las 3 copias de datos incluyen 2 copias de DMA y 1 copia de CPU

3. Implementación de copia cero de sendfile con función de copia de colección DMA:

        La versión de Linux 2.4 lo admite.El sistema operativo proporciona el modo SG-DMA de dispersión y recopilación, que lee directamente los datos del búfer de espacio del kernel a la tarjeta de red, sin copiar los datos en el búfer de espacio del kernel al búfer de socket.

  •  (1) Emita la llamada al sistema sendfile, lo que resulta en un cambio de contexto del espacio del usuario al espacio del kernel; luego copie el contenido del archivo del disco al búfer del espacio del kernel a través de DMA
  • (2) Los datos no se copian en el búfer del zócalo, pero la información del descriptor correspondiente se copia en el búfer del zócalo. El descriptor contiene dos tipos de información: ① la dirección de memoria del búfer del núcleo, ② el desplazamiento del búfer del núcleo de
  • (3) La llamada al sistema sendfile regresa, lo que resulta en un cambio de contexto del espacio del kernel al espacio del usuario.
  • (4) DMA copia directamente los datos en el búfer del kernel a la tarjeta de red de acuerdo con la dirección y el desplazamiento provistos por el descriptor en el búfer del zócalo.

        La E/S implementada por sendfile con la función de copia de colección DMA utiliza dos cambios de contexto entre el espacio del usuario y el espacio del kernel, y dos copias de datos, y estas dos copias de datos son todas copias que no son de CPU, logrando así la I/ de copia cero más ideal Transferencia O, sin necesidad de ninguna copia de la CPU y cambio de

Nota: Cabe señalar que la copia cero tiene una desventaja, es decir, no permite que el proceso realice algún procesamiento en el contenido del archivo y luego lo envíe, como la compresión de datos y luego lo envíe.

4. Escenarios de aplicación de la tecnología de copia cero:

1. NIO en Java:

(1) Método de copia cero de mmap + escritura:

        MappedByteBuffer generado por el método map() de FileChannel: FileChannel proporciona el método map(), que puede establecer un mapeo de memoria virtual entre un archivo abierto y MappedByteBuffer.MappedByteBuffer hereda de ByteBuffer; la memoria del búfer es la memoria de una memoria de archivo área mapeada. La capa inferior del método map() se implementa a través de mmap, por lo que después de leer la memoria del archivo desde el disco al búfer del núcleo, el espacio del usuario y el espacio del núcleo comparten el búfer.

(2) Método de copia cero del archivo de envío:

        Si el sistema operativo subyacente admite transferTo y transferFrom de FileChannel, transferTo y transferFrom también utilizarán la tecnología de copia cero de sendfile para transferir datos.

2. Marco de red:

La copia cero de Netty se refleja principalmente en los siguientes cinco aspectos:

(1) En la comunicación de red, Netty usa memoria directa para recibir y enviar ByteBuffer, y usa memoria directa fuera del montón para lectura y escritura de Socket, y no requiere una segunda copia del búfer de bytes. Si la memoria de montón tradicional se usa para la lectura y escritura de socket, la JVM copiará el búfer de la memoria de montón a la memoria directa (¿por qué copiar? Debido a que la JVM se someterá a la recolección de basura de GC, la dirección de memoria de los datos cambiará y la memoria en el montón se copiará directamente.La dirección se pasa al kernel, una vez que se cambia la dirección de la memoria, el kernel no puede leer los datos), y luego se escribe en el Socket. En comparación con la memoria directa fuera del montón, el mensaje tiene una copia de memoria adicional del búfer durante el proceso de envío.

(2) En la transferencia de archivos, FileChannel.tranferTo de Netty envuelto en FileRegion realiza la transferencia de archivos, que puede enviar directamente los datos del búfer de archivos al canal de destino, evitando el problema de copia de memoria causado por el método tradicional de escritura cíclica.

(3) En la operación de caché, Netty proporciona la clase CompositeByteBuf, que puede combinar múltiples ByteBufs en un ByteBuf lógico, evitando la copia entre cada ByteBuf.

(4) A través de la operación de envoltura, podemos envolver la matriz byte[], ByteBuf, ByteBuffer, etc. en un objeto Netty ByteBuf, evitando así la operación de copia.

(5) ByteBuf admite la operación de división, por lo que ByteBuf se puede descomponer en varios ByteBufs que comparten la misma área de almacenamiento, evitando la copia de memoria.

3, kafka:

El archivo de índice de Kafka usa el método mmap + write, y el archivo de datos usa el método sendfile

Artículo de referencia:

(Recomendación clave) https://juejin.cn/post/6887469050515947528

https://juejin.cn/post/6854573213452599310#heading-8

https://blog.csdn.net/u022812849/article/details/109805403

Supongo que te gusta

Origin blog.csdn.net/a745233700/article/details/122660332
Recomendado
Clasificación