Hoe te schalen van 1 naar 100 gebruikers

Veel startups hebben dit meegemaakt: elke dag registreren zich massa's nieuwe gebruikers en het ontwikkelingsteam heeft moeite om de service draaiende te houden.

Het is een leuk probleem om te hebben, maar er is weinig duidelijke informatie op internet over hoe je een webapplicatie zorgvuldig kunt opschalen van niets naar honderdduizenden gebruikers. Meestal zijn er brandoplossingen of knelpuntoplossingen (en vaak beide). Daarom gebruiken mensen nogal clichématige technieken om hun amateurproject op te schalen tot iets heel serieus.

Laten we proberen de informatie te filteren en de basisformule op te schrijven. We gaan onze nieuwe fotodeelsite Graminsta stap voor stap opschalen van 1 naar 100 gebruikers.

Laten we opschrijven welke specifieke acties moeten worden ondernomen als het publiek toeneemt tot 10, 100, 1000, 10 en 000 mensen.

1 gebruiker: 1 machine

Bijna elke applicatie, of het nu een website of een mobiele applicatie is, heeft drie belangrijke componenten:

  • API
  • database
  • client (mobiele applicatie zelf of website)

De database slaat persistente gegevens op. De API dient verzoeken naar en rond deze gegevens. De client verzendt gegevens naar de gebruiker.

Ik kwam tot de conclusie dat het veel gemakkelijker is om over het schalen van een applicatie te praten als, vanuit architectonisch oogpunt, de client- en API-entiteiten volledig gescheiden zijn.

Wanneer we voor het eerst beginnen met het bouwen van een applicatie, kunnen alle drie de componenten op dezelfde server worden uitgevoerd. In sommige opzichten is dit vergelijkbaar met onze ontwikkelomgeving: één ingenieur voert de database, API en client op dezelfde machine uit.

In theorie zouden we het in de cloud kunnen implementeren op een enkele DigitalOcean Droplet- of AWS EC2-instantie, zoals hieronder weergegeven:
Hoe te schalen van 1 naar 100 gebruikers
Dat gezegd hebbende, als er meer dan één gebruiker op een site is, is het bijna altijd zinvol om een ​​databaselaag toe te wijzen.

10 gebruikers: de database naar een apart niveau verplaatsen

Het opsplitsen van de database in beheerde services zoals Amazon RDS of Digital Ocean Managed Database zal ons lange tijd goed van pas komen. Het is iets duurder dan zelfhosting op een enkele machine of EC2-instantie, maar met deze diensten krijg je een heleboel nuttige uitbreidingen uit de doos die in de toekomst van pas zullen komen: back-up in meerdere regio's, replica's lezen, automatisch back-ups en meer.

Zo ziet het systeem er nu uit:
Hoe te schalen van 1 naar 100 gebruikers

100 gebruikers: de client naar een apart niveau verplaatsen

Gelukkig vonden onze eerste gebruikers onze applicatie erg leuk. Het verkeer wordt stabieler, dus het is tijd om de client naar een apart niveau te verplaatsen. het zou genoteerd moeten worden dat scheiding entiteiten is een belangrijk aspect bij het bouwen van een schaalbare applicatie. Naarmate een deel van het systeem meer verkeer ontvangt, kunnen we dit verdelen om te bepalen hoe de service wordt geschaald op basis van specifieke verkeerspatronen.

Daarom beschouw ik de client graag los van de API. Dit maakt het heel gemakkelijk om na te denken over ontwikkelen voor meerdere platforms: internet, mobiel internet, iOS, Android, desktopapplicaties, services van derden, enz. Het zijn allemaal gewoon klanten die dezelfde API gebruiken.

Nu vragen onze gebruikers bijvoorbeeld het vaakst om een ​​mobiele applicatie vrij te geven. Als u de client- en API-entiteiten scheidt, wordt dit eenvoudiger.

Zo ziet zo’n systeem eruit:

Hoe te schalen van 1 naar 100 gebruikers

1000 gebruikers: load balancer toevoegen

Het wordt beter. Graminsta-gebruikers uploaden steeds meer foto's. Ook het aantal inschrijvingen groeit. Onze enige API-server heeft moeite met het bijhouden van al het verkeer. Meer ijzer nodig!

