GNU/Linux >> LINUX-Kenntnisse >  >> Linux

dd:Wie berechnet man die optimale Blockgröße?

Ich habe festgestellt, dass meine optimale Blockgröße 8 MB beträgt (entspricht dem Festplatten-Cache?). Ich musste den leeren Speicherplatz auf einer Festplatte löschen (manche sagen:waschen), bevor ich ein komprimiertes Image davon erstellte. Ich verwendete:

cd /media/DiskToWash/
dd if=/dev/zero of=zero bs=8M; rm zero

Ich habe mit Werten von 4K bis 100M experimentiert.

Nachdem ich dd eine Weile laufen ließ, beendete ich es (Strg+C) und las die Ausgabe:

36+0 records in
36+0 records out
301989888 bytes (302 MB) copied, 15.8341 s, 19.1 MB/s

Da dd die Input/Output-Rate anzeigt (in diesem Fall 19,1 MB/s), ist es leicht zu erkennen, ob der von Ihnen gewählte Wert besser oder schlechter als der vorherige abschneidet.

Meine Ergebnisse:

bs=   I/O rate
---------------
4K    13.5 MB/s
64K   18.3 MB/s
8M    19.1 MB/s <--- winner!
10M   19.0 MB/s
20M   18.6 MB/s
100M  18.6 MB/s   

Hinweis:Um zu überprüfen, wie groß Ihr Festplatten-Cache/Puffer ist, können Sie sudo hdparm -i /dev/sda verwenden


Wie andere gesagt haben, gibt es keine allgemein korrekte Blockgröße; Was für eine Situation optimal ist, oder ein Hardwareteil kann für eine andere schrecklich ineffizient sein. Abhängig vom Zustand der Festplatten kann es auch vorzuziehen sein, eine andere Blockgröße als die "optimale" zu verwenden.

Eine Sache, die auf moderner Hardware ziemlich zuverlässig ist, ist, dass die Standard-Blockgröße von 512 Bytes dazu neigt, fast eine Größenordnung langsamer zu sein als eine optimalere Alternative. Im Zweifelsfall habe ich festgestellt, dass 64K ein ziemlich solider moderner Standard ist. Obwohl 64K normalerweise nicht DIE optimale Blockgröße ist, ist sie meiner Erfahrung nach viel effizienter als der Standardwert. 64K hat auch eine ziemlich solide Geschichte der zuverlässigen Leistung:Sie finden hier eine Nachricht von der Eug-Lug-Mailingliste, circa 2002, die eine Blockgröße von 64K empfiehlt:http://www.mail-archive.com/example@ unixlinux.online/msg12073.html

Um DIE optimale Ausgabeblockgröße zu bestimmen, habe ich das folgende Skript geschrieben, das das Schreiben einer 128 MB großen Testdatei mit dd bei einer Reihe unterschiedlicher Blockgrößen testet, von der Standardeinstellung von 512 Byte bis zu einem Maximum von 64 MB. Seien Sie gewarnt, dieses Skript verwendet intern dd, verwenden Sie es also mit Vorsicht.

dd_obs_test.sh:

#!/bin/bash

# Since we're dealing with dd, abort if any errors occur
set -e

TEST_FILE=${1:-dd_obs_testfile}
TEST_FILE_EXISTS=0
if [ -e "$TEST_FILE" ]; then TEST_FILE_EXISTS=1; fi
TEST_FILE_SIZE=134217728

if [ $EUID -ne 0 ]; then
  echo "NOTE: Kernel cache will not be cleared between tests without sudo. This will likely cause inaccurate results." 1>&2
fi

# Header
PRINTF_FORMAT="%8s : %s\n"
printf "$PRINTF_FORMAT" 'block size' 'transfer rate'

