Dnes se podíváme na NoSQL databázi, která není “jen” dobrá pro web – ona vlastně web je.
Co je CouchDB
Na stránkách cloudsvet jsme mluvili o MongoDB, která je nejúspěšnějším zástupcem NoSQL Document databází. Viděli jsme, že to co se ukládá, je relativně volná datová struktura popsaná jako JSON (uložená binárně jako BSON). CouchDB je zástupce stejné rodiny, ale jde do extrému, co se týče “webového chování”. Současně má VELMI odlišný přístup k namíchání CAP vlastností. Místo vynucení konzistence na úkor výkonu přichází s čistě eventuální konzistencí a principem časových značek – o tom ale až příště.
Zpět ke CouchDB samotné. Je napsána v poměrně exotickém jazyce Erlang (vznikl v 90. letech v Ericssonu pro potřeby telco segmentu – je to příklad tzv. funkčního programování a zaměřuje se na velmi důslednou share nothing architekturu a extrémní paralelismus ne jen na úrovni threadů, ale systémů … zkrátka je to opravdu exotické a současně dost speciální a zajímavé). Podstatnější ale je, že se CouchDB chochová jako web. Na rozdíl od MongoDB nepotřebujete žádný binární protokol, žádné knihovny, vůbec nic kromě HTTP. Všechno od vytváření databází přes vkládání a úpravy dat až po Map Reduce je řešeno jako HTTP volání. Tuto DB tedy můžete číst z libovolného prohlížeče, třeba z mikrovlnky nebo chytrých hodinek. Zápisy (např. operace POST nebo PUT) jsou rovněž zcela klasický arzenál HTTP protokolu, tedy webu. Ke každému uloženému “dokumentu”, kterým je JSON struktura, vede URL složená z IP adresy, jména DB a ID objektu. A klidně si do takové URL můžete přidat ještě obrázek. Při práci s CouchDB zjistíte, že je to jako serfovat na webu nebo využívat RESTful rozhraní.
Model konzistence a replikace necháme na příště – pro dnešek jen musíme vědět, že každý záznam je opatřen číslem verze (tímto se dají řešit konflikty při asynchronní replikaci). Pokud chceme záznam modifikovat, musíme si nejprve přečíst jeho číslo verze a při modifikaci toto uvést – pokud mezi tím někdo stihl dokument změnit, náš zápis bude odmítnut a máme šanci se znovu podívat, co tam je.
Kam se hodí?
CouchDB je fantasticky jednoduchá a má takřka nulové nároky na hardware. V zásadě každá instance funguje samostatně (nemá tedy nějaké synchronní clustery), ale mezi nimi funguje velmi jednoduchá a účinná replikace (s časovými značkami pro detekci konfliktů). Pokud potřebujete centrálně držet informace, ale distribuovat je třeba do auta nebo mobilu, tohle je perfektní způsob. Data v autě jsou dostupná nepřetržitě i bez konektivity a lze do nich klidně i zapisovat. Až bude auto připojeno (třeba v garáži), obousměrná replika zařídí vše potřebné.
Chcete výkon a při tom trváte na Document NoSQL (jinak jděte do Cassandra)? Použijte raději Couchbase. Chcete jednoduchost, širokou komunitu (tedy hodně příkladů) a laditelnou dobrou konzistenci a stále to má být Document NoSQL? Jděte do MongoDB. Hledáte úžasnou jednoduchost, naprostou nenáročnost a ideální řešení s “občasnou” replikací tak, jak se nody připojují a odpojují? CouchDB.
Instalace
V mém Ubutnu 14.04 jsem to provedl takhle:
sudo apt-get install software-properties-common -y sudo add-apt-repository ppa:couchdb/stable -y sudo apt-get update sudo apt-get install couchdb -y
CouchDB se chová jako web, takže nepotřebujeme žádného klienta či knihovnu. Použijeme jednoduše cURL – jakýsi textový “prohlížeč”, který umí i všechny potřebné metody jako je PUT nebo DELETE. Namiřte jej loopback adresu na portu, kde CouchDB ve výchozím stavu běží, a uvidíme, co se stane.
cloudsvet@ubuntu:~$ curl http://127.0.0.1:5984/ {"couchdb":"Welcome","uuid":"20c1b4327eb7ec24ecc58d9eae31de49","version":"1.6.1","vendor":{"version":"14.04","name":"Ubuntu"}}
Naše CouchDB žije.
Pojďme tedy založit databázi … hmm, jak na to? Bude to složité? Musíme definovat nějaké schéma? Použít utilitku? Kdepak – jednoduše použijeme HTTP PUT metodu a do URL přidáme název nové databáze:
cloudsvet@ubuntu:~$ curl -X PUT http://127.0.0.1:5984/napoje {"ok":true}
Nechoďme kolem horké kaše – zapišme tam nějaký dokument. Opět použijeme HTTP PUT, ale za jméno databáze přidáme ID nového objektu a jako data (přepínač -d) použijeme JSON objekt.
cloudsvet@ubuntu:~$ curl -X PUT http://127.0.0.1:5984/napoje/mojeid -d '{"name":"pivo"}' {"ok":true,"id":"mojeid","rev":"1-2db82d800a2e4740c3126c2711585748"}
Snadné, že? Zaběhnutá praxe je jako document ID používat nějaký řetězec s menší pravděpodobností, že stejný napadne i všechny ostatní – tedy UUID. Ideální je si ho generovat přímo v aplikaci, ale pro náš případ si ho třeba necháme dodat přímo samotným CouchDB (připomínám – není to nutné! Klidně používejte jakýkoli unikátní řetězec jako ID dokumentu, nesejde na tom, UUID je jen obvyklá praxe).
cloudsvet@ubuntu:~$ curl -X GET http://127.0.0.1:5984/_uuids {"uuids":["b47ba980a89eb0f8422ec4da8a000a79"]}
A ten pak použijeme
cloudsvet@ubuntu:~$ curl -X PUT http://127.0.0.1:5984/napoje/b47ba980a89eb0f8422ec4da8a000a79 -d '{"name":"vino"}' {"ok":true,"id":"b47ba980a89eb0f8422ec4da8a000a79","rev":"1-c363a1699e54c24c7b0ca30eca7955b6"}
Přečtěme si něco o naší databázi (pro GET operace úplně klidně můžete využít i váš oblíbený prohlížeč).
cloudsvet@ubuntu:~$ curl -X GET http://127.0.0.1:5984/napoje {"db_name":"napoje","doc_count":2,"doc_del_count":0,"update_seq":2,"purge_seq":0,"compact_running":false,"disk_size":8287,"data_size":441,"instance_start_time":"1442928729678746","disk_format_version":6,"committed_update_seq":2}
A přečtěme také naše záznamy
cloudsvet@ubuntu:~$ curl -X GET http://127.0.0.1:5984/napoje/mojeid {"_id":"mojeid","_rev":"1-2db82d800a2e4740c3126c2711585748","name":"pivo"} cloudsvet@ubuntu:~$ curl -X GET http://127.0.0.1:5984/napoje/b47ba980a89eb0f8422ec4da8a000a79 {"_id":"b47ba980a89eb0f8422ec4da8a000a79","_rev":"1-c363a1699e54c24c7b0ca30eca7955b6","name":"vino"}
Všimněte si přidaného atributu _rev – jde o číslo revize, tedy verze dokumentu. Při každé úpravě se nám promění. Abychom minimalizovali problém, že dva si dokument “otevřou” a rozhodnou se udělat změnu, ale ten který ji provede jako druhý, přepíše modifikace toho prvního, aniž by o nich věděl, musíme specifikovat číslo revize při požadavku na modifikaci. Tedy “dokázat”, že naše rozhodnutí o změně dokumentu jsme přijali na základě přečtení jeho poslední verze.
Změňte name z pivo na pivecko
cloudsvet@ubuntu:~$ curl -X PUT http://127.0.0.1:5984/napoje/mojeid -d '{"_rev":"1-2db82d800a2e4740c3126c2711585748","name":"pivecko"}' {"ok":true,"id":"mojeid","rev":"2-0c64aa606bc56849ed3b70747f405a1f"}
Získáváme nové číslo revize, což můžeme ověřit i přečtením
cloudsvet@ubuntu:~$ curl -X GET http://127.0.0.1:5984/napoje/mojeid {"_id":"mojeid","_rev":"2-0c64aa606bc56849ed3b70747f405a1f","name":"pivecko"}
Co když provedeme další update, ale uvedeme původní číslo verze?
cloudsvet@ubuntu:~$ curl -X PUT http://127.0.0.1:5984/napoje/mojeid -d '{"_rev":"1-2db82d800a2e4740c3126c2711585748","name":"pivko"}' {"error":"conflict","reason":"Document update conflict."}
Poslední bombonek v dnešní ukázce – k dokumentu můžete přiložit libovolný soubor, stejně, jako byste to dělali v HTTP formuláři nebo při odesílání emailu. Přidejte za URL dokumentu název souboru, předejte jako argument číslo revize a datovým proudem tam pošlete soubor – já jsem k dokumentu o pivu přiložil jeho obrázek (ve skutečnosti je mým obsahem pivo.jpg text, ale to je teď jedno).
cloudsvet@ubuntu:~$ curl -X PUT http://127.0.0.1:5984/napoje/mojeid/pivo.jpg?rev=2-0c64aa606bc56849ed3b70747f405a1f --data-binary @pivo.jpg -H "Content-Type: image/jpg" {"ok":true,"id":"mojeid","rev":"3-91d0960a4e64421732c1b4c1979544cb"}
Obrázek je dostupný zase jako HTTP – třeba z všeho prohlížeče. My použijeme curl a uvidíme jeho obsah (kterým je pro ukázku text).
cloudsvet@ubuntu:~$ curl -X GET http://127.0.0.1:5984/napoje/mojeid/pivo.jpg imagedata
Zabudované GUI
CouchDB má zabudované jednoduché GUI, aby byla práce se systémem ještě jednodušší.
Nejpre upravíme konfigurační soubor, aby bylo možné na CouchDB přistupovat zvenčí (nemusíte, pokud v systému s CouchDB máte i grafické prostředí s prohlížečem…což já nemám).
cloudsvet@ubuntu:~$ sudo nano /etc/couchdb/local.ini
Řádek …
;bind_address = 127.0.0.0
změňte na (nezapomeňte odstranit úvodní znak) …
bind_address = 0.0.0.0
Restartujte službu
cloudsvet@ubuntu:~$ sudo service couchdb restart couchdb stop/waiting couchdb start/running, process 3603
A připojte se na IP a port vaší VM s cestou _utils, například http://10.0.0.2:5984/_utils/
Web si můžete projít sami, je to velmi intuitivní – tady je pár screenshotů.