Eine Ramdisk unter Linux erstellen und verwenden

Eine Ramdisk erstellen

Hier beschreibe ich wie man unter den gängigen Linux Distributionen eine Ramdisk erstellt. Das kann an vielen Stellen ganz nützlich sein.

Was ist eine Ramdisk?

Eine Ramdisk ist ein Teil des flüchtigen Arbeitsspeichers (RAM –> Random Access Memory), auf welchen man wie auf eine Festplatte zugreift. Großer Vorteil der Ramdisk ist, das diese erheblich schneller ist als eine Festplatte. Während man von modernen Festplatten bis ca. 150 MB/s lesen kann, kann dies bei einer Ramdisk leicht mit über 1 GB/s passieren. Großer Nachteil an einer Ramdisk ist, das der Inhalt in einem flüchtigen Speicher liegt und bei jedem Reboot oder bei jedem abschalten der Maschine verloren geht. D.h. die Ramdisk muss bei jedem starten neu „beladen“ werden bzw. durch temporären Inhalt versorgt werden.

Wie erstellt man eine Ramdisk

Ein Ramdisk kann man heute unter jeder aktuellen Linux Distribution erstellen. Der Support für Ramdisks ist im Kernel integriert. Ich beschreibe hier alle Schritte die nötig sind um eine Ramdisk zu erstellen und diese als „Plattenersatz“ zu verwenden.

Kerneloptionen konfigurieren

Zum Erstellen einer Ramdisk muss man dem Kernel eine Option mitgeben diese zu erstellen. Das tut man in der Regel in seinem Bootloader. Auf dem meisten gängigen Distributionen ist dies Grub. Die Konfigurationsdatei befindet sich bei den meisten Distributionen unter /boot/grub/menu.lst. In dieser ist der zu bootende Kernel aufgeführt und seine Parameter. Erkennen kann man das an dem vorgestelltem Wort kernel. Wir fügen an diese Zeile einfach den Parameter ramdisk_size=xxxxxx an, wobei xxxxxxx durch eine Anzahl 1024KB Blöcke ersetzt wird. D.h. wenn ich 10 Megabyte Ramdisk haben möchte setze ich den Wert auf 10 * 1024 = 10240. Damit erhalte ich eine 10 MB Ramdisk. 300 MB Ramdisk sind dann entsprechend 307200. Ein Beispiel einer Ramdisk mit 976,5625 MB .

# grub.conf generated by anaconda
#
# Note that you do not have to rerun grub after making changes to this file
# NOTICE:  You have a /boot partition.  This means that
#          all kernel and initrd paths are relative to /boot/, eg.
#          root (hd0,0)
#          kernel /vmlinuz-version ro root=/dev/sda2
#          initrd /initrd-version.img
#boot=/dev/sda
default=0
timeout=5
splashimage=(hd0,0)/grub/splash.xpm.gz
hiddenmenu
title CentOS (2.6.18-53.1.21.el5)
        root (hd0,0)
        kernel /vmlinuz-2.6.18-53.1.21.el5 ro root=LABEL=/ ramdisk_size=1000000
        initrd /initrd-2.6.18-53.1.21.el5.img

Ist der Parameter hinzugefügt worden muss gebootet werden. Damit der Kernel die Option bei Starten auswerten kann. Im Anschluß an den boot Vorgang kann man sich mit dem Befehl dmesg das Log des Kernels anschauen und folgendes entdecken:

Diese Ausgabe kommt nicht bei jeder Distribution …

Kernel command line: ro root=LABEL=/ ramdisk_size=1000000

Diese Ausgabe sollte man aber immer sehen, die Zahlen beziehen sich auf das Beispiel mit der 976,5625 MB Ramdisk.

RAMDISK driver initialized: 16 RAM disks of 1000000K size 4096 blocksize

Das sagt uns das jetzt prinzipiell 16 RAM disks mit 1000000K große zur Verfügung stehen. Das ist ein bischen viel, weil 16 * 1000000 K = 15625 MB = 15.2587890625 GB. Zuviel für die meisten Rechner. Den Rechner den ich hier verwende hat auch nur 8 GB RAM. Also hätten wir ein Problem, da uns der RAM nicht reicht. Aber keine Angst, wir haben nun nur die Möglichkeit 16 Ramdisks in der größe verwendet, der Speicher wird erst dann verbraucht wenn wir diese auch tatsächlich nutzen. Ich benötige nur eine und hab damit noch genug ram frei.

Ramdisk nutzen

