Ik raad aan om op de PostgreSQL-mailinglijsten te zoeken naar informatie over multi-tenanted design. Er is daar veel discussie geweest en het antwoord komt neer op "het hangt ervan af". Er zijn overal afwegingen tussen gegarandeerde isolatie, prestaties en onderhoudbaarheid.
Een gebruikelijke benadering is het gebruik van één enkele database, maar één schema (naamruimte) per klant met dezelfde tabelstructuur in elk schema, plus een gedeeld of gemeenschappelijk schema voor gegevens dat overal hetzelfde is. Een PostgreSQL-schema is als een MySQL-"database" in die zin dat u in verschillende schema's kunt zoeken, maar ze zijn standaard geïsoleerd. Met klantgegevens in een apart schema kunt u de zoekpad
instelling, meestal via GEBRUIKER VERANDEREN
klantnaam SET search_path ='klantschema, gedeeldschema'
om ervoor te zorgen dat elke klant zijn gegevens ziet en alleen zijn gegevens.
Voor extra bescherming moet u REVOKE
ALLES VAN SCHEMA klantschema VAN openbaar
dan GRANT
ALLES OP SCHEMA klantschema AAN de klant
dus zij zijn de enige die er toegang toe hebben en doen hetzelfde met elk van hun tafels. Uw verbindingspool kan dan inloggen met een vast gebruikersaccount dat nee . heeft SUBSIDIE
ed toegang tot elk klantschema, maar heeft het recht op ROL INSTELLEN
om enige klant te worden. (Doe dat door ze lidmaatschap te geven van elke klantrol met NOINHERIT-set, zodat rechten expliciet moeten worden geclaimd via SET ROLE
). De verbinding moet onmiddellijk SET ROLE
voor de klant waar het momenteel mee werkt. Zo vermijdt u de overhead van het maken van nieuwe verbindingen voor elke klant, terwijl u een sterke bescherming behoudt tegen programmeerfouten die leiden tot toegang tot de gegevens van de verkeerde klant. Zolang de pool een DISCARD ALL
en/of een RESET ROL
voordat u verbindingen uitdeelt aan de volgende klant, geeft dat u een zeer sterke isolatie zonder de frustratie van individuele verbindingen per gebruiker.
Als uw web-app-omgeving geen behoorlijke ingebouwde verbindingspool heeft (bijvoorbeeld, u gebruikt PHP met permanente verbindingen), dan echt moet een goede verbindingspool
plaatsen tussen Pg en de webserver, omdat te veel verbindingen met de backend uw prestaties schaden. PgBouncer
en PgPool-II
zijn de beste opties, en kunnen handig zorgen voor het uitvoeren van de ALLES VERWIJDEREN
en RESET ROL
voor u tijdens de overdracht van de verbinding.
Het belangrijkste nadeel van deze aanpak is de overhead die gepaard gaat met het onderhouden van zoveel tabellen, aangezien uw basisset van niet-gedeelde tabellen voor elke klant wordt gekloond. Het zal oplopen naarmate het aantal klanten groeit, tot het punt waarop het enorme aantal tafels dat moet worden onderzocht tijdens autovacuüm-runs duur begint te worden en waar elke bewerking die wordt geschaald op basis van het totale aantal tabellen in de DB vertraagt. Dit is meer een probleem als u denkt vele duizenden of tienduizenden klanten in dezelfde database te hebben, maar ik sterk raad u aan een aantal schaaltests uit te voeren met dit ontwerp met behulp van dummy-gegevens voordat u zich eraan vastlegt.
De ideale aanpak zijn waarschijnlijk enkele tabellen met automatische beveiliging op rijniveau die de zichtbaarheid van tuple controleert, maar helaas heeft PostgreSQL dat nog niet. Het lijkt erop dat het onderweg is dankzij het SEPostgreSQL-werk door geschikte infrastructuur en API's toe te voegen, maar het is niet in 9.1.