Střípky ze stavby centrálního úložiště

Úkládání dat a zajištění jejich bezpečnosti a dostupnosti je docela složitá disciplína a věnuje se jí hodně lidí. Existuje spousta řešení jak ukládat data – některá jsou levná, jiná drahá, některá spolehlivá a jiná zase nespolehlivá (přičemž spolehlivost a cena spolu velmi často vůbec, ale vůbec nesouvisí).

Před nějakou dobou jsme si přestali stačit s ukládáním dat na lokální disky a museli jsme řešit rozumné úložiště zajišťující dostupnost dat pro víc počítačů v provozu 24×7 bez možnosti větší odstávky. Rozpočet jsme měli omezený, požadavky relativně vysoké.

Požadavky na nové úložiště

Naše nároky na úložiště:

– odolnost proti výpadku HW, v případě selhání HW naštveme mooooc lidí a přijít o data si v žádném případě nemůžeme dovolit,
– rozumný výkon pro provoz virtuálních serverů a servírování dat pro aplikace v nich běžící (weby, maily a podobné úlohy, databáze jsou na vyhrazených serverech),
– možnost růstu – nechci skončit na tom, že nebude kam píchnout další disky,
– možnost upgrade bez výpadku služeb nebo jen s minimálním,
– známá technologie – nechceme blackbox o kterém nic nevíme,
– data budeme tlačit po ethernetu, NFS, iSCSI nebo AoE
– podporu od dodavatele HW,
– raw prostor min. 4TB
– cena do 300k Kč

S kolegy jsme pracovali pro distributora SUNu jako technici, takže víme jak to chodí s HW pro enterprise sféru. Věděli jsme tedy celkem přesně co nechceme – low-end řadu libovolného diskového pole. Low-end disková pole jsou většinou dost omezené záležitosti ve stylu „za hodně peněz málo muziky, hlavně když to má tu správnou samolepku“. Použitelná řešení od velkých výrobců HW (SUN, IBM, HP, NetApp) začínají zase na cenách mimo náš rozpočet :-(

Výběr skončil na řešení s využitím dvou serverů mezi kterými budou replikována data pomocí DRBD.

Architektura zvoleného řešení

Zvolená varianta nakonec dopadla následujícím způsobem. Pořídíme dva servery s dostatečnou diskovou kapacitou. Nainstalujeme na ně Linux, data budeme replikovat pomocí DRBD v režimu Primary-Secondary. Data budou vystavená přes NFS a iSCSI nebo AoE. Vysokou dostupnost zajistí heartbeat.

Výběr vhodného hardware

Hardware jsme vybrali od Supermicro, mají case, který umožňuje zastrkat až 24 hot-swap disků. V kombinaci s kvalitním RAIDem Areca 1680 s 2GiB cache zálohované baterkou máme dostatečně prostoru i výkonu. Uvedená RAID karta zvládne SATA i SAS, máme variantu s externím SAS portem, takže případné rozšíření až vyčerpáme všech 24 pozic pro disky je velmi snadné – připojíme externí box s disky a pokračujeme dál.

Pro DRBD je nutné zajistit aby byly oba servery stejně silné – nelze si říct, že na Secondary server použiju nějaký slabší (a hlavně levnější) stroj. Koupili jsme tedy oba servery v identické konfiguraci a se supportem na 3 roky, oprava další pracovní den po nahlášení. V případě výpadku jednoho serveru můžeme bez problémů fungovat na jeho dvojčeti.
K serverům jsme koupili i management rozhraní, které umožňuje po síti přes IPMI rozhraní i jejich vzdálený restart. To je velmi důležité – když se server sekne, tak aby mohl druhý fungující server převzít kontrolu, můsí mít možnost násilného restartu. Konfigurace tohoto mechanismu označovaného jako STONITH je popsaná v článku na STONITH – když se oba nody HA clusteru nedohodnout a musí se vzájemně sestřelit.

Instalace a konfigurace OS

Konfigurace sítě

Konfigurace síťe je relativně snadná, pokud si nepromícháte kabely při propojování :-)

