Přejít k navigační liště

Zdroják » Různé » CouchDB – tak trochu jiná databáze (1. část)

CouchDB – tak trochu jiná databáze (1. část)

Články Různé

Ukládání dat je záležitost, kterou řeší vývojáři téměř denně. Existuje mnoho cest, jak k problému přistoupit. jednou z cest může být například CouchDB: distribuovaná, dokumentově orientovaná databáze s HTTP RESTful JSON API (tolik zkratek pohromadě…), kterou lze indexovat ve stylu MapReduce.

CouchDB je relativně mladá databáze. Vývoj započal roku 2005 Damien Katz, minulý rok (tj. 2008) se dostala pod křídla Apache Foundation a oficiálně se stala Apache CouchDB.

Proč CouchDB?

Proč bych se měl zajímat o nějakou další databázi? Předně to může být její zajímavou architekturou – sama je napsána v Erlangu, své API zpřístupňuje přes HTTP a pohledy ve stylu MapReduce (o těch něco málo později) jsou psány v JavaScriptu (ovšem ten může být nahrazen prakticky čímkoli jiným, kupř. Perlem, Pythonem, Ruby atd.).

JSON

V perexu stojí, že CouchDB je dokumentově orientovaná databáze. Dnes se vývojáři nejvíce setkávají s relačními databázemi. Ty jsou založeny na léty ověřeném relačním modelu. CouchDB se ale ubírá jinudy. Místo toho, abyste definovali rigidní strukturu (schéma), do které se budou data ukládat, CouchDB vám poskytuje jednu základní flexibilní jednotku – dokument. Dokument není nic jiného než libovolně složitý JSONovský objekt. CouchDB vás nijak neomezuje v tom, co v dokumentu být smí či nesmí – všechno je to na vás, resp. vaší aplikaci.

Bez schématu

Schémata jsou ale dobrá, ne? Jsou. Avšak dříve nebo později můžeme narazit. Řekněme, že máme obchod a chceme ke každému produktu, který prodáváme, přidávat různé informace – parametry. Pokud budeme uvažovat relačně, dá se vydat dvěma cestami (koho napadne další, má bod).

  1. Budeme tabulku zvětšovat do šířky – pro každý parametr bude nový sloupec.
  2. Kromě tabulky produktů zde bude ještě jedna, ve které se budou ukládat trojice [produkt, parametr, hodnota].

Problémem prvního řešení je, že ve většině řádků, v závislosti na tom, jak moc rozličné zboží prodáváme, zůstane mnoho sloupců nevyužito. Problémem druhého zase to, že ve sloupci hodnota se budou míchat data různých typů (některý parametr je číslo, jiný řetězec, další zase logická hodnota).

Podobně dopadnete, budete-li chtít do relační databáze ukládat vícejazyčné záznamy.

ID dokumentů

U relačních databází je nejčastějším způsobem, jak identifikovat záznamy, nějaký druh samozvyšujícího se ID (auto increment ID). To znám. Je v tom snad problém? Ano, docela ano – jelikož CouchDB si dává hned dva přívlastky (distribuovaná a s RESTful rozhraním), které tomuto přístupu poněkud brání.

RESTful rozhraní (viz článek zde na Zdrojáku o architektuře REST pozn.red.) by měla mít tu vlastnost, že jejich chování nezávisí na předchozích požadavcích – všechno, co potřebujeme k vrácení výsledku, by mělo být založeno na datech právě tohoto požadavku a žádného jiného. Jak v tom brání auto increment ID? Je to stav, který je závislý na předchozích požadavcích. Pokud budu postupně vytvářet záznamy, musím si uchovávat, u jakého ID jsem skončil. Takže k vytvoření nového záznamu zkombinuji data z požadavku s daty ovlivněnými předchozími požadavky.

U distribuovaného prostředí by se takové auto increment ID muselo udržovat napříč servery, což přináší další zbytečnou komunikaci a nepotřebné komplikace rozhraní.

CouchDB tedy místo toho k identifikování záznamů používá UUID (universální unikátní identifikátory). Dokumenty jsou poté distribuovány právě podle toho, jaké mají UUID.

Žádné zámky, žádné čekání

Jako většina databází se i CouchDB drží architektury klient-server. Aby mohlo najednou ke stejným datům přistupovat více klientů, databáze to musí řešit. Mnoho databází používá zámky. Zámky jsou špatné, áno? Ve své podstatě ne, protože neumožní dvěma klientům, aby si zároveň přepisovali data, nebo aby jeden klient četl data, jejichž zápis ještě druhý nedokončil. Ale (vždycky je tu ale) klienti musí čekat a čekat a čekat. A čekání už špatné je. Nikdo nečeká rád.

