Otra mirada a la pregunta "¿Necesito desfragmentación para SSD"

Sin lugar a dudas, la pregunta planteada en el título del artículo no es nueva, se ha planteado más de una vez y se ha llegado a un consenso al respecto "no es realmente necesario e incluso puede ser perjudicial".
Sin embargo, la discusión reciente en los comentarios me hizo pensar de nuevo.


Con el tiempo, cualquier SSD seguirá fragmentándose fuertemente (internamente, en FTL) ... Una SSD recién grabada con lectura lineal dará una alta velocidad, pero si ya ha funcionado, será mucho más baja, ya que será lineal solo para usted.

Sí, por lo general esto no debería suceder: o escribimos "poco a poco" en archivos pequeños / pequeños bloques de metainformación del FS (cuya velocidad de lectura lineal realmente no nos importa), o escribimos "mucho" en archivos grandes y todo estará bien. También sucede que agrega bloques pequeños a archivos grandes, por ejemplo, registros, pero son relativamente de corta duración y no veo ningún problema en particular aquí.
Pero fue fácil imaginar un escenario muy real, en el que puede ocurrir la misma fragmentación interna de la SSD: un archivo de base de datos en el que hay una grabación aleatoria bastante activa. Con el tiempo, (quedando sin fragmentar en el nivel del sistema operativo) estará físicamente muy fragmentado, lo que puede reducir significativamente la velocidad de exploración de secuencia, copia de seguridad, etc.


Para la verificación, escribí un script y ejecuté pruebas.


Spoiler: el problema está presente (afecta significativamente el rendimiento) en solo uno de los modelos que se presentaron (y el fabricante lo coloca no como un centro de datos, sino como una computadora de escritorio / portátil).


¿Que es todo esto? ¿Qué más fragmentación dentro del SSD?

, SSD . NAND flash ( ) . SSD 512- ( 4096-) , .
- , , FTL (flash translation layer): flash- , ( ) , , - log- .
, , , , — .


, FTL, , , , . , .
.


La idea del guión: creamos un archivo de varios gigabytes, lleno de datos aleatorios, medimos la velocidad de las lecturas secuenciales.
Luego, usando el acceso aleatorio, reescriba parte del archivo de prueba y vuelva a medir la velocidad de la lectura lineal. Si nuestras sospechas son ciertas, entonces la lectura del archivo será más lenta.
Después de cada escritura, hacemos tres operaciones de lectura con un retraso entre ellas en caso de que alguna unidad en segundo plano realice la desfragmentación y luego la velocidad de lectura mejore.


, SSD

, , - , , . - , , , , , .
TRIM: SSD «», , FTL. NAND flash, . , , . SSD , .


, , , .


, SSD ( linux /dev/urandom).


.


linux c dash, coreutils fio debian buster, , freebsd «».


echo preparing...
dd if=/dev/urandom of=testfile bs=1M count=4096 status=none
sync
for A in 1 2 3; do
    sleep 10
    dd if=testfile of=/dev/null bs=1M iflag=direct
done

for A in 50 200 800 4000; do
    echo fio: write ${A}M...
    fio --name=test1 --filename=testfile --bs=4k --iodepth=1 --numjobs=1  --rw=randwrite  --io_size=${A}M --randrepeat=0 --direct=1 --size=4096M > /dev/null
    sync

    for B in 1 2 3; do
        echo sleep ${B}0
        sleep ${B}0
        dd if=testfile of=/dev/null bs=1M iflag=direct
    done
done

echo sleep 3600
sleep 3600
dd if=testfile of=/dev/null bs=1M iflag=direct

, NVMe- intel windows; , stackexchange -


ps

fio; exe- .


$testfile = "c:\temp\testfile"
$fio = "c:\temp\fio-3.18-x64\fio"

echo "preparing..."

$filestream = New-Object System.IO.FileStream($testfile, "Create")
$binarywriter = New-Object System.IO.BinaryWriter($filestream)
$out = new-object byte[] 1048576

For ($i=1; $i -le 4096; $i++) {
    (new-object Random).NextBytes($out);
    $binarywriter.write($out)
}
$binarywriter.Close()

For ($i=1; $i -le 3; $i++) {
    sleep 10
    $time = Measure-Command {
        Invoke-Expression "$fio --name=test1 --filename=$testfile --bs=1M --iodepth=1 --numjobs=1  --rw=read --direct=1 --size=4096M" *>$null
    }

    $seconds = $time.Minutes*60+$time.Seconds+$time.Milliseconds/1000
    echo "read in $seconds"
}

foreach ($A in 50,200,800,4000) {
    echo "fio: write ${A}M..."
    Invoke-Expression "$fio --name=test1 --filename=$testfile --bs=4k --iodepth=1 --numjobs=1  --rw=randwrite  --io_size=${A}M --randrepeat=0 --direct=1 --size=4096M" *>$null
    For ($i=10; $i -le 30; $i+=10) {
        echo "sleep $i"
        sleep $i
        $time = Measure-Command {
            Invoke-Expression "$fio --name=test1 --filename=$testfile --bs=1M --iodepth=1 --numjobs=1  --rw=read --direct=1 --size=4096M" *>$null
        }

        $seconds = $time.Minutes*60+$time.Seconds+$time.Milliseconds/1000
        echo "read in $seconds"
    }
}

rm $testfile

:


  • : , «» ( ) , ;
  • windows - (, , , );
  • ( ) .

( ) 4 :


50+200+800+4000
intel S3510 SSDSC2BB480G610.710.710.810.810.8
toshiba XG5 KXG50ZNV512G1.92.93.74.86.8
samsung PM963 MZQLW960HMJP2.83.23.53.74.2
samsung PM983 MZQLB960HAJR3.33.63.43.43.4
samsung PM981 MZVLB1T0HALR1.81.82.12.53.5
samsung PM1725b MZPLL1T6HAJQ1.81.92.02.32.9
micron 5200 eco9.39.810.412.210.7
samsung PM883 MZ7LH1T9HMLT7.97.98.18.18.0
intel P3520 (win)5.85.96.06.15.8
intel P4500 (win)4.24.24.34.44.3

DC ( — /); SATA, NVMe, , .


, PM981 ( , , ), — 3.5 , SATA .
, , .


: SSD , , , ( intel, , ; samsung , ).


(, - NAND flash).
XG5: , SMART >>150, ­— 300-400 , flash , SSD.


: mysql 100. , , «» mysql ( 600/), (>2/).


SSD

, : , , . , downtime ( - ). , , .
( ) SSD:


sync
fsfreeze -f /mountpoint
dd  if=/dev/nvme0n1p2 of=/dev/nvme0n1p2 bs=512M iflag=direct oflag=direct status=progress
fsfreeze -u /mountpoint

«» . - , , , -. «»: 100%, SSD « , TRIM» ( , TRIM, , ).
, « » .


Resumen: la desfragmentación puede ser útil para algunos SSD, pero no es lo mismo (¿para nada?) Como para el HDD. Es importante para nosotros no solo que el archivo esté ubicado en una cadena continua de sectores, sino también que la grabación en estos sectores fue secuencial.


PD: Agradecería que los lectores ejecutaran el script en su lugar y dieran números para sus SSD, ya que mi selección de unidades es bastante unilateral.


All Articles