Hogyan skálázható 1-ről 100 000 felhasználóra

Sok startup átesett ezen: naponta rengeteg új felhasználó regisztrál, a fejlesztőcsapat pedig küzd azért, hogy a szolgáltatás működjön.

Kellemes probléma, de kevés egyértelmű információ található az interneten arról, hogyan lehet gondosan skálázni egy webalkalmazást a semmiből több százezer felhasználóra. Jellemzően vagy tűzvédelmi megoldások, vagy szűk keresztmetszet-megoldások léteznek (és gyakran mindkettő). Ezért az emberek meglehetősen sablonos technikákat alkalmaznak, hogy amatőr projektjüket valami igazán komolyra méretezzenek.

Próbáljuk meg szűrni az információkat és írjuk le az alapképletet. A Graminsta új fotómegosztó oldalunkat lépésről lépésre 1-ről 100 000 felhasználóra bővítjük.

Írjuk le, milyen konkrét lépéseket kell tenni, ha a közönség létszáma 10, 100, 1000, 10 000 és 100 000 főre nő.

1 felhasználó: 1 gép

Szinte minden alkalmazás, legyen az webhely vagy mobilalkalmazás, három kulcsfontosságú összetevőből áll:

  • API
  • adatbázis
  • kliens (maga mobilalkalmazás vagy webhely)

Az adatbázis állandó adatokat tárol. Az API kéréseket szolgál ki ezekhez az adatokhoz és azok körül. A kliens adatokat továbbít a felhasználónak.

Arra a következtetésre jutottam, hogy sokkal könnyebb egy alkalmazás skálázásáról beszélni, ha architekturális szempontból a kliens és az API entitások teljesen elkülönülnek.

Amikor először elkezdünk egy alkalmazást építeni, mindhárom összetevő futtatható ugyanazon a szerveren. Bizonyos tekintetben ez hasonlít a fejlesztői környezetünkhöz: egy mérnök futtatja az adatbázist, az API-t és a klienst ugyanazon a gépen.

Elméletileg telepíthetnénk a felhőben egyetlen DigitalOcean Droplet vagy AWS EC2 példányon, az alábbiak szerint:
Hogyan skálázható 1-ről 100 000 felhasználóra
Ezzel együtt, ha egy webhelyen egynél több felhasználó lesz, szinte mindig van értelme egy adatbázisréteget dedikálni.

10 felhasználó: az adatbázis áthelyezése egy külön szintre

Az adatbázis felosztása felügyelt szolgáltatásokra, mint például az Amazon RDS vagy a Digital Ocean Managed Database, hosszú ideig jól fog szolgálni. Kicsit drágább, mint az önálló üzemeltetés egyetlen gépen vagy EC2-példányon, de ezekkel a szolgáltatásokkal rengeteg hasznos bővítményt kapsz, amelyek a jövőben is jól jöhetnek: többrégiós biztonsági mentés, replikák beolvasása, automatikus biztonsági mentések és még sok más.

Így néz ki most a rendszer:
Hogyan skálázható 1-ről 100 000 felhasználóra

100 felhasználó: a kliens áthelyezése egy külön szintre

Szerencsére első felhasználóinknak nagyon tetszett az alkalmazásunk. A forgalom egyre stabilabb, ezért ideje külön szintre helyezni a klienst. Megjegyzendő elválasztás Az entitások kulcsfontosságú szempont a méretezhető alkalmazás felépítésében. Mivel a rendszer egy része nagyobb forgalmat kap, particionálhatjuk azt, hogy szabályozzuk, hogy a szolgáltatás hogyan skálázódik meghatározott forgalmi minták alapján.

Ezért szeretem úgy gondolni, hogy az ügyfél az API-tól különálló. Ez nagyon megkönnyíti, hogy több platformra is fejlesszen: web, mobil web, iOS, Android, asztali alkalmazások, harmadik féltől származó szolgáltatások stb. Ezek mind ugyanazt az API-t használó kliensek.

Például mostanában felhasználóiink leggyakrabban mobilalkalmazás kiadását kérik. Ha szétválasztja a kliens és az API entitásokat, ez könnyebbé válik.

Így néz ki egy ilyen rendszer:

Hogyan skálázható 1-ről 100 000 felhasználóra

1000 felhasználó: terheléselosztó hozzáadása

A dolgok felfelé néznek. Egyre több fotót töltenek fel a Graminsta felhasználói. A regisztrációk száma is nő. Magányos API-szerverünk nehezen képes lépést tartani a forgalommal. Több vas kell!

