Mecanismo de copia cero de Linux y FileChannel

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.

  • Beneficios de la copia cero
  • Espacio de kernel y espacio de usuario
  • Búfer y memoria virtual
  • E / S tradicional
  • Copia cero lograda por mmap + write
  • Copia cero implementada por sendfile
  • Copia cero realizada por sendfile con función de copia de colección DMA
  • Método de copia cero proporcionado por Java

Beneficios de la copia cero

  • Reducir o evitar la copia de datos de la CPU innecesaria, liberando así la CPU para realizar otras tareas
  • El mecanismo de copia cero puede reducir el cambio de contexto entre el espacio del usuario y el espacio del kernel del sistema operativo
  • Reducir el uso de memoria

Espacio de kernel y espacio de usuario

  • 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

Búfer y memoria virtual

  • Acceso directo a memoria (DMA)
    • Acceso directo a la memoria: DMA permite la transferencia directa de datos IO entre dispositivos periféricos y almacenamiento de memoria, y el proceso no requiere la participación de la CPU

  • El búfer es la base de todas las E / S, y la E / S no es más que mover datos dentro o fuera del búfer
    • El proceso inicia una solicitud de lectura y el kernel primero verifica si los datos que necesita el proceso existen en el búfer de espacio del kernel y, si ya existe, copia directamente los datos en el área de memoria del proceso. De lo contrario, el sistema solicita datos del disco, escribe el área del búfer de lectura del kernel a través de DMA y luego copia los datos del búfer del kernel en el área de memoria del proceso.
    • Cuando el proceso inicia una solicitud de escritura, copia los datos en el área de memoria del proceso al búfer de escritura del kernel y luego descarga los datos del búfer del kernel al disco o tarjeta de red a través de DMA
  • Memoria virtual: todos los sistemas operativos modernos utilizan memoria virtual, que tiene los siguientes dos beneficios
    • Más de una dirección virtual puede apuntar a la misma dirección de memoria física
    • El espacio de memoria virtual puede ser mayor que la dirección física real disponible
  • Con la primera función, la dirección del espacio del kernel y la dirección virtual del espacio del usuario se pueden asignar a la misma dirección física, de modo que DMA pueda llenar (leer y escribir) el búfer que es visible para los procesos del kernel y del espacio del usuario al mismo tiempo; aproximadamente de la siguiente manera

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.

Hay cuatro cambios de contexto entre el espacio de usuario y el espacio del kernel. Cuatro copias de datos, dos copias de datos de la CPU, dos copias de datos DMA

Copia cero realizada por mmap + write

#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

La E / S de copia cero implementada por mmap realizó cuatro cambios de contexto entre el espacio del usuario y el espacio del kernel, y tres copias de datos; las tres copias de datos incluyeron dos copias DMA y una copia de CPU

Copia cero implementada 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

La E / S de copia cero implementada por sendfile 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

Copia cero realizada por sendfile con función de copia de colección 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 para leer 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

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.

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 map 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 intermedia 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());
    }
}

Supongo que te gusta

Origin blog.csdn.net/GYHYCX/article/details/109323153
Recomendado
Clasificación