Problém přístupu více klientů ke stejným datům v jeden okamžik je u CouchDB řešen pomocí MVCC (Multiversion Concurrency Control) – místo toho, aby dokument, do kterého chceme zapisovat, zamkla pro zápis (takže by se k němu ostatní klienti nedostali), vytvoří zcela novou revizi dokumentu, která bude obsahovat změněná data. Když je nová revize úspěšně zapsána, je dalším požadavkům vracena ona. Ovšem mezitím, co je zapisována, ostatní klienti mohou paralelně číst starší revizi dokumentu, a nemusí tedy čekat. Ale (opět je tu ale) tento přístup je vykoupen tím, že databáze potřebuje více diskového prostoru.

Instalace

Jako primární zdroj informací o instalaci berte wiki. Tam byste měli najít ty nejaktuálnější informace.

Linux

Pokud vaše distribuce má balíčkovací systém, nejdříve zkuste jej.

Debian a jeho deriváty (Ubuntu)

# apititude install couchdb

Gentoo

# echo dev-db/couchdb >> /etc/portage/package.keywords
$ emerge -pv couchdb
# emerge couchdb

Arch Linux

CouchDB je dostupná v AURu. Instalace pomocí  yaourt:

$ yaourt -S couchdb

Pokud chcete mít opravdu bleeding edge CouchDB, nahraďte couchdb-svn namísto  couchdb.

Instalace ze zdrojových kódů

A samozřejmě je možná instalace ze zdrojových kódů. Můžete použít tarbally, nebo checkoutnout SVN repozitář na http://svn.apache.org/repos/asf/couchdb/trunk/. Závislosti naleznete v souboru README. Jestliže máte zdrojové kódy z čerstvého checkoutu, spusťte:

$ ./bootstrap

Zkompilujte pak svatou trojkombinací:

$ ./configure
$ make
# make install

V případě, že se vám nechce databázi instalovat, využijte:

$ make dev
$ ./utils/run

Mac OS X

I když si na Mac OS X můžete též hezky zakompilovat, existuje tu snazší způsob, jak si na něm pohrát s CouchDB – pomocí CouchDBX. Sice se jedná o neoficiální aplikaci, ale instalace je velice pohodlná – stáhněte, dvojklikněte a máte běžící CouchDB.

Další možností je využít MacPorts:

$ sudo port selfupdate
$ sudo port install couchdb
$ sudo launchctl load -w /opt/local/Library/LaunchDaemons/org.apache.couchdb.plist

Poslední příkaz spustí CouchDB a přidá ji do seznamu démonů spouštěných po startu.

Windows

CouchDB sice není oficiálně na Windows podporována, ale existuje pro ni neoficiální binární balíček. Samozřejmě budete potřebovat Erlang. Poté ještě Visual C++ 2008 Redistri­buables a OpenSSL. Proklikejte se přes všechna „Next“ a počkejte, až instalátory všechno zařídí.

Nakonec přejděte do podadresáře bin/ vaší CouchDB instalace a spusťte couch_start.bat. Mělo by dojít k otevření Erlang shellu (který s trochou štěstí nevypíše žádné závažné chyby) a CouchDB by měla běžet.

První krůčky

Ověřit si, jestli CouchDB běží, je opravdu jednoduché – otevřete si v prohlížeči adresu http://localhost:5984/. Uvidíte něco jako (verze se s největší pravděpodobností bude lišit):

{"couchdb":"Welcome","version":"0.10.0a799862"} 

Tohle je uvítací hláška, kterou vás CouchDB obštědří, pokud provedete GET požadavek na /. Jelikož budeme chtít odesílat i jiné požadavky, než jen GET, bude potřeba nějaký nástroj, ve kterém se to bude moci nastavit

Milovníci práce se shellem si vystačí s utilitkou curl. Nejdůležitější přepínače jsou -X <metoda>, kdy za metodu dosaďte, co bude potřeba ( GET, POST, PUT, DELETE); -d <data>, kterýžto odešle daná data v těle požadavku; -v, aby byly vidět detailní informace, co se všechno děje; a -H pro nastavení zasílaných hlaviček.

Nebo použijte telnet a požadavky si sestavujte opravdu na míru.

Pro příznivce Firefoxu je tu doplněk RESTClient.

Co když nepoužívám Firefox a nechce se mi pachtit v shellu? Dokonce i když máte Firefox a shell ze srdce rádi, CouchDB vám nabídne hezké Ajaxové administrační rozhraní zvané Futon. Dostanete se k němu ze svého oblíbeného prohlížeče napsáním http://localhost:5984/_utils/ do adresního řádku.