A terheléselosztó egy nagyon erős koncepció. A kulcsötlet az, hogy az API elé helyezünk egy terheléselosztót, amely elosztja a forgalmat az egyes szolgáltatáspéldányokhoz. Így vízszintesen skálázunk, vagyis több szervert adunk hozzá ugyanazzal a kóddal, növelve a feldolgozható kérések számát.

Külön terheléselosztókat fogunk elhelyezni a webes kliens és az API előtt. Ez azt jelenti, hogy több API-kódot és webes ügyfélkódot futtató példányt futtathat. A terheléselosztó a kéréseket a kevésbé terhelt szerverhez irányítja.

Itt kapunk egy másik fontos előnyt - a redundanciát. Ha az egyik példány meghibásodik (talán túlterhelt vagy összeomlik), akkor mások maradnak, amelyek továbbra is válaszolnak a bejövő kérésekre. Ha csak egy példány működne, akkor hiba esetén az egész rendszer összeomlana.

A terheléselosztó automatikus méretezést is biztosít. Beállíthatjuk úgy, hogy növelje a példányok számát a csúcsterhelés előtt, és csökkentse azt, amikor minden felhasználó alszik.

A terheléselosztóval az API-szint szinte korlátlanul skálázható, egyszerűen új példányok hozzáadásával, ahogy a kérések száma növekszik.

Hogyan skálázható 1-ről 100 000 felhasználóra

Jegyzet. Jelenleg rendszerünk nagyon hasonlít ahhoz, amit a PaaS-cégek, például a Heroku vagy az Elastic Beanstalk az AWS-en kínálnak (ezért olyan népszerűek). A Heroku külön gazdagépen helyezi el az adatbázist, egy automatikus skálázó terheléselosztót kezel, és lehetővé teszi a webes kliensnek az API-tól elkülönített üzemeltetését. Ez egy nagyszerű ok arra, hogy a Heroku-t korai szakaszban lévő projektekhez vagy induló vállalkozásokhoz használja – az összes alapvető szolgáltatást megkapja a dobozból.

10 000 felhasználó: CDN

Talán már a kezdetektől ezt kellett volna tennünk. A kérések feldolgozása és az új fotók elfogadása kezd túlságosan megterhelni szervereinket.

Ebben a szakaszban egy felhőszolgáltatást kell használnia statikus tartalom - képek, videók és sok más - tárolására (AWS S3 vagy Digital Ocean Spaces). Általában az API-nknak kerülnie kell az olyan dolgok kezelését, mint a képek kiszolgálása és a képek szerverre való feltöltése.

A felhőtárhely másik előnye a CDN (az AWS ezt a kiegészítőt Cloudfrontnak nevezi, de sok felhőalapú tárolási szolgáltató már a dobozból is kínálja). A CDN automatikusan gyorsítótárazza a képeinket a világ különböző adatközpontjaiban.

Bár a fő adatközpontunk Ohióban található, ha valaki képet kér Japánból, a felhőszolgáltató készít egy másolatot, és tárolja azt a japán adatközpontjában. A következő személy, aki ezt a képet Japánban kéri, sokkal gyorsabban megkapja. Ez akkor fontos, ha nagy fájlokkal, például fényképekkel vagy videókkal dolgozunk, amelyek letöltése és továbbítása a bolygón hosszú ideig tart.

Hogyan skálázható 1-ről 100 000 felhasználóra

100 000 felhasználó: az adatréteg skálázása

A CDN sokat segített: a forgalom teljes sebességgel nő. A híres videoblogger, Mavid Mobrick most regisztrált nálunk, és posztolta a „sztoriját”, ahogy mondani szokás. A terheléselosztónak köszönhetően alacsonyan tartják a CPU- és memóriahasználatot az API szervereken (tíz API-példány fut), de kezdünk sok időtúllépést kapni a kéréseknél... honnan jönnek ezek a késések?

Kicsit beleásva a mérőszámokba, azt látjuk, hogy az adatbázisszerver CPU-ja 80-90%-ban le van töltve. A határon vagyunk.

Az adatréteg skálázása valószínűleg az egyenlet legnehezebb része. Az API-kiszolgálók állapot nélküli kéréseket szolgálnak ki, ezért egyszerűen hozzáadunk további API-példányokat. Orr a többség az adatbázisok ezt nem tudják megtenni. Szó lesz a népszerű relációs adatbázis-kezelő rendszerekről (PostgreSQL, MySQL stb.).

gyorsítótárazás

