Hoe scheidt SaaS bedrijf data van klanten
Bijvoorbeeld een online boekhoudsysteem, online reserveringssysteem, etc.
Zo'n bedrijf heeft meerdere klanten, dus de partijen die een dienst afnemen (meestal bedrijven).
Ik ga even uit van een standaard situatie bij een PHP applicatie.
Typisch gezien hebben de applicaties een bijbehorende database, met daarin database tabellen.
Als we een normale applicatie ontwikkelen zoals bijvoorbeeld PHPHulp, dan wordt onderscheid tussen data gemaakt met bijvoorbeeld user id's. Daar mee wil ik zeggen, de gegevens staan in een database en de gegevens worden 'gescheiden' (of juist gekoppeld) door relaties. Bijvoorbeeld een forum post heeft een topic_id, een post heeft een user_id, enz.
Bij een SaaS applicatie is dit wat complexer. Het hoogste niveau van scheiden van gegevens is het klantniveau van de dienst.
Met andere woorden, een bedrijf (klant) maakt gebruik van het online boekhoudprogramma. Alle gegevens in de applicatie moeten worden geassocieerd met die afnemer van de dienst. In dat bedrijf zitten weer medewerkers/gebruikers, wat de volgende scheiding is, en daarna heb je nog veel meer relaties.
Je zou dus kunnen zeggen dat als je één database hebt voor die hele SaaS applicatie, dat hierin gegevens van alle SaaS klanten tegelijkertijd in zitten.
In theorie zou dit prima kunnen. Maar mocht er ooit iets gebeuren (een nog niet ontdekte bug door een nieuwe feature), dan kan het zomaar zijn dat gegevens van verschillende SaaS klanten door elkaar komen. (Een afnemer van een reserveringssysteem ziet ineens reserveringen van een totaal ander bedrijf)
Het lijkt me ook meer gedoe in het ontwikkelen, want letterlijk bij elke query naar de database moet je iets doen als company_id = 1234. Als je dit in één query zou vergeten, heb je al een vet probleem.
Daarnaast wordt ook toegangscontrole/rechten meer werk om te implementeren, want een request met een id van een stuk data, kan wel elk id bevatten. Je moet controleren of dat stukje data bij de SaaS afnemer hoort, en dan gaat het pas verder met de rest. Dus de eigenlijke business logic van de applicatie.
Wordt dit opgelost door letterlijk een hele kopie van de applicatie te draaien voor elke afnemer van de dienst?
Dit lijkt me dan weer erg duur. De applicatie software (PHP code) is in principe voor iedereen hetzelfde, en zou dus misschien wel duizenden keren precies gedupliceerd worden op de server(s).
Of wordt voor elke afnemer een aparte database gemaakt?
Hoe werkt dit?
Gewijzigd op 15/11/2022 22:34:26 door Mark Hogeveen
Daarvoor is goed automatiseren een kunst. Je zou bijv. iets kunnen ontwikkelen dat een query uitvoert en altijd die company_id automatisch toevoegt, zodat je dat niet zelf hoeft te doen.
en in die query() functie gebeurt dan zoiets:
Code (php)
1
2
3
4
5
6
2
3
4
5
6
<?php
$sql = $sql . ' WHERE company_id=' . $company->getId();
execute_query($sql);
?>
$sql = $sql . ' WHERE company_id=' . $company->getId();
execute_query($sql);
?>
Het gaat er even niet om of dit kloppend is. Het gaat puur om het idee. Op het moment dat een klant inlogt, kun je kijken bij welk bedrijf hij hoort en dat ergens opslaan. En op het moment dat je een query uitvoert, kun je dan geautomatiseerd de company_id ophalen.
De verschillende strategieën in oplopende gradatie van veiligheid:
1. Je voegt een klant ID toe aan elke tabel, en je neemt dit mee in al je queries
2. Je voegt een klant ID toe aan elke tabel en je regel autorisatie in de database
3. Je maakt per klant een schema in de database
4. Je maakt per klant een eigen database
5. Je maakt per klant een eigen database cluster (service)
6. Je maakt per klant een eigen database server
Optie 1 is veel werk en foutgevoelig.
Optie 2 is minder werk, maar nog steeds foutgevoelig wanneer Functioneel Beheer het fout doet.
Optie 3 is al beter, deze kom je vaak tegen bij shared hosting. Alles zit dan wel in dezelfde database, dus bij bugs of iets dergelijks hang je.
Optie 4 is als optie 3, maar het hangt er vanaf of je MySQL/MariaDB gebruikt of een betere database als PostgreSQL. PostgreSQL maakt naast schema's nog een onderscheid in databases, MySQL/MariaDB kan dat niet.
Optie 5 is nog beter, omdat daarmee data-autorisaties en databases volledig gescheiden zijn in aparte services, met elk een eigen poortnummer. Als dan 1 cluster er uit klapt (te weinig schijfruimte, hangende transactie, of MySQL die vastloopt op ZFS, etc.) dan hebben andere klanten daar geen last van.
Optie 6 is de beste. Het is als optie 5 maar dan met meerdere (virtuele) machines. Door de databases van meerdere klanten te spreiden over meerdere machines hebben ze geen last van elkaar qua performance, en is er meer keuze in software en bestandssystemen. Het andere belangrijke voordeel is dat ze via netwerk gescheiden zijn, waardoor er meer veiligheid kan worden ingebouwd door verkeer te filteren en te monitoren.
Wat betreft de PHP-applicatie; die zet je op een (liefst gescheiden) applicatie-server voor een 2-tier applicatie. Je kunt dan per URL een andere database laten selecteren.
Verdere performance kan worden behaald met een proxy-server voor SSL-offloading, en wanneer de applicatieserver vol loopt is het nodig om meerdere applicatieservers te hebben. Dat kan je doen per klant of aantal klanten, of je zet meerdere applicaties in een pool met load balancing.
En mocht een applicatie kritiek zijn en een hoge beschikbaarheid te hebben, dan moeten idealiter zowel de database servers als de webserver en load balancer uitgevoerd met High Availability (HA). Bijvoorbeeld PostgreSQL ondersteunt dit vanuit 'streaming replication', je hebt dan een reserve database server die synchroon loopt met de 'master', en als er één uitvalt heb je nog een andere database server met dezelfde data.
Overigens moeten dan gegevens altijd redundant worden opgeslagen in een RAID configuratie groter dan 1 (geen JBOD), als er dan een keer een harde schijf stuk gaat blijft het syteem gewoon doorlopen. Je kunt harde schijven 'hot swappable' uit een NAS of SAN trekken en er nieuwe in zetten, dan blijft het systeem gewoon door draaien. Dit laatste punt is overigens iets wat een hostingpartij standaard aan zou moeten bieden, dat hoef je niet zelf te doen als je het in de cloud op slaat. Maar met een private cloud, die je zelf beheert, is dat wel van belang.
Als je dit voor één organisatie hebt opgelost, wordt het doorgaans makkelijker om het voor meerdere organisaties door te voeren. Afdelingen of functiegroepen kun je namelijk zien als organisaties binnen een organisatie.
Onder grootschalige SaaS-oplossingen zijn microservices populair. Daarbij heb je niet meer één monoliet-database voor alles en iedereen, maar is elke microservice (onder ideale omstandigheden) een self-contained system met volledig autonome code en zelfstandige opslag.
Ik ben altijd voorstander geweest van autorisaties op de data, maar met het scheiden van FB (een per dochterorganisatie, en centraal FB voor de moederorganisatie en kleinere dochterorganisaties) lijkt er meer nodig dan PostgreSQL autorisaties.
Je moet idealiter FB kunnen delegeren naar de lagere regionen die het voor zichzelf mogen inregelen.
Wat zijn mogelijke oplossingen voor dit vraagstuk? PostgreSQL is daarbij een onveranderlijk gegeven.
Bovendien vraag ik me af of het ophalen / schrijven van data niet onnodig trager wordt als je één database hebt waar álle klanten hun gegevens in staan, eigenlijk ook nog eens van alle klanten door elkaar.
Om dit goed te doen, besef ik me nu dat er dus wel wat bij komt kijken. Je zou eigenlijk een soort virtuele server / VM moeten hebben voor elke klant, tenminste dat lijkt me een betere oplossing. Dankjewel voor de reacties.
Gewijzigd op 21/11/2022 20:38:56 door Mark Hogeveen
Kortom, het is dus een afweging van 'risico beperken' versus onderhoud. Als je genoeg geld en tijd hebt, kun je werken met losse databases en wijzigingen automatiseren.
Gewijzigd op 22/11/2022 10:55:15 door Aad B