# Block sizes of 512b 1K 2K 4K 8K 16K 32K 64K 128K 256K 512K 1M 2M 4M 8M 16M 32M 64M
for BLOCK_SIZE in 512 1024 2048 4096 8192 16384 32768 65536 131072 262144 524288 1048576 2097152 4194304 8388608 16777216 33554432 67108864
do
  # Calculate number of segments required to copy
  COUNT=$(($TEST_FILE_SIZE / $BLOCK_SIZE))

  if [ $COUNT -le 0 ]; then
    echo "Block size of $BLOCK_SIZE estimated to require $COUNT blocks, aborting further tests."
    break
  fi

  # Clear kernel cache to ensure more accurate test
  [ $EUID -eq 0 ] && [ -e /proc/sys/vm/drop_caches ] && echo 3 > /proc/sys/vm/drop_caches

  # Create a test file with the specified block size
  DD_RESULT=$(dd if=/dev/zero of=$TEST_FILE bs=$BLOCK_SIZE count=$COUNT conv=fsync 2>&1 1>/dev/null)

  # Extract the transfer rate from dd's STDERR output
  TRANSFER_RATE=$(echo $DD_RESULT | \grep --only-matching -E '[0-9.]+ ([MGk]?B|bytes)/s(ec)?')

  # Clean up the test file if we created one
  if [ $TEST_FILE_EXISTS -ne 0 ]; then rm $TEST_FILE; fi

  # Output the result
  printf "$PRINTF_FORMAT" "$BLOCK_SIZE" "$TRANSFER_RATE"
done

Auf GitHub ansehen

Ich habe dieses Skript nur auf einem Debian (Ubuntu)-System und auf OSX Yosemite getestet, daher wird es wahrscheinlich einige Anpassungen erfordern, damit es auf anderen Unix-Varianten funktioniert.

Standardmäßig erstellt der Befehl eine Testdatei namens dd_obs_testfile im aktuellen Verzeichnis. Alternativ können Sie einen Pfad zu einer benutzerdefinierten Testdatei angeben, indem Sie nach dem Skriptnamen einen Pfad angeben:

$ ./dd_obs_test.sh /path/to/disk/test_file

Die Ausgabe des Skripts ist eine Liste der getesteten Blockgrößen und ihrer jeweiligen Übertragungsraten wie folgt:

$ ./dd_obs_test.sh
block size : transfer rate
       512 : 11.3 MB/s
      1024 : 22.1 MB/s
      2048 : 42.3 MB/s
      4096 : 75.2 MB/s
      8192 : 90.7 MB/s
     16384 : 101 MB/s
     32768 : 104 MB/s
     65536 : 108 MB/s
    131072 : 113 MB/s
    262144 : 112 MB/s
    524288 : 133 MB/s
   1048576 : 125 MB/s
   2097152 : 113 MB/s
   4194304 : 106 MB/s
   8388608 : 107 MB/s
  16777216 : 110 MB/s
  33554432 : 119 MB/s
  67108864 : 134 MB/s

(Hinweis:Die Einheit der Übertragungsraten variiert je nach Betriebssystem)

Um die optimale Leseblockgröße zu testen, könnten Sie mehr oder weniger denselben Prozess verwenden, aber anstatt von /dev/zero zu lesen und auf die Festplatte zu schreiben, würden Sie von der Festplatte lesen und nach /dev/null schreiben. Ein Skript dafür könnte so aussehen:

dd_ibs_test.sh:

#!/bin/bash

# Since we're dealing with dd, abort if any errors occur
set -e

TEST_FILE=${1:-dd_ibs_testfile}
if [ -e "$TEST_FILE" ]; then TEST_FILE_EXISTS=$?; fi
TEST_FILE_SIZE=134217728

# Exit if file exists
if [ -e $TEST_FILE ]; then
  echo "Test file $TEST_FILE exists, aborting."
  exit 1
fi
TEST_FILE_EXISTS=1

if [ $EUID -ne 0 ]; then
  echo "NOTE: Kernel cache will not be cleared between tests without sudo. This will likely cause inaccurate results." 1>&2
fi

# Create test file
echo 'Generating test file...'
BLOCK_SIZE=65536
COUNT=$(($TEST_FILE_SIZE / $BLOCK_SIZE))
dd if=/dev/urandom of=$TEST_FILE bs=$BLOCK_SIZE count=$COUNT conv=fsync > /dev/null 2>&1

# Header
PRINTF_FORMAT="%8s : %s\n"
printf "$PRINTF_FORMAT" 'block size' 'transfer rate'