Load balancer is een zeer krachtig concept. Het belangrijkste idee is dat we een load balancer vóór de API plaatsen en dat deze het verkeer naar individuele service-instances verdeelt. Op deze manier schalen we horizontaal, wat betekent dat we meer servers met dezelfde code toevoegen, waardoor het aantal verzoeken dat we kunnen verwerken toeneemt.

We gaan aparte load balancers voor de webclient en voor de API plaatsen. Dit betekent dat u meerdere instanties kunt uitvoeren met API-code en webclientcode. De load balancer stuurt verzoeken naar de server die minder belast is.

Hier krijgen we nog een belangrijk voordeel: redundantie. Wanneer één instantie faalt (misschien overbelast of gecrasht), blijven er andere over die blijven reageren op inkomende verzoeken. Als er maar één exemplaar zou werken, zou bij een storing het hele systeem crashen.

De load balancer biedt ook automatische schaling. We kunnen het configureren om het aantal instanties vóór de piekbelasting te vergroten en te verlagen wanneer alle gebruikers slapen.

Met een load balancer kan het API-niveau vrijwel onbeperkt worden geschaald, door simpelweg nieuwe instances toe te voegen naarmate het aantal verzoeken toeneemt.

Hoe te schalen van 1 naar 100 gebruikers

Opmerking. Op dit moment lijkt ons systeem sterk op wat PaaS-bedrijven zoals Heroku of Elastic Beanstalk op AWS kant-en-klaar aanbieden (en daarom zijn ze zo populair). Heroku plaatst de database op een aparte host, beheert een automatisch schalende load balancer en stelt u in staat de webclient afzonderlijk van de API te hosten. Dit is een goede reden om Heroku te gebruiken voor projecten in een vroeg stadium of voor startups: je krijgt alle basisdiensten kant-en-klaar.

10 gebruikers: CDN

Misschien hadden we dit al vanaf het begin moeten doen. Het verwerken van verzoeken en het accepteren van nieuwe foto's begint onze servers te zwaar te belasten.

In dit stadium moet u een cloudservice gebruiken voor het opslaan van statische inhoud - afbeeldingen, video's en nog veel meer (AWS S3 of Digital Ocean Spaces). Over het algemeen moet onze API voorkomen dat er zaken als het weergeven van afbeeldingen en het uploaden van afbeeldingen naar de server worden afgehandeld.

Een ander voordeel van cloudhosting is de CDN (AWS noemt deze add-on Cloudfront, maar veel cloudopslagproviders bieden dit out of the box aan). Het CDN slaat onze afbeeldingen automatisch op in verschillende datacentra over de hele wereld.

Hoewel ons hoofddatacenter zich mogelijk in Ohio bevindt, zal de cloudprovider, als iemand om een ​​afbeelding uit Japan vraagt, een kopie maken en deze opslaan in hun Japanse datacenter. De volgende persoon die dit beeld in Japan aanvraagt, zal het veel sneller ontvangen. Dit is belangrijk als we met grote bestanden werken, zoals foto's of video's, die veel tijd nodig hebben om te downloaden en over de hele planeet te verzenden.

Hoe te schalen van 1 naar 100 gebruikers

100 gebruikers: de datalaag opschalen

CDN heeft veel geholpen: het verkeer groeit op volle snelheid. De beroemde videoblogger Mavid Mobrick heeft zich zojuist bij ons geregistreerd en zijn ‘verhaal’ gepost, zoals ze zeggen. Dankzij de load balancer wordt het CPU- en geheugengebruik op de API-servers laag gehouden (tien API-instances actief), maar we beginnen veel time-outs te krijgen bij verzoeken... waar komen deze vertragingen vandaan?

Als we een beetje in de statistieken duiken, zien we dat de CPU op de databaseserver voor 80-90% geladen is. We zitten op de limiet.

Het schalen van de datalaag is waarschijnlijk het moeilijkste deel van de vergelijking. API-servers verwerken staatloze verzoeken, dus we voegen eenvoudigweg meer API-instanties toe. Neus meerderheid databases kunnen dit niet. We zullen het hebben over populaire relationele databasebeheersystemen (PostgreSQL, MySQL, enz.).