K Futonu se ještě vrátíme, ale až na konci, do té doby si vystačíme s HTTP požadavky. V dalších dílech bude proto používán curl; zápisy jsou pochopitelné, takže by neměl být problém s pomocí předchozího popisu poslat stejné požadavky vaším oblíbeným klientem.

Abychom mohli ukládat dokumenty, je potřeba si nejdříve vytvořit přihrádku, kam půjdou – databázi. O tom, jak pracovat s databázemi a jak vytvářet dokumenty, si povíme v další části článku.

Komentáře

Subscribe
Upozornit na
guest
20 Komentářů
Nejstarší
Nejnovější Most Voted
Inline Feedbacks
View all comments
Nuko

A co zamky u konkurencniho zapisu?

Gorilka

Vzhledem k tomu, že se autor poněkud topí už u zamykání dat a concurency modelu na DB serveru, nemá cenu tuto otázku ani pokládat.
Ale jinak pěkný článek.

ego

Doufam, ze autora tento bezcenny a arogantni prispevek neznechuti tak, aby nas pripravil o dalsi dily.

Martin Malý

Autor dodal celý miniseriál najednou, takže o další díly nebudete připraveni.

MarSik

Nejsou potřeba. Všdy se zapisuje celý dokument a pokud v požadavku nesedí (povinný) klíč _rev s aktuálně platnou revizí, zápis se neprovede a databáze informuje klienta o konfliktu verzí. Ten na to pak může reagovat.

Není to databáze na ukládání transakčního logu burzy, na to se opravdu lépe hodí relační (vyřešená tak, aby zamykání nezpomalovalo). Ale na data pro eshop nebo publikační systém vypadá velmi dobře.

Krom toho má zabudovány replikační mechanizmy, distribuovanost a fail-over mechanizmy erlangu, což by mohlo být dost zajímavé.

aprilchild

Zadne zamky nejsou, prectu dokument, spolu s nim ziskam cislo revize, pri ukladani musim cislo zpetne posilat, pokud mezitim vznikla nova revize, ulozeni selze. Pokud selhalo, zkusim opakovat. V CouchDB neni definovano, kdy ulozeni projde, v pripade caste konkurence muze cyklus teoreticky trvat vecne.

Pokud k danemu problemu dojde, v naproste vetsine pripadu se jedna o chybu navrhu. Je treba se malinko odprostit od klasickeho relacniho pohledu. Klasickym prikladem budiz bankovni transakce (penize z uctu na ucet). Oproti transakci v klasicke databazi (bez transakce by taky penize mohli zustat nekde viset:), spociva reseni v CouchDB (jen pro priklad, ne, ze to v tom nekdo napise bankovni aplikaci:) v nasledujicim zpusobu:

Kazdy ucet si drzi zakladni dokument s udaji o vlastnikovi, ale nikoliv o zustatku (protoze pri urcitem objemu transakci by nebyl zarucen zapis „nekdo mi posila penize a zaroven je odesilam jinemu“). Pro kazdy prevod se vytvori novy dokument s castkou, od koho/komu atp. Zustatek je pro kazdy ucet spocitan pres „reduce“ iteraci pres kolekci techto dokumentu vybranych na zaklade „koho/komu“. Protoze pri prevodu vznika jeden dokument (oproti klasickemu reseni „sniz zustatek u odesilatele, zvys u prijemce“), penize nemizi, „transakce“ je zarucena.

povinná

Slovo, po kterém tak marně tápete, se píše „souběžný“.

yossarian

pekne napsane, kamera chvali. po vecne strance trochu horsi, kamera kara.

(nill)

Shodou okolnosti zrovna s CouchDB koketuju takze uvitam clanky na toto tema. CouchDB je svym zpusobem genialni napad, autor by mel vice rozvest dalsi ficurky jako skalovatelnost, replikaci atd. Ukazkova aplikace by byla taky super, jen nejaka jina nez v couchdb dokumentaci…aby z toho serialu nebylo jen prekladani dokumentace, coz by byla skoda, protoze CouchDB ma potencial.

Almad

Já bych spíš uvítal i srovnání s jinými systémy, používam mongodb a rád bych si nějak strukturovaně uložil rozdíly.

David Majda

Děkuji autorovi za zajímavý článek, těším se na pokračování.

Lokutus

Vzhledem ke jménu Damien Katz a popsaným principům (dokumentově orientovaná databáze, UUID) apod. soudím, že inspirace přišla ze strany Lotus Notes. Jsem dychtivý přečíst si pokračování.

pavel

ano jako bývalého „notesaře“ mě to taky hned napadlo….. :o)))

Almad

Na tohle téma doporučuju video couchdb and me.

pepek

Som netusil, ze Tom Cruise je programator.. :)