Mezi servery doporučuji nepoužívat žádné další prvky – propojte je pěkně na přímo. Používáme tzv. „bonding“ kdy jsou spojené dvě síťové karty do jedné virtuální. Linux pak zajišťuje rozkládání zátěže mezi ně a v případě výpadku jedné z nich i převedení veškerého provozu na tu zbývající kartu.

Pro bonding jsem vybral dvě různé karty, jedna integrovaná na desce, druhá v PCIe slotu. Konfiguraci stačí zapsat do standardních konfiguračních souborů CentOSu a on už její nahození zajistí při každém startu sám.

Pro přímou komunikaci mezi servery používáme rozhraní bond0 a pro komunikaci s klienty bond1.

[root@node1 ~]# grep bond /etc/modprobe.conf
alias bond0 bonding
alias bond1 bonding
options bonding mode=balance-rr miimon=100

[root@node1 ~]# cat /etc/sysconfig/network-scripts/ifcfg-eth1
DEVICE=eth0
BOOTPROTO=none
HWADDR=00:30:48:B9:6B:50
ONBOOT=yes
TYPE=Ethernet
SLAVE=yes
MASTER=bond0
USERCTL=no

[root@node1 ~]# cat /etc/sysconfig/network-scripts/ifcfg-eth5
DEVICE=eth2
BOOTPROTO=none
HWADDR=00:30:48:9C:2C:80
ONBOOT=yes
TYPE=Ethernet
SLAVE=yes
MASTER=bond0
USERCTL=no

[root@node1 ~]# cat /etc/sysconfig/network-scripts/ifcfg-bond0
DEVICE=bond1
BOOTPROTO=none
ONBOOT=yes
USERCTL=no
IPADDR=172.16.1.100
NETMASK=255.255.255.0

Každý ze serverů má tedy rozhraní bond0 pro komunikaci s druhým serverem a oba stroje jsou propojené napřímo. Další rozhraní je bond1, které slouží pro servírování dat klientům a poslední rozhraní je libovolné volné připojené do management síťě aby bylo možné stroje spravovat. Do management síťe je také zapojené management rozhraní serverů a raid karet.

Při konfiguraci síťe také nezapomeňte na nastevení iptables. Při jejich konfiguraci upravuji soubor /etc/sysconfig/iptables a následně aktualizuji konfiguraci pomocí iptables-restore < /etc/sysconfig/iptables. Jakmile zkusíte použít „klikací“ nástroj system-config-security, tak vám konfiguraci iptables totálně rozseká a znefunkční (proto také na uvedený soubor nastavuji atribut „i“ – chattr +i …).

Jumbo Frames

Aby byla zajištěna maximální propustnost sítě, doporučuji začít používat tzv. Jumbo Frames. Výchozí velikost je 1500b, podle toho jaké máte síťové karty a switche po cestě doporučuji použít vyšší hodnoty. Náš switch bez problémů zvládne velikost rámce 16k, intelky síťovký zvládají 9k – nastavil jsem tedy pro všechny sítťovky velikost MTU 9000.

DRBD

Konfiguraci DRBD a jednu z možností řešení situace kdy se DRBD rozpadne jsem popsal v jiném článku na blogu:
Konfigurace DRBD a řešení situace „Split-Brain“
, pro pochopení způsobu konfigurace to snad stačí.

Konfigurace DRBD pro naše použití je trochu specifická – na svazcích exportovaných z HW RAIDu mám nasazené LVM. V něm vytvořené volumy a ty jsou použité jako zařízení pro DRBD. Mám takto udělané 3 DRDB zařízení (podle konkrétních diskových skupin kde každá je určená pro jiná data) a nad nimi je zase nasazené LVM a v něm vytvořené volumy na kterých je souborový systém.

O první úroveň LVM se stará přímo distribuce – nahazuje ho při startu CentOS standardními skripty. DRBD nahazuje heartbeat, po naběhnutí DRBD heartbeat nahodí druhou úroveň LVM, připojí souborový systém a začne startovat další služby (IP adresy, NFS, AoE). Heartbeat má nastavená pravidla tak aby nahazoval služby tam kde je DRBD ve stavu Primary. Nemůže se tedy stát, že by na node0 nahodil DRBD a připojil souborový systém a na node1 nahodil NFS.