caching

Een van de gemakkelijkste manieren om de prestaties van onze database te verbeteren is door een nieuw onderdeel te introduceren: de cachelaag. De meest gebruikelijke cachemethode is een sleutelwaarderecordarchief in het geheugen, zoals Redis of Memcached. De meeste clouds hebben een beheerde versie van deze services: Elasticache op AWS en Memorystore op Google Cloud.

Een cache is handig wanneer een service veel herhaalde oproepen naar de database doet om dezelfde informatie op te halen. In wezen hebben we slechts één keer toegang tot de database, slaan we de informatie op in de cache en raken we deze niet meer aan.

In onze Graminsta-service vraagt ​​de API-server bijvoorbeeld elke keer dat iemand naar de profielpagina van de ster Mobrik gaat, de database om informatie uit zijn profiel. Dit gebeurt keer op keer. Omdat de profielinformatie van Mobrik niet bij elk verzoek verandert, is deze uitstekend geschikt voor caching.

We slaan de resultaten uit de database in Redis op sleutel op in de cache user:id met een geldigheidsduur van 30 seconden. Als iemand nu naar het profiel van Mobrik gaat, controleren we eerst Redis, en als de gegevens daar zijn, zetten we deze eenvoudig rechtstreeks vanuit Redis over. Nu laden verzoeken aan het meest populaire profiel op de site onze database praktisch niet.

Een ander voordeel van de meeste cachingdiensten is dat ze gemakkelijker te schalen zijn dan databaseservers. Redis heeft een ingebouwde Redis Cluster-modus. Vergelijkbaar met een load-balancer1, kunt u uw Redis-cache over meerdere machines verdelen (indien nodig over duizenden servers).

Bijna alle grootschalige applicaties maken gebruik van caching; het is een absoluut integraal onderdeel van een snelle API. Snellere verwerking van zoekopdrachten en productievere code zijn allemaal belangrijk, maar zonder cache is het vrijwel onmogelijk om een ​​service op te schalen naar miljoenen gebruikers.

Lees replica's

Wanneer het aantal queries op de database enorm is toegenomen, kunnen we nog een ding doen: leesreplica's toevoegen aan het databasebeheersysteem. Met de hierboven beschreven managed services kan dit in één klik. De leesreplica blijft actueel in de hoofddatabase en is beschikbaar voor SELECT-instructies.

Dit is ons systeem nu:

Hoe te schalen van 1 naar 100 gebruikers

Volgende stappen

Naarmate de applicatie blijft schalen, zullen we de services blijven scheiden om ze onafhankelijk van elkaar te schalen. Als we bijvoorbeeld Websockets gaan gebruiken, is het zinvol om de Websockets-verwerkingscode in een aparte service te plaatsen. We kunnen het op nieuwe instances plaatsen achter onze eigen load balancer, die kan op- en afschalen op basis van open Websockets-verbindingen en ongeacht het aantal HTTP-verzoeken.

We zullen ook doorgaan met het bestrijden van beperkingen op databaseniveau. Het is in dit stadium dat het tijd is om databasepartitionering en -sharding te bestuderen. Beide benaderingen vereisen extra overhead, maar stellen u in staat de database vrijwel onbeperkt te schalen.

We willen ook een monitoring- en analyseservice zoals New Relic of Datadog installeren. Dit zal u helpen langzame vragen te identificeren en te begrijpen waar verbetering nodig is. Terwijl we opschalen, willen we ons concentreren op het vinden van knelpunten en het elimineren ervan, waarbij we vaak gebruik maken van enkele ideeën uit eerdere secties.

bronnen

Dit bericht is geïnspireerd door een van mijn favoriete berichten over hoge schaalbaarheid. Ik wilde het artikel iets specifieker maken voor de beginfase van projecten en het loskoppelen van één leverancier. Lees zeker even als je geïnteresseerd bent in dit onderwerp.

Voetnoten

  1. Hoewel vergelijkbaar qua belastingverdeling over meerdere instanties, is de onderliggende implementatie van een Redis-cluster heel anders dan die van een load balancer. [opbrengst]

Hoe te schalen van 1 naar 100 gebruikers

Bron: www.habr.com

Voeg een reactie