Investigación sobre el fenómeno de la amplificación de escritura Direct IO

Inserte la descripción de la imagen aquíEste trabajo está licenciado bajo el Acuerdo de Licencia Internacional de Atribución-Uso No Comercial-Compartir 4.0 de Creative Commons de la misma manera .
Inserte la descripción de la imagen aquíEste trabajo ( Lizhao Long Bowen por la creación de Li Zhaolong ) por la confirmación de Li Zhaolong , por favor indique los derechos de autor.

Introducción

Esta pregunta apareció del lado de Ali. Para ser honesto, cuando hice esta pregunta, supe que era un maestro en el teléfono. Como era de esperar, no respondí esta pregunta. De hecho, si hay un recordatorio, puede haber una posibilidad. Es realmente un poco problemático adivinar el significado de los sustantivos que no se han visto.

Después de algunas consultas de datos, el llamado fenómeno de amplificación de escritura del entrevistador debe decirse que el número real de IO realizadas por el sistema operativo es mayor que el número de IO realizadas por el modo de usuario. En realidad, esto se debe a la organización del sistema de archivos en el disco. df -TPuede usarlo para ver el formato del sistema de archivos en el sistema actual, generalmente hay ext4más en Linux .

sistema de archivos ext4

Inserte la descripción de la imagen aquí

Inserte la descripción de la imagen aquí

La figura anterior es el diagrama de arquitectura básica del sistema de archivos ext4.

Puede ingresar para dfver cada sistema de archivos en la máquina, y luego llamar para dumpe2fs -h /dev/sda10 | grep nodever y inodelos datos relacionados, llamar para tune2fs -l /dev/sda10 | grep "Block size"ver el tamaño del bloque, por supuesto, el nombre del disco duro se reemplaza según las diferentes máquinas.

Para más detalles, consulte [4], pero estas dos imágenes son suficientes para permitirnos comprender el proceso arquitectónico general de ext4.

Pero en este momento debemos ser muy conscientes de que si desea encontrar los datos en un inodo en particular, especialmente los datos con un desplazamiento grande, parece que no puede encontrarlos una vez y debe ingresar al disco varias veces. Una operación de E / S en modo de usuario puede provocar que el sistema operativo realice varias operaciones de E / S.

En cuanto a la conversión entre bloques físicos de disco a bloques lógicos, consulte [9], y los documentos ext4 pueden hacer referencia a [10].

Reaparición de la amplificación de escritura

Intentemos reproducir este proceso, primero generando varios archivos grandes. Luego, cada vez que se lee el desplazamiento, la caché se actualiza cada vez al mismo tiempo. El código simple es el siguiente:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

#include <string>
#include <vector>
#include <iostream>
using std::string;
using std::vector;

int main(){
    
    
    int FileName = 0;
    vector<int> arr;
    arr.reserve(500);

    constexpr int len = 1024*1024*1024;

	// 硬盘上没空间了,所以只生成了10个文件,想要结果更准确且机器允许的话可以生成500个向上。
    for (size_t i = 0; i < 10; i++){
    
    
        int fd = open(std::to_string(i).c_str(), O_RDWR | O_CREAT | O_DIRECT, 0755);
        arr.push_back(fd);
        char *buf;
        size_t buf_size = len;
        posix_memalign((void **)&buf, getpagesize(), buf_size);
        int ret = write(fd, buf, len);
        if(ret != len){
    
    
            std::cerr << "Partially written!\n";
        }
    }

    for(auto x : arr){
    
    
        close(x);
    }
    return  0;
}

Al leer estos diez archivos en un bucle, sincronizar cada vez, para simular varios archivos grandes, la máquina está en una vida terrible.

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

#include <string>
#include <vector>
#include <iostream>
using std::string;
using std::vector;

int main(){
    
    
    vector<int> arr;
    arr.reserve(500);

    constexpr int len = 1024;

    for (size_t i = 0; i < 10; i++){
    
    
        int fd = open(std::to_string(i).c_str(), O_RDONLY | O_DIRECT, 0755);
        std::cout << fd << std::endl;
        arr.push_back(fd);
    }

    for (size_t i = 0; i < 1000; i++){
    
    
        int index = i%10;
        lseek(arr[index], 1024*1024*512, SEEK_SET); // 转移偏移量
        char* buf;
        posix_memalign((void**)&buf, getpagesize(), 1025);
        std::cout << arr[index] << std::endl;
        size_t buf_size = len;
        int ret = read(arr[index], buf, buf_size);
        if(ret != buf_size){
    
    
            free(buf);
            std::cerr << "Partially written!\n";
            continue;
        }
        free(buf);
        sync();
    }
    

    for(auto x : arr){
    
    
        close(x);
    }
    return  0;
}

En primer lugar, puede ver en el código que hemos realizado 1000 operaciones de E / S en modo de usuario, y la cantidad total de datos leídos es de 1000 KB.

