{"id":36,"date":"2013-07-07T20:46:30","date_gmt":"2013-07-07T18:46:30","guid":{"rendered":"http:\/\/www.theta-soft.de\/blog\/?p=36"},"modified":"2016-05-22T13:32:31","modified_gmt":"2016-05-22T11:32:31","slug":"lvm-snapshots","status":"publish","type":"post","link":"https:\/\/www.theta-soft.de\/blog\/2013\/lvm-snapshots\/","title":{"rendered":"LVM-Snapshots"},"content":{"rendered":"<h2>Grundlagen<\/h2>\n<p>LVM, der Linux Logical Volume Manager, bietet die M\u00f6glichkeit, von einzelnen logischen Laufwerken (Logical Volumes, LVs) einen sog.\u00a0<em>Snapshot<\/em> zu erzeugen. Ein Snapshot verh\u00e4lt sich wie eine unabh\u00e4ngige Kopie des urspr\u00fcnglichen Volume. Allerdings speichert der Snapshot nur die Ver\u00e4nderungen gegen\u00fcber dem Original, d.h. es wird potenziell erheblich weniger Platz ben\u00f6tigt. Tats\u00e4chlich kann die Gr\u00f6\u00dfe eines Snapshot-LV beliebig gew\u00e4hlt werden (unabh\u00e4ngig von der Gr\u00f6\u00dfe des Originals). Wenn allerdings der Platz im Snapshot nicht ausreicht, um alle Ver\u00e4nderungen aufzunehmen, wird der Snapshot ung\u00fcltig. Wenn man auf Nummer sicher gehen will, sollte daher der Snapshot die gleiche Gr\u00f6\u00dfe haben wie das Original.<\/p>\n<p>Technisch handelt es sich bei einem Snapshot um eine COW-Tabelle\u00a0<em>(copy on write)<\/em>. Das bedeutet: Jede Ver\u00e4nderung, die am Snapshot vorgenommen wird, wird in dieser Tabelle vermerkt, und das Original-Volume wird nicht ver\u00e4ndert. Wird hingegen in das Original-Volume geschrieben, so werden die urspr\u00fcnglichen Daten ebenfalls in die COW-Tabelle \u00fcbertragen. Somit ist die Ver\u00e4nderung am Original im Snapshot nicht sichtbar. Falls die gleichen Daten im Snapshot bereits fr\u00fcher ge\u00e4ndert worden sind (d.h. es existiert bereits ein Eintrag in der COW-Tabelle), so wird diese Ver\u00e4nderung nat\u00fcrlich nicht \u00fcberschrieben.<\/p>\n<h2>Der Device Mapper<\/h2>\n<p>Die Funktionalit\u00e4t von LVM wird gr\u00f6\u00dftenteils durch den\u00a0<em>Device Mapper<\/em> erledigt. Dieser kann virtuelle\u00a0Block Devices bereitstellen und sorgt daf\u00fcr, dass jeder Zugriff auf diese virtuellen Devices auf ein anderes darunter liegendes Device umgeleitet wird. Dabei gibt es verschiedene\u00a0<em>Targets<\/em>, d.h. Kernel-Module, die das eigentliche Mapping \u00fcbernehmen.<\/p>\n<p>Ein einfaches LV wird normalerweise \u00fcber das Target\u00a0<em>linear<\/em> realisiert. Dieses bildet einen zusammenh\u00e4ngenden Bereich des virtuellen Devices auf einen ebenfalls zusammenh\u00e4ngenden Bereich des darunter liegenden Devices ab. Ein Beispiel:<\/p>\n<pre>test:~ # lvcreate -l 2 -n base vg0\r\n Logical volume \"base\" created\r\ntest:~ # dir \/dev\/vg0\r\ntotal 0\r\nlrwxrwxrwx 1 root root 7 Jul 4 09:33 base -&gt; ..\/dm-0\r\ntest:~ # dir \/dev\/mapper\r\ntotal 0\r\ncrw------- 1 root root 10, 236 Jul 4 09:28 control\r\nlrwxrwxrwx 1 root root 7 Jul 4 09:33 vg0-base -&gt; ..\/dm-0\r\ntest:~ # dmsetup table vg0-base\r\n0 16384 linear 202:4 2048<\/pre>\n<p>Dabei ist das Ger\u00e4t 202,4 das physische Laufwerk <code>\/dev\/xvda4<\/code>, das zum Aufbau der Volume Group vg0 verwendet wurde:<\/p>\n<pre>test:~ # dir \/dev\/xvda*\r\nbrw-rw---- 1 root disk 202, 0 Jul 7 16:16 \/dev\/xvda\r\nbrw-rw---- 1 root disk 202, 1 Jul 7 16:16 \/dev\/xvda1\r\nbrw-rw---- 1 root disk 202, 2 Jul 7 16:16 \/dev\/xvda2\r\nbrw-rw---- 1 root disk 202, 3 Jul 7 16:16 \/dev\/xvda3\r\nbrw-rw---- 1 root disk 202, 4 Jul 7 16:16 \/dev\/xvda4<\/pre>\n<h2>Vorbereitung des Original-Volumes<\/h2>\n<p>F\u00fcr die sp\u00e4teren Tests wird das LV mit definiertem Inhalt gef\u00fcllt, z.B. mit dem Text &#8222;base&#8220;. Da die Volume Group eine\u00a0<em>Physical Extent Size<\/em> von 4 MB hat und das LV mit einer Gr\u00f6\u00dfe von 2 Extents angelegt wurde, betr\u00e4gt die Gr\u00f6\u00dfe 8 MB:<\/p>\n<pre>test:~ # lvdisplay \/dev\/vg0\/base | grep 'LV Size'\r\n LV Size 8.00 MiB<\/pre>\n<p>Zum F\u00fcllen wird der Befehl <code>dd<\/code>\u00a0verwendet:<\/p>\n<pre>test:~ # for i in $(seq 1 2097152); do \r\n&gt; echo -n base\r\n&gt; done | dd of=\/dev\/vg0\/base bs=4\r\n 2097152+0 records in\r\n 2097152+0 records out\r\n 8388608 bytes (8.4 MB) copied, 56.5065 s, 148 kB\/s<\/pre>\n<p>Um zu \u00fcberpr\u00fcfen, ob die Daten korrekt geschrieben worden sind, kann ebenfalls <code>dd<\/code>\u00a0verwendet werden:<\/p>\n<pre>test:~ # dd if=\/dev\/vg0\/base bs=1 count=32\r\n basebasebasebasebasebasebasebase<\/pre>\n<h2>Anlegen des Snapshot<\/h2>\n<p>Nun wird der Snapshot angelegt, und zwar mit einer Gr\u00f6\u00dfe von 1 Extent (4 MB):<\/p>\n<pre>test:~ # lvcreate -s \/dev\/vg0\/base -n snap -l 1\r\nLogical volume \"snap\" created<\/pre>\n<p>Im Verzeichnis <code>\/dev\/vg0<\/code>\u00a0sieht man anschlie\u00dfend den Snapshot als eigenes LV. Au\u00dferdem ist nat\u00fcrlich weiterhin das Original-Volume vorhanden:<\/p>\n<pre>test:~ # dir \/dev\/vg0\r\n total 0\r\n lrwxrwxrwx 1 root root 7 Jul 4 09:35 base -&gt; ..\/dm-0\r\n lrwxrwxrwx 1 root root 7 Jul 4 09:35 snap -&gt; ..\/dm-1<\/pre>\n<p>Deutlich interessanter ist jedoch der Blick in das Verzeichnis <code>\/dev\/mapper<\/code>. Hier sieht man, dass neben den beiden nach au\u00dfen sichtbaren Ger\u00e4ten (die man auch in <code>\/dev\/vg0<\/code>\u00a0findet) zwei weitere Ger\u00e4te angelegt worden sind, n\u00e4mlich <code>vg0-base-real<\/code>\u00a0und <code>vg0-snap-cow<\/code>:<\/p>\n<pre>test:~ # dir \/dev\/mapper\r\n total 0\r\n crw------- 1 root root 10, 236 Jul 4 09:28 control\r\n lrwxrwxrwx 1 root root 7 Jul 4 09:35 vg0-base -&gt; ..\/dm-0\r\n lrwxrwxrwx 1 root root 7 Jul 4 09:35 vg0-snap -&gt; ..\/dm-1\r\n lrwxrwxrwx 1 root root 7 Jul 4 09:35 vg0-snap-cow -&gt; ..\/dm-3\r\n lrwxrwxrwx 1 root root 7 Jul 4 09:35 vg0-base-real -&gt; ..\/dm-2<\/pre>\n<p>Ebenfalls interessant ist die Ausgabe von <em>dmsetup<\/em> f\u00fcr diese Ger\u00e4te:<\/p>\n<pre>test:~ # dmsetup table vg0-base\r\n0 16384 snapshot-origin 253:2\r\ntest:~ # dmsetup table vg0-base-real\r\n0 16384 linear 202:4 2048\r\ntest:~ # dmsetup table vg0-snap\r\n0 16384 snapshot 253:2 253:3 P 8\r\ntest:~ # dmsetup table vg0-snap-cow\r\n0 8192 linear 202:4 18432<\/pre>\n<p>Wie man sieht, ist durch den Snapshot eine weitere Mapping-Ebene hinzugekommen. Das bisherige Ger\u00e4t f\u00fcr das Original-LV (<code>vg0-base<\/code>) ist nicht l\u00e4nger vom Typ <em>linear<\/em>, sondern stattdessen vom Typ <em>snapshot-origin<\/em>. Dieser verweist auf das Ger\u00e4t <code>vg0-base-real<\/code>.\u00a0Das neu hinzugekommene Ger\u00e4t <code>vg0-snap<\/code>\u00a0ist vom Typ <em>snapshot<\/em>. Dieser verweist ebenfalls auf das Ger\u00e4t\u00a0<code>vg0-base-real<\/code>\u00a0sowie auf <code>vg0-snap-cow<\/code>. Diese beiden Ger\u00e4te wiederum verhalten sich wie &#8222;normale&#8220; LVs, d.h. sie verweisen auf einen Bereich des physischen Volumes.<\/p>\n<p><a href=\"http:\/\/www.theta-soft.de\/blog\/wp-content\/uploads\/2013\/07\/lvm-snapshots.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-medium wp-image-46\" src=\"http:\/\/www.theta-soft.de\/blog\/wp-content\/uploads\/2013\/07\/lvm-snapshots-300x214.png\" alt=\"lvm-snapshots\" width=\"300\" height=\"214\" srcset=\"https:\/\/www.theta-soft.de\/blog\/wp-content\/uploads\/2013\/07\/lvm-snapshots-300x214.png 300w, https:\/\/www.theta-soft.de\/blog\/wp-content\/uploads\/2013\/07\/lvm-snapshots.png 451w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p>Betrachtet man die Gr\u00f6\u00dfe der vier Block Devices, so sind die beiden Devices <code>vg0-base<\/code>\u00a0und <code>vg0-base-real<\/code>\u00a0nat\u00fcrlich jeweils 8 MB gro\u00df. <code>vg0-base-real<\/code>\u00a0ist ja das anfangs angelegte Original-Volume, und <code>vg0-base<\/code>\u00a0ist lediglich eine dar\u00fcber gelegte Mapping-Schicht. Auch das Device <code>vg0-snap<\/code>\u00a0ist (virtuell) 8 MB gro\u00df, da ein Snapshot immer die gleiche Gr\u00f6\u00dfe hat wie das darunter liegende Original-Volume. Die COW-Tabelle <code>vg0-snap-cow<\/code>\u00a0ist hingegen nur 4 MB gro\u00df, genau die Gr\u00f6\u00dfe, die beim Anlegen des Snapshot angegeben wurde.<\/p>\n<pre>test:~ # blockdev --getsize64 \/dev\/mapper\/vg0-base \/dev\/mapper\/vg0-snap \/dev\/mapper\/vg0-snap-cow \/dev\/mapper\/vg0-base-real\r\n 8388608\r\n 8388608\r\n 4194304\r\n 8388608<\/pre>\n<h2>Ver\u00e4nderungen am Snapshot<\/h2>\n<p>Was passiert, wenn der Snapshot mit Daten beschrieben wird?<\/p>\n<pre>test:~ # echo -n snapshot | dd of=\/dev\/vg0\/snap bs=1\r\n8+0 records in\r\n8+0 records out\r\n8 bytes (8 B) copied, 0.0341143 s, 0.2 kB\/s\r\n\r\ntest:~ # dd if=\/dev\/mapper\/vg0-snap bs=1 count=32\r\n<strong><span style=\"color: #ff0000;\">snapshot<\/span><\/strong>basebasebasebasebasebase\r\n\r\ntest:~ # dd if=\/dev\/mapper\/vg0-base bs=1 count=32\r\nbasebasebasebasebasebasebasebase<\/pre>\n<p>Erwartungsgem\u00e4\u00df sind die Daten im Snapshot ver\u00e4ndert worden, w\u00e4hrend das Original-Volume unver\u00e4ndert geblieben ist. Interessant ist der Blick auf die darunter liegenden Devices:<\/p>\n<pre>test:~ # dd if=\/dev\/mapper\/vg0-base-real bs=1 count=32\r\nbasebasebasebasebasebasebasebase\r\ntest:~ # dd if=\/dev\/mapper\/vg0-snap-cow | hexdump -C\r\n00000000  53 6e 41 70 01 00 00 00  01 00 00 00 08 00 00 00  |SnAp............|\r\n00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|\r\n*\r\n00001000  00 00 00 00 00 00 00 00  02 00 00 00 00 00 00 00  |................|\r\n00001010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|\r\n*\r\n00002000  73 6e 61 70 73 68 6f 74  62 61 73 65 62 61 73 65  |snapshotbasebase|\r\n00002010  62 61 73 65 62 61 73 65  62 61 73 65 62 61 73 65  |basebasebasebase|\r\n*\r\n00003000  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|\r\n*\r\n00400000<\/pre>\n<p>Die ver\u00e4nderten Daten sind in die COW-Tabelle geschrieben worden, w\u00e4hrend das Original-LV unver\u00e4ndert geblieben ist. Auff\u00e4llig ist, dass trotz der kleinen \u00c4nderung (4 Bytes) der in die COW-Tabelle geschriebene Block mit 4096 Bytes erheblich gr\u00f6\u00dfer ist. Die Gr\u00f6\u00dfe der pro \u00c4nderung geschriebenen Bl\u00f6cke ist die <em>Snapshot chunk size<\/em>, die bei der Anlage des Snapshot eingestellt werden kann. Aufgrund der Belegung der COW-Tabelle in Chunks\u00a0l\u00e4sst sich mit gleichm\u00e4\u00dfig \u00fcber den Snapshot verteilten kleinen \u00c4nderungen die COW-Tabelle f\u00fcllen, so dass der Snapshot ung\u00fcltig wird, obwohl die Gesamtmenge der ver\u00e4nderten Daten weit unterhalb der Gr\u00f6\u00dfe des Snapshot liegt.<\/p>\n<h2>Ver\u00e4nderungen am Original-Volume<\/h2>\n<p>Was passiert, wenn das Original-Volume ver\u00e4ndert wird?<\/p>\n<pre>test:~ # echo -n test | dd of=\/dev\/vg0\/base bs=1 seek=4096\r\n4+0 records in\r\n4+0 records out\r\n4 bytes (4 B) copied, 0.0174384 s, 0.2 kB\/s\r\n\r\ntest:~ # dd if=\/dev\/mapper\/vg0-base bs=1 count=32 skip=4096\r\n<strong><span style=\"color: #ff0000;\">test<\/span><\/strong>basebasebasebasebasebasebase\r\n\r\ntest:~ # dd if=\/dev\/mapper\/vg0-base-real bs=1 count=32 skip=4096\r\n<strong><span style=\"color: #ff0000;\">test<\/span><\/strong>basebasebasebasebasebasebase\r\n\r\ntest:~ # dd if=\/dev\/mapper\/vg0-snap-cow | hexdump -C\r\n00000000 53 6e 41 70 01 00 00 00 01 00 00 00 08 00 00 00 |SnAp............|\r\n00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|\r\n*\r\n00001000 00 00 00 00 00 00 00 00 02 00 00 00 00 00 00 00 |................|\r\n00001010 01 00 00 00 00 00 00 00 03 00 00 00 00 00 00 00 |................|\r\n00001020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|\r\n*\r\n00002000 73 6e 61 70 73 68 6f 74 62 61 73 65 62 61 73 65 |snapshotbasebase|\r\n00002010 62 61 73 65 62 61 73 65 62 61 73 65 62 61 73 65 |basebasebasebase|\r\n*\r\n<strong><span style=\"color: #ff0000;\">00004000<\/span><\/strong> 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|\r\n*\r\n00400000<\/pre>\n<p>Dass die beiden Ger\u00e4te vg0-base und vg0-base-real die Ver\u00e4nderung zeigen, ist nicht weiter \u00fcberraschend. Spannender ist die COW-Tabelle: Auf den ersten Blick sieht es so aus, als h\u00e4tte sich diese gar nicht ver\u00e4ndert. Tats\u00e4chlich ist jedoch ein weiterer 4k-Block hinzugekommen, in den die urspr\u00fcnglichen Daten (&#8222;&#8230;basebasebasebase&#8230;&#8220;) kopiert worden sind. Daher ist die Ver\u00e4nderung im Snapshot nicht sichtbar. Die Tatsache, dass die COW-Tabelle in 4k-Bl\u00f6cken belegt wird, ist \u00fcbrigens auch der Grund, warum beim Beschreiben mittels <code>seek=4096<\/code>\u00a0weiter hinten in das Volume geschrieben worden ist.<\/p>\n<h2>Quellen \/ Links<\/h2>\n<ul>\n<li><a href=\"http:\/\/www.tldp.org\/HOWTO\/LVM-HOWTO\/snapshotintro.html\">http:\/\/www.tldp.org\/HOWTO\/LVM-HOWTO\/snapshotintro.html<\/a><\/li>\n<li><a style=\"line-height: 1.714285714; font-size: 1rem;\" href=\"http:\/\/rwmj.wordpress.com\/2010\/09\/28\/how-lvm-does-snapshots\/\">http:\/\/rwmj.wordpress.com\/2010\/09\/28\/how-lvm-does-snapshots\/<\/a><\/li>\n<li><a href=\"http:\/\/www.centos.org\/docs\/5\/html\/5.2\/Cluster_Logical_Volume_Manager\/snapshot-map.html\">http:\/\/www.centos.org\/docs\/5\/html\/5.2\/Cluster_Logical_Volume_Manager\/snapshot-map.html<\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Grundlagen LVM, der Linux Logical Volume Manager, bietet die M\u00f6glichkeit, von einzelnen logischen Laufwerken (Logical Volumes, LVs) einen sog.\u00a0Snapshot zu erzeugen. Ein Snapshot verh\u00e4lt sich wie eine unabh\u00e4ngige Kopie des urspr\u00fcnglichen Volume. Allerdings speichert der Snapshot nur die Ver\u00e4nderungen gegen\u00fcber dem Original, d.h. es wird potenziell erheblich weniger Platz ben\u00f6tigt. Tats\u00e4chlich kann die Gr\u00f6\u00dfe eines [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":"","_members_access_role":[],"_members_access_error":""},"categories":[1],"tags":[4,2,3],"class_list":["post-36","post","type-post","status-publish","format-standard","hentry","category-allgemein","tag-linux","tag-lvm","tag-snapshot"],"_links":{"self":[{"href":"https:\/\/www.theta-soft.de\/blog\/wp-json\/wp\/v2\/posts\/36","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.theta-soft.de\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.theta-soft.de\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.theta-soft.de\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.theta-soft.de\/blog\/wp-json\/wp\/v2\/comments?post=36"}],"version-history":[{"count":23,"href":"https:\/\/www.theta-soft.de\/blog\/wp-json\/wp\/v2\/posts\/36\/revisions"}],"predecessor-version":[{"id":114,"href":"https:\/\/www.theta-soft.de\/blog\/wp-json\/wp\/v2\/posts\/36\/revisions\/114"}],"wp:attachment":[{"href":"https:\/\/www.theta-soft.de\/blog\/wp-json\/wp\/v2\/media?parent=36"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.theta-soft.de\/blog\/wp-json\/wp\/v2\/categories?post=36"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.theta-soft.de\/blog\/wp-json\/wp\/v2\/tags?post=36"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}