Nachdem wir nun erfolgreich die Ramdisk(s) initialisiert haben, können wir diese nun nutzen. Dazu müssen wir ein Dateisystem auf der Ramdisk erstellen, damit wir auch Dateien abspeichern können. Die Ramdisk steht uns unter einer Device Adresse zur Verfügung, ähnlich wie eine Festplatte. /dev/ram0 ist die erste Ramdisk in einem System /dev/ram1 die zweite und so weiter, in meinem Fall bis /dev/ram15, also die 16te Ramdisk. Ich brauche ja nur eine, nehme also die /dev/ram0. Auf dieser Ramdisk benötigen wir kein tolles Filesystem mit Journaling oder ähnlichem, da es sowieso bei jedem booten verloren geht. Also entscheide ich mich für das klassiche ext2 Dateisystem, dies ist recht ausgereift und auf ner Ramdisk ausreichend performant. Wir verwenden also folgenden Befehl: mkfs.ext2 -m /dev/ram0. Damit erstellen wir das Dateisystem auf dem Device /dev/ram0, die Option -m bewirkt das wir das Dateisystem im vollen Umfang nutzen können und kein Platz für den Benutzer root reserviert wird (weil das brauchen wir hier ja nicht). Und schon ist unsere Ramdisk fertig. Wir können Sie nun mounten und verwenden. mount /dev/ram0 /mnt.

Zu Beachten

  • Die Erzeugung des Filesystems und das mounten muss nach jedem reboot wiederholt werden. Ich verwende dafür ein init script, mann kann es natürlich auch anders machen.
  • Auch zu beachten ist, das man jetzt eine hochperformante Platte hat, von der Daten schnell gelesen und in die Daten schnell geschrieben werden können. Es kann durchaus dazu kommen, das Prozesse die zuvor an zu langsamen Platten gescheitert sind, nun plötzlich an nicht ausreichender Prozessorperformance scheitern, bzw. den Rechner enorm auslasten. Das muss man im Einzelfall testen.

Netcat

Netcat ist ein sehr nützliches Tool für viele Gelegenheiten. Ich persönlich benutze es meistens nur um den Durchsatz eines Netzwerkes zu testen wenn ich mir nicht sicher bin ob Performanceprobleme auf das Netwzerk, oder die Software zurückzuführen sind.

Dazu muss man auf dem Zielrechner netcat (oft auch nc) starten:

netcat -l <Port> > <Dateiname>

Und natürlich auf der sendenden Maschiene ein entsprechendes Netcat starten damit auf dem Zielhost empfangen werden kann:

netcat <Zieladresse> <Port> < <Dateiname>

Wenn man die Zeit des des Befehl auf der sendenden Maschine misst, kann man daraus den Durchsatz errechnen, dieser kommt meist nahe der praktischen Leistungsgrenzen der Netzwerkverbindung, da dort weder Kompression noch aufwändige Protokolle overhead erzeugen.

Backup mit Netcat

Weiterhin kann man ganz nette Backups mit Netcat machen. Z.b. ganze Partitionen, oder ganze Platten. Partitionen kann man hinterher schön mounten, deswegen finde ich das praktischer. Will man eine Partition mit netcat über das Netzwerk wegsichern, macht man folgendes:

Auf dem Quellrechner:

dd if=/dev/<partition> | netcat/nc <Zieladresse> <Port> 

Auf dem Zielrechner:

netcat/nc -l <Port> > <Dateiname>

Und schon hat man ein file in dem die Partion enthalten ist. Diese kann man nun ein bischen aufpeppen.

Backup mit Tricks

Will man das ganze noch ein bischen verfeineren, schribt man bevor man ein solches Backup macht erstmal den restlichen space mit „0“ voll. Das geht ganz einfach mit:

cd <Verzeichnis auf der Partition>
dd if=/dev/zero of=lala.txt

Das hat den Sinn, das der freie Platz mit nullen überschrieben wird und sich so besser komprimieren läßt.

Aufpassen muss man bei der root Partition, da muss man ein wenig Platz freilassen. Das kann man mit der Angabe bs=1m und count=<mb frei – 50>. So vermeidet man das das System unansprechbar wird.

Anschließend komprimieren wir die Ausgabe des dd durch folgende Angabe:

Quellrechner:

dd if=/dev/<Partition> | gzip -9 -c | netcat <Zieladresse> <Port>

Damit wird das ganze dann „on the fly“ komprimiert. Das kostet zwar CPU Zeit, spart aber viel Platz. Auf dem Zielsystem braucht man eigentlich nicht viel ändern, ich würde als Endung einfach .gz anfügen, damit man weiß das das Image komprimiert ist.