Viliceq
  1. Budeme tabulku zvětšovat do šířky – pro každý parametr bude nový sloupec.
  2. Kromě tabulky produktů zde bude ještě jedna, ve které se budou ukládat trojice [produkt, parametr, hodnota].
  3. Kromě tabulky produktů zde bude ještě jedna, ve které se budou ukládat dvojice [produkt, parametr] a jedna další hodnota podle typu [hodnota_int, hodnota_text, hodnota_float, hodnota_timestamp, hodnota_bool]

Jedná se sice jen o rozšíření typu 2, ale přidáním sloupce pro každý používaný datový typ omezíme jeho nevýhody.

Navíc může mít jeden parametr více hodnot různého typu, které se dají využít bez nutnosti duplikovat parametr v tabulce.

Jinak hezký článek o zajímavé databázi, už se těším na další díl.

Mintaka

Ten bod 3. vyznívá podivně. Jestli jsem to pochopil správně, není z něj zřejmé, že pro každý typ uložené hodnoty bude třeba samostatná tabulka [produkt, hodnota]. (Předpokládám běžnou relační databázi.), s tím, že pro nalezení hodnot vztahujících se k danému produktu, budu třeba prohledat všechny tabulky.

Takže komplexnější řešení by bylo: Tabulka produktu [produkt(id), [..Další sloupce s vlastnostmi stejnými pro všechny produkty..]]

Tabulka parametrů [parametr(id)[­..vlastnosti společné pro parametry, například jeho název, autor, datum vložení.. ]]

Vazební tabulka mezi produkty a parametry [produkt(id), parametr(id)]

Toliko k vazbě parametr produkt. Pro relační databáze běžná záležitost. Nyní chceme spolu s parametry ukládat ještě konkrétní hodnoty.

Možností je několik a všechny závisí na parametrech cílového využití takové struktury. Tz. jaká data do toho potečou, jaké operace se s nimi budou provádět, v jakém množství, …

ř1] V tabulce parametrů budou navíc dva sloupce [typ_hodnoty, hodnota_v_binar­nich_datech_s_pro­mennou_delkou­] V situaci, kdy by se hodnoty vztahovaly k jednotlivým jednotlivým parametrům. výhody: obejití nutnosti založit pro každý typ samostatnou tabulku, mnoho specifických typů hodnot nevýhody: specifický přístup binárních datům, specifika vyhledávání podle binární hodnoty

ř2] Samostatná tabulka hodnoty_parametrů [hodnota(id), typ_hodnoty, hodnota_v_binar­nich_datech_s_pro­mennou_delkou­] a vazební tabulka [parametr(id), produkt(id), hodnota(id)] Pro situaci, kdy jsou hodnoty parametrů vztažené k jednotlivým produktům. výhody: jako ř1 nevýhody: jako ř1

ř3, ř4] Analogie k ř1 a ř2 ale místo binárních dat je použit textový řetězec. výhody: „lidštější“ práce než s binárními daty, o něco lepším možnost využít standardního aparátu DBMS nevýhody: omezení délkou řetězce, větší nároky při encodování/de­kódování celočíselných hodnot, binárních dat, strukturovaných formátů jako datum a čas, …

ř5] Samostatné tabulky pro každý typ [hodnota(id), hodnota] a provázání na produkty / parametry, vazební tabulkou výhody: bez nutnosti encodování/de­kódování hodnot (to udělá DBMS automaticky sám) nevýhody: tabulka pro každý typ ukládaných hodnot o obsluha této struktury


Určitě by s k tomu dalo najít ještě spousta řešení. Možností je mnoho, záležet bude na konkrétním nasazení.

viliceq

Špatně jsem se vyjádřil – jednalo by se o jednu tabulku, a jeden sloupec pro každý používaný datový typ.

Tozn. tabulka by měla tyto sloupce:

produkt integer, parametr text, hodnota_int integer, hodnota_text text, hodnota_float float, hodnota_timestamp timestamp, hodnota_bool boolean

Mintaka

Taky řešení. Pak by to chtělo logiku, která by dohledávala ve kterém z těch sloupců je obsah a které jsou jen vycpávka.

WuDo

Ahoj, moc děkuji… pouze prosím o doplnění nálepky CouchDB pro snadnější nalezení tohoto článku zde, na skvělém Zdrojáku…

Děkuji ;-)

Enum a statická analýza kódu

Mám jednu univerzální radu pro začínající programátorty. V učení sice neexistují rychlé zkratky, ovšem tuhle radu můžete snadno začít používat a zrychlit tak tempo učení. Tou tajemnou ingrediencí je statická analýza kódu. Ukážeme si to na příkladu enum.