Se puede llamar cuando se ejecuta el código iostat -d 1. La función es ejecutar iostat cada segundo. Si desea especificar el operando, agregue el límite superior a la ejecución. Si no lo agrega antes, no hay límite superior para el número de ejecuciones.
Inserte la descripción de la imagen aquí
Podemos ver que el sistema operativo ha ejecutado aproximadamente 2500 IO, y la cantidad total de datos es de aproximadamente 4000 KB.

Cambiamos Direct IO al proceso normal de IO, es decir, O_DIRECTeliminamos los parámetros en abierto y luego cambiamos la asignación de memoria para malloccontinuar monitoreando IO: el
Inserte la descripción de la imagen aquí
número de IO es 1200, pero es obvio que la cantidad de datos leídos se ha vuelto mucho más pequeño. Eso es 40 KB, diez archivos, y luego considere lo anterior 4 veces. Obviamente, hay alguna relación entre ellos. Personalmente creo que es así. Ya hemos visto la estructura de organización de ext4 arriba. Cuando el bloque es de 4096 bytes Para guardar un archivo G se requiere un índice indirecto doble para guardar, lo que significa que, en comparación con la E / S directa, requiere dos E / S adicionales. Además, el inodo debe encontrarse en el disco al principio y los datos deben leerse en el bloque de datos al final.

En cuanto a por qué tps sigue siendo 1000, porque no lo eliminé sync. Esta es también la razón por la que la cantidad de bytes escritos es muy grande. Si se elimina sync, debido a que los datos del archivo aún existen page cache, se puede esperar que los datos leídos sean relativamente pequeño, y tps también será menor que el precio.

Inserte la descripción de la imagen aquí

En línea con las expectativas.

para resumir

Después de la exploración anterior y el estudio de [3] este artículo, básicamente podemos localizar la causa del fenómeno de amplificación de escritura en Direct IO a la realización del sistema de archivos , porque cada vez que Direct IO es un archivo diferente, significa que necesitamos para realizar varias operaciones de E / S adicionales para obtener la ubicación de almacenamiento real de los datos. Aunque los datos se almacenan en caché, no se utilizarán la próxima vez, lo que conduce a un aumento significativo en el número de E / S adicionales. En el archivo de tamaño 1G de ext4, ya es 4 veces este terrible número.

Por supuesto, un resumen más detallado son los últimos tres puntos en [3], para evitar que se pierda el texto original, regístrelo aquí:

  1. El método de índice de archivo adoptado por ext3 generará IO adicionales cuando el desplazamiento de lectura sea grande y cuanto mayor sea el desplazamiento, más IO adicionales;
  2. Linux usa la caché del búfer para almacenar en caché el bloque de índice de ext3 Para encontrar la ubicación del bloque de datos, primero se busca el bloque de índice en la caché y el bloque de índice se lee del disco si falla la caché;
  3. El número de solicitudes de E / S emitidas por el kernel de Linux durante DirectIO está realmente relacionado con los siguientes factores: a) La continuidad de los bloques lógicos en el disco físico; b) Granularidad de alineación del búfer de la aplicación, intente alinearse con PAGE_SIZE en la programación.

De hecho, también se puede ver que Direct IO es más apropiado en los dos casos, en los extremos de lectura y escritura respectivamente.

Al escribir, los datos deben colocarse en el disco de inmediato para evitar la pérdida de datos de la memoria durante un corte de energía. Hemos descubierto que la razón del fenómeno de amplificación de escritura radica en la implementación del caché y el sistema de archivos, por lo que no es necesario preocuparse demasiado por escenarios como WAL, porque el índice del disco está en Se ha almacenado en caché por primera vez, y la operación posterior es solo una E / S (en comparación con la escritura por lotes, por supuesto, la eficiencia es relativamente baja).

Cuando leer es para determinar que el acceso a los datos no sigue la localidad, por supuesto fadviseque también hizo tal cosa.

Es posible que la conclusión no sea correcta, indíquelo si encuentra un error.

referencia:

  1. Un artículo para comprender el directorio del sistema de archivos Ext4
  2. Habla de Linux IO de nuevo
  3. Investigación sobre amplificación IO en DirectIO
  4. Introducción al mecanismo de gestión del sistema de archivos ext4
  5. Iostat detallado
  6. Ejemplo de lectura de archivos en modo O_DIRECT
  7. DirectIO (O_DIRECT) detallado
  8. Uso de / proc / sys / vm / drop_caches
  9. ext2_get_branch resuelve el proceso de asignación de espacio en disco al modo de usuario
  10. Disposición del disco Ext4
  11. hombre fadvise

Supongo que te gusta

Origin blog.csdn.net/weixin_43705457/article/details/115118406
Recomendado
Clasificación