Adatbázisunk teljesítményének növelésének egyik legegyszerűbb módja egy új komponens, a cache réteg bevezetése. A leggyakoribb gyorsítótárazási módszer a memórián belüli kulcsérték rekordtároló, például a Redis vagy a Memcached. A legtöbb felhő rendelkezik ezeknek a szolgáltatásoknak felügyelt verziójával: az Elasticache az AWS-en és a Memorystore a Google Cloudon.

A gyorsítótár akkor hasznos, ha egy szolgáltatás többször is felhívja az adatbázist ugyanazon információk lekérése érdekében. Lényegében csak egyszer férünk hozzá az adatbázishoz, tároljuk az információkat a gyorsítótárban, és többé nem nyúlunk hozzá.

Például a Graminsta szolgáltatásunkban minden alkalommal, amikor valaki a Mobrik sztár profiloldalára lép, az API-szerver lekérdezi az adatbázist a profiljából származó információkért. Ez újra és újra megtörténik. Mivel a Mobrik profilinformációi nem változnak minden kéréssel, így gyorsítótárazáshoz kiválóan alkalmas.

Az eredményeket kulcsonként tároljuk a Redis adatbázisából user:id 30 másodperces érvényességi idővel. Most, ha valaki felmegy Mobrik profiljára, először ellenőrizzük a Redis-t, és ha ott vannak az adatok, egyszerűen átvisszük közvetlenül a Redisből. Most a webhely legnépszerűbb profiljára irányuló kérések gyakorlatilag nem töltik be az adatbázisunkat.

A legtöbb gyorsítótárazási szolgáltatás másik előnye, hogy könnyebben méretezhetők, mint az adatbázis-kiszolgálók. A Redis beépített Redis Cluster móddal rendelkezik. Hasonló a terheléselosztóhoz1, lehetővé teszi Redis gyorsítótárának elosztását több gép között (szükség esetén több ezer szerver között).

Szinte minden nagyszabású alkalmazás gyorsítótárat használ; ez a gyors API szerves része. A gyorsabb lekérdezésfeldolgozás és a produktívabb kód mind fontosak, de gyorsítótár nélkül szinte lehetetlen egy szolgáltatást több millió felhasználóhoz skálázni.

Olvassa el a replikákat

Amikor az adatbázis lekérdezésének száma jelentősen megnőtt, még egy dolog, amit tehetünk, az olvasási replikák hozzáadása az adatbázis-kezelő rendszerhez. A fent leírt felügyelt szolgáltatásokkal ez egy kattintással megtehető. Az olvasott replika aktuális marad a fő adatbázisban, és elérhető a SELECT utasításokhoz.

Íme most a rendszerünk:

Hogyan skálázható 1-ről 100 000 felhasználóra

Következő lépések

Mivel az alkalmazás folyamatosan skálázódik, továbbra is szétválasztjuk a szolgáltatásokat, hogy egymástól függetlenül méretezzük őket. Például, ha elkezdjük a Websockets használatát, akkor célszerű a Websockets feldolgozó kódját egy külön szolgáltatásba húzni. Új példányokra helyezhetjük el saját terheléselosztónk mögé, amely a nyitott Websockets kapcsolatok alapján és a HTTP kérések számától függetlenül skálázható fel és le.

Továbbra is küzdeni fogunk az adatbázis-szintű korlátozások ellen. Itt az ideje, hogy tanulmányozzuk az adatbázis-particionálást és a felosztást. Mindkét megközelítés további többletköltséget igényel, de lehetővé teszi az adatbázis szinte korlátlanul méretezését.

Olyan megfigyelő és elemző szolgáltatást is szeretnénk telepíteni, mint a New Relic vagy a Datadog. Ez segít azonosítani a lassú lekérdezéseket, és megérteni, hol van szükség fejlesztésre. A méretezés során a szűk keresztmetszetek megtalálására és kiküszöbölésére szeretnénk összpontosítani – gyakran az előző szakaszok ötleteinek felhasználásával.

forrás

Ezt a bejegyzést az egyik ihlette kedvenc bejegyzéseim a magas skálázhatóságról. Kicsit konkrétabbá akartam tenni a cikket a projektek kezdeti szakaszaira vonatkozóan, és meg akartam oldani egy szállítótól. Feltétlenül olvassa el, ha érdekel ez a téma.

Lábjegyzetek

  1. Bár hasonló a terheléselosztás tekintetében több példány között, a Redis-fürt mögöttes megvalósítása nagyon különbözik a terheléselosztótól. [Visszatérés]

Hogyan skálázható 1-ről 100 000 felhasználóra

Forrás: will.com

Hozzászólás