Artikel top billede

(Foto: Computerworld)

Programmering med NoSQL - del 4

Du er nået til fjerde og sidste del i serien om NoSQL. Tidligere har du læst om teorien bag distribuerede systemer i form af CAP-sætningen og NoSQL-databaserne Keystore og CouchDB. Her i sidste del kommer du til at stifte bekendtskab med NoSQL-databasen MongoDB.

Af Kenneth Geisshirt, Alt om Data

Denne artikel er oprindeligt bragt på Alt om Data. Computerworld overtog i november 2022 Alt om Data. Du kan læse mere om overtagelsen her.

Firmaet 10gen står bag udviklingen af MongoDB, og de første linjer blev skrevet i 2007. Den første offentlige udgave af MongoDB skete i 2009, og siden har en række organisationer og firmaer valgt at bruge denne NoSQL-database. I dag finder du MongoDB hos så forskellige steder som Foursquare, CERN/LHC, New York Times og Doodle.

Selve databasen er skrevet i programmeringssproget C++. Men sproget JavaScript bruges meget på serversiden af MongoDB, herunder til specifikation af forespørgsler og hjælpefunktioner. Det vil sige, at i MongoDB er der indlejret en JavaScript-fortolker.

Softwaren er underlagt en række forskellige licenser. MongoDB-kernen distribueres under AGPL, som er en modificeret udgave af GNU General Public License version 3 (GPLv3).

Modifikationen består i – ud over betingelserne i GPLv3 – at når du tilbyder andre adgang til din database, skal disse brugere også have adgang til MongoDB-kildeteksten.

Bindingerne til forskellige programmeringssprog omtales blandt MongoDB-udviklere og -brugere som drivers, og disse distribueres under Apache-licensen (version 2). Al dokumentation frigives under en Creative Commons-baseret licens. Alt i alt kan MongoDB regnes som open source-software.

Egenskaber

MongoDB er en dokumentorienteret database. Både ved forespørgsler og til lagring bruger MongoDB en variant af JSON kaldet BSON (binær JSON). Mens JSON er klar tekst og kan læses umiddelbart af mennesker, er BSON et mere kompakt format, som er velegnet til computere.

Der er tale om en distribueret database. MongoDB kan bruges i to forskellige distribuerede konfigurationer. Den første en ren master/slave-konfiguration. Der er tale om en konfiguration, hvor slaven står klar til at overtage, hvis masteren går ned. Med andre ord master/slave-konfigurationen kan bruges til at sikre tilgængeligheden.

Den anden konfiguration (replica sets) er en mere avanceret form for master/slave. Går masteren ned i denne situation, vil slaverne automatisk finde ud af, hvilken slave som skal være den nye master. Det kræver derfor mindst tre servere – en master og mindst to slaver.

Eftersom alle operationer på data sker hos masteren, kan en eller flere slaver være bagud med hensyn til opdateringer af data. Går du altid kun til masteren, vil dit MongoDB- system altid være stærk konsistent.

Men kan du leve med, at data ikke altid er konsistent (eventually consistency), kan du bruge slaverne til at læse data fra. Det betyder, at du kan få spredt dataoperationer ud på flere servere og derved få en større skalerbarhed.

Det er dog også muligt at øge skalerbarheden ved at bruge en teknik ved navn sharding. Ideen er at sprede en database ud på flere master/slave-instanser ved at skære den i mindre stykker: Tænk på en krukke, som du slår i stykker og får en masse potteskår af (shard betyder potteskår på engelsk).

Installation

Bruger du Ubuntu Linux, er det let at installere MongoDB, idet der findes pakker. Du kan med kommandoen sudo apt-get install mongodb-server installere serverdelen.

Har du mere lyst til at installere den seneste udgave af MongoDB, kan du downloade kildeteksten. Men inden du gør det, skal du under Ubuntu Linux installere en lang række pakker.

Kommandoen sudo apt-get install scons g++ xulrunner-dev libpcre++-dev libboost-dev libboost-thread-dev libboost-program-options-dev libboost-filesystem-dev libreadline-dev installerer alle relevante pakker.

Du er nu klar til at downloade kildeteksten fra MongoDB’s hjemmeside. I skrivende stund kan du gøre det med kommandoen wget http://downloads.mongodb.org/src/mongodb-src-r1.6.5.tar.gz.

