Gdy tworzymy pierwszą aplikację webową, która umożliwia upload plików przeważnie lądują one lokalnie w pewniej lokalizacji. Gdy druga aplikacja potrzebuje dostępu do tych plików wystarczy podać ścieżkę. Problemy zaczynają się gdy aplikacji jest kilka i rozmieszczonych na kilku serwerach. Można korzystać z sieciowych systemów plików ale to często nie jest zbyt wygodne - ciężko odpowiednio ustawić uprawnienia by pewne aplikacje miały dostęp do zapisu plików a inne nie, trzeba skonfigurować dany katalog w kilku miejscach w konfiguracji serwera WWW aby serwować pliki itp…
Jeżeli w utrzymaniu swoich aplikacji dociera się do takiego momentu to kolejne pomysły zakładają wykorzystanie bazy danych do przechowywania plików. Ale chwila googlania i już wiemy że bazy typu SQL średnio radzą sobie z przetwarzaniem tak dużych rekordów jak pliki. Kolejny etap to sprawdzenie co mogą nam zaoferować bazy NoSQL.
W tym miejscu przeczytałem wiele różnych artykułów i ostatecznie zastanawiałem się czy wybrać MongoDB czy CouchDB. Oba projekty są bardzo podobne a główną ich zaletą jest łatwość wykorzystania w istniejących aplikacjach webowych. Tutaj szczególnie CouchDB wypada bardzo dobrze bo zarządzanie i dostęp do bazy odbywa się standardowym protokołem HTTP - polecenia wydaje się POST’ami, a dane pobiera GET’ami. Dzięki takiej budowie łatwo można schować CouchDB za reverse proxy i serwować np. pliki uploadowane przez użytkowników wprost z bazy - bez dorabiania dodatkowych interfejsów. Bardzo łatwo też obsługuje się bazę z poziomu aplikacji AJAX. Więc w moim przypadku wypadło na CouchDB.
Instalacja
Instalacja na Debianie jest banalna i sprowadza się do:
apt-get install -y couchdb
TADAM! Mamy działające CouchDB. Domyślnie baza nasłuchuje na adresie 127.0.0.1
i porcie 5984
.
Dodatkowo Couch posiada webowy interfejs (zwany Futon’em) zarządzający dostępny na tym samym porcie pod adresem, np. http://127.0.0.1:5984/_utils/
Optymalizacja
NODELAY
W moim przypadku CouchDB służy do przechowywania zarówno bardzo wielu małych plików, jak i kilku całkiem sporych. W przypadku bardzo małych plików CouchDB w wersji 0.11 czeka z wysłaniem odpowiedzi od razu bo być może uda się “dorzucić coś jeszcze”. Takie zachowanie może powodować opóźnienia przy pobieraniu małych plików, warto więc zmienić w pliku /etc/couchdb/local.ini
taką opcję:
[httpd]
socket_options = [{nodelay, true}]
Ustawienie opcji TCP NODELAY wyłączy opóźnienie przy wysyłaniu małych plików.
Identyfikatory
Warto zastanowić się nad długością i schematem identyfikatorów dla rekordów. Domyślnie mają one 32 bajty co przy małej liczbie elementów w bazie jest mocną przesadą. Rozmiar identyfikatorów znacznie wpływa na rozmiar bazy i jej wydajność - dlatego czasem warto opracować własny schemat generowanych identyfikatorów. Przykładowo jeśli identyfikator będzie generowany z cyfr oraz dużych i małych liter to dla 3 znaków możemy wygenerować identyfikatory dla ponad 260 tys. elementów, dla 4 znaków już ponad 14 milionów co powinno wystarczyć dla średniej wielkości bazy.
Ustawienia bezpieczeństwa
Trochę mnie zaskoczyło podejście do bezpieczeństwa w bazie CouchDB - domyślnie po instalacji baza działa w trybie Admin Party, czyli każda osoba która wejdzie do zarządzania bez logowania ma uprawnienia administratora 😄
Mnie ten stan rzeczy nie bardzo odpowiadał więc:
- odpalamy interfejs zarządzający - Futon i w prawym dolnym rogu szukamy tekstu: “Welcome to Admin Party! Everyone is admin. Fix this” - klikamy na “Fix this”,
- w okienku które się pojawi podajemy login i hasło administratora.
Po ustawieniu konta administratora dalsze musimy zadbać o ustawienie odpowiednich uprawnień dla każdej nowo tworzonej bazy, czyli bazy tworzą się dostępem dla wszystkich ale możemy ograniczyć np. zapis/odczyt dla pewnych grup użytkowników.
Zabezpieczenie bazy użytkowników
Po ustawieniu pierwszego użytkownika kolejna rzecz, o którą powinniśmy zadbać do dostępna dla każdego do odczytu baza użytkowników. Najlepiej gdy tylko administratorzy będą mieli do niej dostęp. By to osiągnąć:
- w Futonie wchodzimy do bazy _users i klikamy przycisk “Security” na górze strony,
- w okienku które się pojawi w polu Readers -> Roles (pole na samym dole) wpisujemy
["admin"]
Od teraz tylko administratorzy mają dostęp do bazy _users.
Ustawienie bazy jako tylko do odczytu
To co chciałem osiągnąć korzystając z CouchDB to jakieś repozytorium, do którego wrzucać mogą wybrańcy a czytać wszyscy (np. taki CDN dla stronki itp) ale otrzymanie takiego rezultatu jest nieco… nieintuicyjne. By to osiągnąć:
- w bazie którą chcemy ustawić jako tylko do odczytu wchodzimy w Security i w polu Admin Roles (drugie z góry) wpisujemy
["admin"]
- to zablokuje dostęp do panelu Security i możliwości modyfikowania design dokumentów, nadal możliwe jest jednak dodawanie, modyfikowani i kasowanie dokumentów, - by zablokować dostęp do zapisu w CouchDB trzeba wykorzystać funkcję
validate_doc_update
która będzie wywoływana przy każdej próbie dostępu do pojedynczego dokumentu, by z niej skorzystać tworzymy nowy pusty dokument, - zmieniamy pole
_id
dokumentu na_design/auth
- dodajemy pole nazwane
language
z wartościąjavascript
- dodajemy kolejne pole nazwane
validate_doc_update
z wartością:
function(newDoc, oldDoc, userCtx) {
if (userCtx.roles.indexOf('_admin') !== -1) {
return;
} else {
throw({forbidden: 'Nie jesteś administratorem!'});
}
}
- zapisujemy dokument klikając na “Save Document”