Jestli se vám zdá zbytečné nasadit LVM pod i nad DRBD, tak napište proč to tak nemůže být :-) Mě připadá variabilita takového řešení docela dobrým důvodem – mohu stěhovat data kam chci a jak chci aniž by to klienti poznali a zvětšování prostoru také není úplně k zahození.

LVM na DRBD

Pokud budete chtít tak jako já nacpat LVM na DRBD svazek, je nutné to povolit v konfiguraci /etc/lvm/lvm.conf – v sekci devices jsem upravil:

preferred_names = [ "^/dev/drbd", "^/dev/sd", "^/dev/mapper/" ]
filter = [ "a|/dev/drbd.*|","a|/dev/sd.*|","r|.*|" ]

Heartbeat

Instalaci Heartbeatu a Pacemakeru zvládnete pravděpodobně sami, na Internetu je k nalezení docela dost návodů. Jeden z možných: http://www.clusterlabs.org/wiki/Install
Docela pěkný popis konfigurace je také k nalezení na webu Novellu o SLESu.

Servery jsem propojil přes RS232 abych měl zaručený paralelní komunikační kanál k síťovým kartám – pro cluster je to docela důležité. Poižitá konfigurace heartbeatu (/etc/ha.d/ha.cf):

use_logd off
logfile /var/log/ha.log
debugfile /var/log/ha.debug
keepalive 1
warntime 10
deadtime 30
initdead 120
udpport 694
bcast bond0
baud 19200
serial /dev/ttyS0
node node0.domain.tld
node node1.domain.tld
auto_failback on
crm respawn
apiauth         mgmtd   uid=root
respawn         root    /usr/lib64/heartbeat/mgmtd -v
respawn         root    /usr/lib64/heartbeat/hbagent

Zajímavé části konfigurace CRM:

DRBD

Nejdřív si v clusteru nadefinuji jednotlivé svazky DRBD:

primitive drbd0 ocf:heartbeat:drbd \
	params drbd_resource="r0" \
	op stop interval="0" timeout="180"
primitive drbd1 ocf:heartbeat:drbd \
	params drbd_resource="r1" \
	op stop interval="0" timeout="180"
primitive drbd2 ocf:heartbeat:drbd \
	params drbd_resource="r2" \
	op stop interval="0" timeout="180"

Chci aby všechny DRBD svazky nabíhaly do Primary stavu na stejném serveru, proto jsem je seskupil do grp_drbd. Svazky nahazuji najednou a pouze tak aby byl vždy jeden server ve stavu Master (~Primary pro DRBD, definice ms_drbd). Spouštím je na preferovaném uzlu clusteru (pravidlo loc-drbd). Protože je cluster symetrický a nastavený do režimu failover, bude v případě nedostupnosti tohoto uzlu (node1.domain.tld) použit uzel druhý.

group grp_drbd drbd0 drbd1 drbd2 \
  meta migration-threshold="2" failure-timeout="180s"

ms ms_drbd grp_drbd \
  params clone_max="2" clone_node_max="1" master_max="1" \
master_node_max="1" notify="yes" globally_unique="false" target_role="stopped" \
  meta target-role="Started"

location loc-drbd ms_drbd \
  rule $id="loc-drbd-rule" $role="Master" inf: #uname eq node1.domain.tld

Jak jsem psal, nad drbd je zase LVM, je třeba ho tedy také nadefinovat. V rámci zjednodušení následného zapisování pravidel případně rozšiřování konfigurace jsem všechny LVM svazky vsadil do jedné skupiny (grp_lvm).

primitive lvmdrbd0 ocf:heartbeat:LVM \
  params volgrpname="vgrep0" exclusive="truemeta" start="45" stop="45"
primitive lvmdrbd1 ocf:heartbeat:LVM \
  params volgrpname="vgrep1" exclusive="truemeta" start="45" stop="45"
primitive lvmdrbd2 ocf:heartbeat:LVM \
  params volgrpname="vgrep2" exclusive="truemeta" start="45" stop="45"