Udpakning og oversættelse af MongoDB kræver tre enkelte kommandoer: tar xzf mongodb-src-r1.6.5.tar.gz; cd mongodb-src-r1.6.5; scons ..

Den sidste kommando udfører selve oversættelsen af MongoDB, og den kan godt tage 10-15 minutter (det afhænger naturligvis af, hvor hurtig din computer er). Afslutningsvis kan du installere MongoDB med kommandoen sudo scons --prefix=/opt/mongo install.

Opsætning

Som allerede nævnt kan MongoDB køre i flere forskellige konfigurationer. Den enkle master/slave-konfiguration er let at sætte op – i det mindste til de første eksperimenter. Det er muligt at nøjes med en maskine til dine eksperimenter, og til de indledende eksperimenter behøver du ikke at skrive en konfigurationsfil.

Først skal du oprette to foldere på din computer med kommandoerne sudo mkdir /opt/mongo/masterdata og mkdir /opt/mongo/slavedata. Folderen /opt/mongo/masterdata bruger masteren til sine data, men /opt/mongo/slavedata brugeren slaven.

Du er nu klar til at starte masteren op. Kommandoen sudo /opt/mongo/bin/mongod --master --dbpath /opt/mongo/masterdata sætter masteren i gang. Som du kan se, angiver du, at MongoDB-dæmonen skal køre som master, og at /opt/mongo/masterdata er dens data-område.

Slaven bruger samme program som dæmon. Men slaven er nødt til at vide, hvor masteren er. Kommandoen, som starter slaven op, må angive dette: sudo /opt/mongo/bin/mongod --slave --port 27018 --source localhost:27017 --dbpath /opt/mongo/slavedata.

Med option –source angiver du, hvor masteren befinder sig. Eftersom master og slave kører på samme computer, må slaven lytte til en anden port end masteren. 27017 bruges af masteren, så valget er faldet på 27018 til slaven.

Både master og slave vil skrive en del ud på skærmen, mens de kører. På den måde kan du følge med i, hvad de foretager sig. Du vil hurtigt lægge mærke til, at slaven ofte forsøger at replikere data fra masteren.

MongoDB har et webinterface til administration på port 28017, så du kan pege din webbrowser på http://localhost:28017 (under antagelse af, at du bruger din desktop-maskine til dine eksperimenter) og få afgang til dette.

For at bruge MongoDB fra programmeringssproget php skal du installere php-driveren. Den findes ikke som pakke til Ubuntu Linux, så det er du nødt til at gøre semimanuelt.

Først skal du have dit php-miljø klar. Det kan du klare med Ubuntu-pakker. Kommandoen er sudo apt-get install php5-cli php5-dev php-pecl.

Når det er gjort, kan du bruge php’s eget pakkesystem til at installere MongoDB-driveren. Du bruger kommandoen sudo pecl install mongo. Endelig skal du tilføje linjen extension=mongo.so til php’s konfigurationsfil.

Oprettelse af forbindelse

Det er ikke nødvendigt at oprette en database i MongoDB, før du bruger den. Tricket er, at data oprettes, når du indsætter det, men MongoDB er doven. Og det betyder, at en database oprettes, første gang du indsætter data i en database. På den måde findes tomme databaser ikke.

At oprette en forbindelse til MongoDB er ikke svært. Her et eksempel på hvordan:

<?

$m = new Mongo(”localhost:27017”, array(”persist” => ”x”));

$aod = $m->aod;

$billeder = $aod->billeder;

?>

Det er muligt at sætte en række options under oprettelse af forbindelse. For eksempel er det muligt at bruge en fast forbindelse (persistent) og sætte brugernavn og kodeord (dette er nødvendigt, hvis du starter masteren op med option –auth). Forbindelsen holdes med variablen $m.

Koden i boksen Opret forbindelse viser også lidt mere end blot oprettelse af forbindelse. Der skiftes til databasen aod og samlingen (collection) billeder. I en sammenligning med en relationsdatabase vil aod være en database, mens billeder vil være en tabel. Du skal dog passe på med denne sammenligning, da der er tale om to meget forskellige databasemodeller.

Gem billede

