Replikace

Školení, která pořádám

Ve webové prezentaci vznikají data, která se ukládají do databáze. S těmito daty je dále potřeba intenzivně pracovat – zobrazovat je a upravovat v administračním rozhraní. V zájmu dosažení co nejvyšší rychlosti a odstínění občasných výpadků připojení by bylo ideální s databází pracovat z lokální sítě. K tomu MySQL nabízí replikaci. Vzhledem k tomu, že data vznikají a upravují se jak „venku“, tak „vevnitř“, hodila by se replikace obousměrná. Tu MySQL při splnění určitých podmínek nabízí – nesmí dojít ke kolizi unikátních klíčů (nejčastěji způsobené vložením řádku do tabulky s AUTO_INCREMENT na obou serverech) a nesmí nám záležet na pořadí provedení rozdílných modifikací záznamů provedených na obou serverech v podobném čase.

S těmito omezeními se dá docela dobře žít. Co mě ale trápí, je proces zotavení, když replikace z jakýchkoliv důvodů přestane pracovat. To se obvykle řeší tak, že se na master serveru udělá snapshot, který se nahraje na slave, a replikace se zase spustí. V případě obousměrné replikace to ale není možné – část správných dat je na obou serverech. Řešit by se to dalo asi jen vlastním skriptem – správným směrem přenést data z tabulek, které se modifikují na tom kterém serveru (například do tabulky objednavky se „venku“ vkládají záznamy, zatímco „vevnitř“ se tyto záznamy modifikují), a případné konflikty řešit ručně. To je velmi krkolomné řešení – k úplnému zastavení replikace by nemělo docházet moc často, ale je nutné s tím počítat a mít pro tento případ připravený postup.

Proto bude možná lepší zvolit kompromisní řešení – data modifikovat vždy „venku“, replikovat je jedním směrem a ze slave je pouze číst. Toto řešení samozřejmě není tak robustní jako obousměrná replikace, protože v případě výpadku spojení bude data možné pouze číst, zato umožňuje popsaný triviální postup zotavení. V případě aktualizace dat na master serveru ale může nějakou dobu trvat, než se data přenesou zpět na slave, proto je na ně vhodné počkat:

<?php
$slave = mysql_connect("localhost");
$master = mysql_connect("example.com");
mysql_query("INSERT INTO tabulka (jmeno) VALUES ('" . mysql_real_escape_string($_POST["jmeno"]) . "')", $master);
$status = mysql_fetch_assoc(mysql_query("SHOW MASTER STATUS", $master));
mysql_query("DO MASTER_POS_WAIT('$status[File]', $status[Position])", $slave);
?>

Tím se po provedení aktualizace počká na přetažení dat, čímž sice odpadne velká výhoda asynchronnosti, ale pořád lepší, než data změnit a výsledky nevidět. Stav master serveru je také možné uložit do session proměnné a na synchronizaci počkat až v momentě, kdy se data mají zobrazit.

Připomínám, že příkaz DO provede zadanou funkci a dá se použít jako nepatrně rychlejší varianta SELECT bez FROM, pokud nás nezajímá návratová hodnota.

Protože čekání na synchronizaci může trvat dlouho, dá se na základě příkazu SHOW SLAVE STATUS a jeho položek Master_Log_File a Exec_Master_Log_Pos rozhodnout o tom, zda se následující SELECT má provést na slave nebo na master serveru.

Opačný přístup, tedy zřízení master serveru „vevnitř“ a slave „venku“ by byl příjemnější v tom, že změn prováděných „venku“ je minimum (vytváření objednávek, přidávání komentářů) a jen část změn musí být viditelná okamžitě. Pokud by ale došlo k výpadku spojení např. při vytváření objednávky, je nutné mít navržené náhradní řešení – v tom případě je nutné data uložit někam bokem a na master je nahrát dodatečně. Tím se toto řešení opět značně komplikuje.

Na paměti je nutné mít i bezpečnost. Při připojení k SQL serveru na stejném počítači nebo ve stejné síti je riziko přenášení nezašifrovaných hesel samozřejmě mnohem menší než při přenášení těchto údajů Internetem. K tomu je možné použít šifrované spojení (jako pátý parametr funkce mysql_connect uvést MYSQL_CLIENT_SSL a PHP mít zkompilované s MySQL knihovnami alespoň verze 4 nebo v případě MySQLi funkcí mysqli_ssl_set).

Kromě dat v databázi je obvykle potřeba pamatovat také na soubory. Pokud jsou uloženy v souborovém systému, tak máme o starost navíc – musíme je přenášet mezi servery nezávisle na databázi a odděleně musíme řešit i zabezpečení – skript zajišťující nahrání souboru musí být zabezpečen tak, aby nahrání souboru nepovolil komukoliv. V mnoha případech proto bude mnohem jednodušší zvážit často opovrhované ukládání souborů do databáze a soubory servírovat vlastním skriptem.

Přijďte si o tomto tématu popovídat na školení Konfigurace a výkonnost MySQL.

Jakub Vrána, Seznámení s oblastí, 10.3.2006, diskuse: 4 (nové: 0)

Diskuse

mekele:

Rekne mi nekdo z hlavy od jake verze je replikace podporovana? Najit cokoliv v dokumentaci MySQL je nejhorsi nocni mura..

ikona Jakub Vrána OpenID:

3.23.15 (08 May 2000). Mě se v MySQL dokumentaci hledá docela dobře.

Jitka Dařbujanová:

Dobrý den, máte u MySQL praktickou zkušenost s tím, při kolika připojených uživatelích se již vyplácí replikovat?
Díky

ikona Jakub Vrána OpenID:

Na počtu uživatelů to ani tolik nemusí záležet. Důležité je to, jak je server vytížen, což je dáno jednak jeho hardwarem a jednak aplikací, kterou na něm provozujeme.

Vložit komentář

Používejte diakritiku. Vstup se chápe jako čistý text, ale URL budou převedeny na odkazy a PHP kód uzavřený do <?php ?> bude zvýrazněn. Pokud máte dotaz, který nesouvisí s článkem, zkuste raději diskusi o PHP, zde se odpovědi pravděpodobně nedočkáte.

Jméno: URL:

avatar © 2005-2018 Jakub Vrána. Publikované texty můžete přetiskovat pouze se svolením autora. Ukázky kódu smíte používat s uvedením autora a URL tohoto webu bez dalších omezení Creative Commons. Můžeme si tykat. Skripty předpokládají nastavení: magic_quotes_gpc=Off, magic_quotes_runtime=Off, error_reporting=E_ALL & ~E_NOTICE a očekávají předchozí zavolání mysql_set_charset. Skripty by měly být funkční v PHP >= 4.3 a PHP >= 5.0.