W sobotę w Lublinie odbyło się 7 spotkanie branży internetowej Netday. I ja tam byłem, prelekcje wygłosiłem, miód i wino piłem…
W ostatnich projektach często potrzebuję sparsować jakiś URL – wyciągnąć hosta czy np. nazwę pliku i ścieżkę z adresu strony internetowej. W .NET jest klasa Uri która świetnie radzi sobie z tym zadaniem, w PHP jest funkcja parse_url(), która sprawdza się równie dobrze. Niestety w standardowych bibliotekach JavaScript czegoś takiego się nie uświadczy.
I tu z pomocą przychodzi funkcja parseUri stworzona przez Stevena Levithan. Jej zwięzłość jest wręcz zadziwiająca. Użycie jest bardzo proste: wywołujemy funkcję parseUri podając URL jako parametr i dostajemy w efekcie obiekt JSON z poszczególnymi częściami adresu, dla przykładu:
parseUri("http://google.com").host; // google.com
parseUri("http://jakublaskowski.pl/index.php/2010/11/10/parsowanie-url-w-javascript/").directory; // /index.php/2010/11/10/parsowanie-url-w-javascript/
Więcej przykładów tutaj. Kod funkcji:
// parseUri 1.2.2
// (c) Steven Levithan <stevenlevithan .com>
// MIT License
function parseUri (str) {
var o = parseUri.options,
m = o.parser[o.strictMode ? "strict" : "loose"].exec(str),
uri = {},
i = 14;
while (i--) uri[o.key[i]] = m[i] || "";
uri[o.q.name] = {};
uri[o.key[12]].replace(o.q.parser, function ($0, $1, $2) {
if ($1) uri[o.q.name][$1] = $2;
});
return uri;
};
parseUri.options = {
strictMode: false,
key: ["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"],
q: {
name: "queryKey",
parser: /(?:^|&)([^&=]*)=?([^&]*)/g
},
parser: {
strict: /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/,
loose: /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/
}
};
MongoDB – nierelacyjna baza danych
0 Comments Published listopad 10th, 2010 in Programowanie, ProjektyWczoraj, podczas projektowania architektury bardzo ważnego modułu jednego z moich projektów natknąłem się na ciekawe wyzwanie, związane z wydajnością i skalowalnością. Nie chcę w tym momencie ujawniać zbyt wielu szczegółów samego projektu, skupie się wiec na problemie i rozwiązaniu jakie udało mi się znaleźć.
Moduł o którym mowa to coś w rodzaju distributed computing: wiele węzłów, każdy co jakiś czas pobiera zestaw danych do przetworzenia, przetwarza je i zapisuje wyniki do centralnej bazy danych. Różnica w porównaniu z np. seti@home jest taka, ze paczki tutaj są bardzo małe i w praktyce co kilkanaście sekund zachodzi potrzeba komunikacji między węzłem a centralą. Baza danych musi być jedna, aby łatwo móc wygenerować raporty na podstawie całego zbioru danych.
Na początku węzłów będzie kilka, ale spodziewam się, że nie będą mogły zapewnić wystarczającej wydajności przetwarzania danych i wkrótce będę musiał postawić do tego celu kilkanaście czy kilkadziesiąt serwerów. Moje główne obawy dotyczą bazy danych która ma być w środku – nie chciałbym by okazała się ona wąskim gardłem. W razie potrzeby dodanie węzłów przetwarzających dane nie byłoby wielkim problemem, zwiększenie wydajności centralnej bazy jest już znacznie trudniejsze.
Wymagania stawiane bazie były zatem dwa: jak najwyższa wydajność i możliwość skalowania na wiele serwerów z jednoczesnym zachowaniem spójności danych. No i oczywiście koszt musi być jak najniższy
. Tradycyjne SQL-owe bazy danych nie wypadają tu najlepiej, z pomocą przychodzą bazy nierelacyjne, najkrócej mówiąc, coś pomiędzy prostymi tablicami klucz:wartość a normalnymi bazami SQL.
Do tej pory tematyka ta była mi nieco obca, oczywiście, słyszałem co nieco, głównie o BigTable by Google, ale nigdy nie zagłębiałem się w to dokładnie – do wczoraj, kiedy rozmyślając nad architekturą modułu przypomniałem sobie o istnieniu takich baz i postanowiłem przyjrzeć się dokładnie.
Cały wczorajszy dzień poświęciłem na analizę tego tematu – i wygląda bardzo obiecująco. Z dostępnych rozwiązań najbardziej przypadło mi do gustu MongoDB. Muszę przyznać, że jestem zachwycony prostotą obsługi tej bazy, tego w jaki sposób się tworzy nowe bazy, kolekcje, jak się dodaje, wyszukuje i modyfikuję rekordy. W zasadzie na poziomie samej bazy mamy już zaimplementowany moduł ORM. Do MongoDB można zapisać po prostu tablicę, nie ma potrzeby budowania zapytania. Pobrane rekordy także otrzymujemy w bardzo wygodnym formacie. Dodatkowo nie trzyma nas żaden schemat tabeli, co na pewno często jest zaletą, utrudnia nieco jednak projektowanie aplikacji, w której brak sztywno zdefiniowanych tabel.
W tym konkretnym przypadku nie jest jednak istotna łatwość korzystania z bazy (choć niewątpliwie jest to kolejny argument na tak), a wydajność i skalowalność. I w obydwu tych punktach MongoDB bez problemu pokonuje MySQL. Baza jest bardzo szybka, a przy tym dobrze się skaluję w szerz dzięki technologii o nazwie Sharding. Jest to swego rodzaju partycjonowanie danych pomiędzy wiele serwerów z zachowaniem spójności – dodatkowy serwer pośredniczący wie z którego serwera pobrać potrzebne dane i przesyła je do aplikacji w całkowicie przezroczysty sposób. Rozwiązanie dla mnie idealne. Na początku mogę postawić jeden serwer, a gdy się okaże, że to nie wystarcza, bez żadnych problemów, bez konieczności modyfikowania kodu mogę łatwo dodać kolejne i rozdzielić ruch między nimi.
Wczoraj zainstalowałem MongoDB na moim serwerze developerskim, dzisiaj czas na testy programistyczne. O wynikach na pewno napiszę
. Gorąco wierzę, że będzie to strzał w dziesiątkę.
Na koniec krótkie omówienie funkcji MongoDB:
- Rekordami w bazie są obiekty JSON. Obiekty te mogą tworzyć wielopoziomowe drzewo, a wyszukiwanie (i zakładanie indeksów) możliwe jest na dowolnej właściwości obiektu, także na tych głęboko zagnieżdżonych. Nie ma sztywnego schematu rekordów. W teorii każdy rekord może mieć zupełnie inny schemat, inne pola. W praktyce jednak zawsze jakaś logika jest zachowana
- Standardem jest replikacja danych w modelu master/slave. Zapis może być dokonywany tylko na serwerze master, odczyt może być z dowolnego serwera.
- Auto-Sharding pozwala na poziome skalowanie bazy danych na wiele serwisów bez utraty spójności danych.
- Technologia Map/Reduce pozwala na bardzo elastyczną agregację danych i super wydaje, rozproszone przetwarzanie danych z bazy
- GridFS – dodatkowy bonus, pozwalający przechowywać pliki w bazie danych, szczególnie fajne w połączeniu z wieloma serwerami pracującymi w Auto-Sharding
Ostatnio, w czasie powrotu z democamp zepsuł mi się samochód. To długa historia, a skończyła się (a może to nie jest jeszcze jej koniec?) tak, ze samochód został w warsztacie w Warszawie, a ja wróciłem do Lublina. Teraz własnie jadę busem go odebrać.
Podróż się dluzy, mi się nudzi a rzeczy do zrobienia mnóstwo. Pomyślałem, ze może przynajmniej napisze coś na bloga. Z AppStore pobralem aplikacje wordpress.
Muszę przyznać ze jest to bardzo przyjemne narzędzie. Pozwala podłączyć wiele blogów, zarówno tych na wordpress.com jak i zainstalowanych na własnym serwerze. Można tworzyć i edytowac posty, dodawać i moderowac komentarze a także zarządzać zdjęciami. Słowem, wszystkie podstawowe funkcje które warto mieć zawsze pod ręka. Jedyne dwa zastrzeżenia jakie można mieć to pewne problemy z pisaniem w poziomym położeniu telefonu (pisać można, ale cieżko jest zrobić tak, by było widać co się pisze) i brak formatowania treści posta.
Podsumowując, aplikacja wordpress na iOs to dobre narzędzie gdy trzeba szybko opublikować krótka informacje na blogu, a brak komputera w pobliżu, ale do pisania dłuższych postów już raczej się nie nadaje.
Ostatnio sporo angażuje się w projekty informatyczne na zlecenie – moje własne projekty pożerają dowolną ilość gotówki, mimo to nie jestem w stanie przekroczyć tego krytycznego momentu, by zarabiać na nich sensowne pieniądze. A jako że najprościej dorobić wykonując strony i aplikacje dla innych, postanowiłem pare miesięcy się na tym skupić, by zgromadzić fundusze na dalszy rozwój moich projektów.
Wiadomo, że w takim przypadku efektywność jest niesamowicie istotna – im więcej projektów uda mi się zrealizować w tym samym okresie, tym więcej zarobię. Zaczynając pracę nad kolejnym projektem (Portal licytacji usług – Alleuslugi.pl) stwierdziłem że mam dosyć już pisania po raz n-ty klas obsługujących bazę danych, generowanie i walidację formularzy itp. i skorzystam z gotowych rozwiązań. Prosty framework, który napisałem na potrzeby kilku projektów przestał mi się podobać – generował zbyt duży narzut, głównie za sprawą braku systemu szablonów typu Smarty, porzuciłem go więc już jakiś czas temu.
Poświęciłem godzinę na pobierzne przejrzenie dostępnych dla PHP Frameworków. Moją szczególną uwagę zwrócił CakePHP – opisany był jako prosty, efektywny, z krótka krzywą uczenia się (to było dla mnie bardzo ważne – czas na nauczenie się frameworka na poziomie pozwalającym na stworzenie projektu wraz z wykonaniem go powinien być krótszy niż czas potrzebny na zrealizowanie projektu bez korzystania z tegotypu narzędzi). Zaryzykowałem.
Ściągnąłem CakePHP, przejrzałem oficjalny tutorial i zabrałem się za tworzenie mojej aplikacji (wcześniej miałem już przygotowaną bazę danych). Po krótkim czasie dysponowałem skryptem, który działał i był całkiem dobrym początkiem. To fenomen zasady Convention over Configuration stosowanej w CakePHP – stosując określoną konwencję nazewnictwa tabel, kolumn, klas itp. konfiguracja jest ograniczona do minimum! Nigdzie w kodzie nie podaję nazw tabel, kolumn, wszystko jest określane domyślnie. Innymi słowy – klasa Category sama wie, że dane ma pobierać z tabeli categories Jedyne co trzeba określić w kodzie to zależności między tabelkami – to chyba naturalna konsekwencja tego, że nie da się informacji o kluczach obcych łatwo wyciągnąć z MySQLa. To było dla mnie niesamowite. Po kilku godzinach nauki połączonej z tworzeniem dysponowałem całkiem funkcjonalną aplikacją. Gdyby nie CakePHP, grzebałbym się w kodzie bez żadnych widocznych obiektów…
Wiele ideii wykorzystanych w CakePHP było mi wcześniej znanyc, często też je stosowałem w swoich skryptach – jak choćby model MVC, mapowanie obiektowo-relacyjne czy nawet nieświadomie stosowane elementy zasacy Convention over Coniguration. To wszystko jednak połączone w jednym frameworku tworzy mieszankę wybuchową – w ciągu 3 dni i 20 godzin pracy mam w pełni zrealizowaną funkcjonalność projektu. Wcześniejszy, optymistyczny plan zakładał zrobienie tego w 5 dni i 40 godzin, pesymistyczny – 10 dni i 80 godzin.
Pozostaje mi jeszcze tylko podpiąć do tego grafikę. Na szczęście, dzięki wykorzystaniu MVC w CakePHP będzie to sama przyjemność