Da du nu kan oprette forbindelse til MongoDB, er det tid til at indsætte et billede i databasen. Her kan du bruge metoden insert:

<?

$date = new DateTime();

$handle = fopen(”/tmp/kneth.jpg”, ”r”);

$imgfile = fread($handle, filesize(”/tmp/kneth.jpg”));

fclose($handle);



$m = new Mongo(”localhost:27017”, array(”persist” => ”x”));

$aod = $m->aod;

$billeder = $aod->billeder;



$billeder->insert(array(”title”=>”billede_kneth”, ”timestamp”=>$date->getTimeStamp(), ”data”=>base64_encode($imgfile)));

?>

Du kan indsætte vilkårlige php-objekter, og MongoDB vil konvertere dem til BSON undervejs. Kompleksiteten af objekter, du indsætter i MongoDB, bestemmer du selv. Det betyder, at du uden problemer kan have arrays af arrays (og så fremdeles).

For at få forespørgslerne til at gå hurtigere senere, kan det være en fordel at oprette en indeks til en samling. Du kan med metoden ensureIndex oprette et indeks; linjen $billeder->ensureIndex(array(“title” => 1)) vil oprette et indeks på title, som blev brugt som en del af data, da billedet blev indsat.

Få oversigt

Med billeder i dine samlinger vil du sikkert gerne danne dig en oversigt over, hvilke billeder du har. En oversigt dannes lettest ved at forespørge på alt. Det er nok en lidt krævende proces, men det giver dig alle data.

Her ser du php-koden til at give en oversigt over alle billeder, som har en titel:

<?

$m = new Mongo(”localhost:27017”, array(”persist” => ”x”));

$aod = $m->aod;

$billeder = $aod->billeder;



echo ”Antal: ”.$billeder->count().”n”;

$cursor = $billeder->find();

foreach ($cursor as $id => $value) {

if (array_key_exists(”title”, $value)) {

echo ”$id: ”.$value[’title’].”n”;

}

}

?>

Inden du forsøger at danne oversigter, kan du bruge metoden count til at fortælle dig, hvor mange objekter som findes i samlingen.

Metoden find sender en forespørgsel til MongoDB. Er der intet argument, betyder det, at alle data hentes. Du har en cursor tilbage – sådan en cursor er et array, som er indekseret ved hjælp af et internt ID. Da en NoSQL-database som MongoDB ikke har en fast struktur, kan det være nødvendigt at tjekke, om dataelementer findes, inden de bruges.

Hent billede

Fra oversigten er det tid til at hente det ønskede billede frem. Billederne blev gemt med en titel, som gerne skal være entydig. Denne antagelse anses for sand i php-koden:

<?

$m = new Mongo(”localhost:27017”, array(”persist” => ”x”));

$aod = $m->aod;

$billeder = $aod->billeder;



$cursor = $billeder->find(array(”title” => ”billede_kneth”));

$billede = $cursor->getNext();



print $billede[”title”].” dateret ”.date(”d M Y”, $billede[”timestamp”]).”n”;

$data = base64_decode($billede[”data”]);

$handle = fopen(”test.jpg”, ”w”);

fwrite($handle, $data);

fclose($handle);

?>

Metoden find gives en forespørgsel. Som du kan se, angives forespørgslen som et array, hvor de enkelte felters værdi angives. Holder antagelsen om kun et resultat fra forespørgslen, er det nok at få det ene element.

Metoden getNext giver altid det næste element. Det er muligt at spørge, om der er flere ved hjælp af metoden hasNext. Brugen af hasNext og getNext sammen i en while-løkke gør det muligt iterativt at hente alle resultaterne.

Afslutning

Serien om NoSQL-databaser er kommet til en slutning. Har du store websites med mange brugere, kan det være, at du skal overveje en NoSQL-database i fremtiden.

NoSQL-databasernes distribuerede natur gør dem velegnede til at skalere til store voluminer, som du finder i websites som Facebook, Amazon og Google. Træerne vokser ikke ind i himlen, og CAP-sætningen sætter sine begrænsninger på, hvordan du kan bruge NoSQL-databaserne.

[themepacific_accordion]
[themepacific_accordion_section title="Fakta"]

Få mere at vide

[/themepacific_accordion_section]
[/themepacific_accordion]