group grp_lvm lvmdrbd0 lvmdrbd1 lvmdrbd2 \
  meta target-role="Started"

Souborové systémy na tomto LVM je třeba také připojit, zase to musí obsloužit Heartbeat:

primitive fs1 ocf:heartbeat:Filesystem \
  params device="/dev/vgrep0/lv0" fstype="xfs" directory="/export/d0" options="noatime"
primitive fs2 ocf:heartbeat:Filesystem \
  params device="/dev/vgrep1/lv0" fstype="xfs" directory="/export/d1" options="noatime"
primitive fs3 ocf:heartbeat:Filesystem \
  params device="/dev/vgrep2/lv0" fstype="xfs" directory="/export/d2" options="noatime"
primitive fs4 ocf:heartbeat:Filesystem \
  params device="/dev/vgrep2/lv1" fstype="xfs" directory="/export/clust" options="noatime"

group grp_fs fs1 fs2 fs3 fs4 \
  meta target-role="Started"

Aby všechny služby startovaly na správné straně clusteru, tedy na té kde je DRBD ve stavu Primary, je třeba nadefinovat „colocation“ pravidla:

colocation grp_fs_on_grp_drbd inf: grp_fs ms_drbd:Master
colocation grp_lvm_on_grp_drbd inf: grp_lvm ms_drbd:Master
colocation grp_vps_on_grp_drbd inf: grp_vps ms_drbd:Master

Služby sice nastartují na správné straně, ale asi v nesprávném pořadí, proto ještě pořadí explicitně určím:

order ord_grp_fs_after_grp_lvm inf: grp_lvm:start grp_fs:start
order ord_grp_lvm_after_ms_drbd inf: ms_drbd:promote grp_lvm:start

Jak vidíte, pravidla popisující na které straně cluster nahodí služby a v jakém pořadí zapisuji již jen přes skupiny – je to tak přehlednější. Názvy těch pravidel se snažím volit co nejvíc popisné abych se v tom snadno orientoval, stejně jako v případě názvů skupin a služeb.

Export dat ke klientům

Ata over Ethernet – AoE

Na straně serveru je nutné nainstalovat vblade (teda nutné, existují i jiné aoe targety, ale vblade znám), který zajistí export dat. Exportovaná dat jsou obrazy disků pro XEN, tedy velké soubory.
Veškerá konfigurace vblade se zadává při startu, je tedy třeba jí zapsat do CRM. Pro spouštění je možné použít skript ocf:heartbeat:AoEtarget, ale ten neumožňuje zadání dalších příznaků, které jsou pro mě důležité, -d a -s. Umožňují totiž v novém vblade exportovat data s příznakem O_DIRECT a O_SYNC. Skript jsem tedy upravil a pojmenoval AoEtargetKl. Poslední verze vblade je důležitá – chová se stabilněji. Při provozu doporučuji věnovat trochu času čtení dokumentace a ladění sítě pro kombinaci vblade a Jumbo Frames.

primitive aoedomU1 ocf:heartbeat:AoEtargetKl \
  params binary="/usr/local/sbin/vblade" \
device="/export/d1/domU1.img" nic="bond1" shelf="11" slot="0" vbladeparams="-d -s"
primitive aoedomU2 ocf:heartbeat:AoEtargetKl \
  params binary="/usr/local/sbin/vblade" \
device="/export/d1/domU2.img" nic="bond1" shelf="12" slot="0" vbladeparams="-d -s"
group grp_aoe aoedomU1 aoedomU2
	meta target-role="Started"
colocation grp_aoe_on_grp_drbd inf: grp_aoe ms_drbd:Master
order ord_grp_aoe_after_grp_fs inf: grp_fs:start grp_aoe:start

Docela prima u AoE je, že na straně klienta se při spouštění (tedy modprobe aoe) dá zadat parametr jak dlouho má klient čekat na timeout serveru. Přehození clusteru z jednoho nodu na druhý tedy aoe přežije velmi snadno, stačí nastavit rozumný timeout a není nutné řešit multipathing.

NFS

Konfigurace NFS bude v dalším zápisku.