# Block sizes of 512b 1K 2K 4K 8K 16K 32K 64K 128K 256K 512K 1M 2M 4M 8M 16M 32M 64M
for BLOCK_SIZE in 512 1024 2048 4096 8192 16384 32768 65536 131072 262144 524288 1048576 2097152 4194304 8388608 16777216 33554432 67108864
do
  # Clear kernel cache to ensure more accurate test
  [ $EUID -eq 0 ] && [ -e /proc/sys/vm/drop_caches ] && echo 3 > /proc/sys/vm/drop_caches

  # Read test file out to /dev/null with specified block size
  DD_RESULT=$(dd if=$TEST_FILE of=/dev/null bs=$BLOCK_SIZE 2>&1 1>/dev/null)

  # Extract transfer rate
  TRANSFER_RATE=$(echo $DD_RESULT | \grep --only-matching -E '[0-9.]+ ([MGk]?B|bytes)/s(ec)?')

  printf "$PRINTF_FORMAT" "$BLOCK_SIZE" "$TRANSFER_RATE"
done

# Clean up the test file if we created one
if [ $TEST_FILE_EXISTS -ne 0 ]; then rm $TEST_FILE; fi

Auf GitHub ansehen

Ein wichtiger Unterschied besteht in diesem Fall darin, dass die Testdatei eine Datei ist, die vom Skript geschrieben wird. Richten Sie diesen Befehl nicht auf eine vorhandene Datei, sonst wird die vorhandene Datei mit Nullen überschrieben!

Für meine spezielle Hardware fand ich heraus, dass 128 KB die optimalste Eingangsblockgröße auf einer Festplatte und 32 KB die optimalste auf einer SSD war.

Obwohl diese Antwort die meisten meiner Erkenntnisse abdeckt, bin ich oft genug auf diese Situation gestoßen, dass ich einen Blog-Beitrag darüber geschrieben habe:http://blog.tdg5.com/tuning-dd-block-size/ Sie können weitere Einzelheiten finden auf die Tests, die ich dort durchgeführt habe.


Dies ist völlig systemabhängig. Sie sollten experimentieren, um die optimale Lösung zu finden. Beginnen Sie mit bs=8388608 . (Da Hitachi HDDs 8 MB Cache zu haben scheinen.)


Die optimale Blockgröße hängt von verschiedenen Faktoren ab, einschließlich des Betriebssystems (und seiner Version) und der verschiedenen beteiligten Hardwarebusse und Festplatten. Mehrere Unix-ähnliche Systeme (einschließlich Linux und zumindest einige Varianten von BSD) definieren den st_blksize Mitglied im struct stat das gibt an, was der Kernel für die optimale Blockgröße hält:

#include <sys/stat.h>
#include <stdio.h>

int main(void)
{
    struct stat stats;

    if (!stat("/", &stats))
    {
        printf("%u\n", stats.st_blksize);
    }
}

Der beste Weg kann sein, zu experimentieren:Kopieren Sie ein Gigabyte mit verschiedenen Blockgrößen und die Zeit dafür. (Denken Sie daran, die Kernel-Puffer-Caches vor jedem Lauf zu löschen:echo 3 > /proc/sys/vm/drop_caches ).

Als Faustregel habe ich jedoch herausgefunden, dass eine ausreichend große Blockgröße dd zulässt leisten gute Arbeit, und die Unterschiede zwischen beispielsweise 64 KiB und 1 MiB sind gering, verglichen mit 4 KiB gegenüber 64 KiB. (Obwohl es zugegebenermaßen eine Weile her ist, seit ich das getan habe. Ich verwende jetzt standardmäßig ein Mebibyte oder lasse einfach dd Wählen Sie die Größe aus.)


Linux
  1. So erstellen Sie einen virtuellen Nginx-Host (Serverblock)

  2. Vimrc – Wie blockiert man Kommentare?

  3. Linux – Kann die Bitrate auf dem WLAN-Adapter nicht ändern?

  4. So richten Sie den GeoIP-Block mit Apache ein

  5. Wie kann ich eine MD5-Prüfsumme eines Verzeichnisses berechnen?

So blockieren Sie einen Port mit einer Firewall in Linux

So blockieren Sie XML-RPC in WordPress mit Nginx/Apache

So blockieren Sie SSH-Brute-Force-Angriffe mit SSHGUARD

Wie blockiere ich eine IP-Adresse mit .htaccess?

So blockieren oder entsperren Sie PING-Anfragen in Ubuntu

So verschlüsseln Sie Blockgeräte mit LUKS unter Linux