Polecam szukać informacji na listach mailingowych PostgreSQL na temat projektowania z wieloma dzierżawcami. Odbyło się tam wiele dyskusji, a odpowiedź sprowadza się do „to zależy”. Istnieją kompromisy między gwarantowaną izolacją, wydajnością i konserwacją.
Powszechnym podejściem jest użycie jednej bazy danych, ale jednego schematu (przestrzeń nazw) na klienta z taką samą strukturą tabeli w każdym schemacie oraz udostępnionym lub wspólnym schematem dla danych, które są takie same we wszystkich z nich. Schemat PostgreSQL jest jak „baza danych” MySQL, ponieważ można wykonywać zapytania w różnych schematach, ale są one domyślnie izolowane. Mając dane klientów w osobnym schemacie, możesz użyć search_path
ustawienie, zwykle przez ALTER USER
customername SET search_path = 'customerschema, sharedschema'
aby upewnić się, że każdy klient widzi swoje dane i tylko swoje dane.
Aby uzyskać dodatkową ochronę, należy REVOKE
ALL FROM SCHEMA customerschema FROM public
następnie GRANT
ALL ON SCHEMA customerschema TO thecustomer
więc tylko oni mają do niego dostęp, robiąc to samo z każdym ze swoich stołów. Twoja pula połączeń może wtedy zalogować się na stałe konto użytkownika, które nie ma nie GRANT
ed dostęp do dowolnego schematu klienta, ale ma prawo do SET ROLE
zostać dowolnym klientem. (Zrób to, przyznając im członkostwo w każdej roli klienta z ustawionym NOINHERIT, więc prawa muszą być wyraźnie zgłaszane przez SET ROLE
). Połączenie powinno natychmiast SET ROLE
klientowi, pod którym obecnie działa. Pozwoli to uniknąć narzutów związanych z tworzeniem nowych połączeń dla każdego klienta przy jednoczesnym zachowaniu silnej ochrony przed błędami programisty prowadzącymi do uzyskania dostępu do niewłaściwych danych klienta. Dopóki pula wykonuje DISCARD ALL
i/lub RESET ROLE
przed przekazaniem połączeń następnemu klientowi, zapewni to bardzo silną izolację bez frustracji związanych z poszczególnymi połączeniami na użytkownika.
Jeśli środowisko Twojej aplikacji internetowej nie ma wbudowanej przyzwoitej puli połączeń (powiedzmy, że używasz PHP z trwałymi połączeniami), to naprawdę trzeba umieścić dobrą pulę połączeń
w każdym razie między Pg a serwerem WWW, ponieważ zbyt wiele połączeń z backendem obniży twoją wydajność. PgBouncer
i PgPool-II
są najlepszymi opcjami i mogą z łatwością zająć się wykonaniem DISCARD ALL
i RESET ROLE
dla Ciebie podczas przekazywania połączenia.
Główną wadą tego podejścia jest obciążenie związane z utrzymaniem tak wielu tabel, ponieważ podstawowy zestaw nieudostępnionych tabel jest klonowany dla każdego klienta. Będzie się sumować w miarę wzrostu liczby klientów, do punktu, w którym sama liczba tabel do zbadania podczas uruchamiania automatycznego odkurzania staje się kosztowna, a każda operacja, która skaluje się na podstawie całkowitej liczby tabel w bazie danych, spowalnia. Jest to większy problem, jeśli myślisz o wielu tysiącach lub dziesiątkach tysięcy klientów w tej samej bazie danych, ale zdecydowanie zalecamy wykonanie kilku testów skalowania z tym projektem przy użyciu fikcyjnych danych przed zatwierdzeniem go.
Idealnym podejściem mogą być pojedyncze tabele z automatyczną kontrolą bezpieczeństwa na poziomie wiersza, kontrolującą widoczność krotek, ale niestety jest to coś, czego PostgreSQL jeszcze nie ma. Wygląda na to, że jest w drodze dzięki pracy SEPostgreSQL dodając odpowiednią infrastrukturę i API, ale nie jest to w wersji 9.1.