GYIK a VKontakte építészetéről és munkájáról

A VKontakte létrehozásának története a Wikipédián található, maga Pavel mondta el. Úgy tűnik, már mindenki ismeri. A HighLoad++ Pavel webhely belső részeiről, architektúrájáról és szerkezetéről mondta még 2010-ben. Azóta sok szerver kiszivárgott, így frissítjük az információkat: felboncoljuk, kiszedjük a belsejét, lemérjük, és megnézzük a VK készüléket műszaki oldalról.

GYIK a VKontakte építészetéről és munkájáról

Alekszej Akulovics (AterCattus) háttérfejlesztő a VKontakte csapatában. A jelentés átirata egy kollektív válasz a gyakran feltett kérdésekre a platform működésével, az infrastruktúrával, a szerverekkel és a köztük lévő interakcióval kapcsolatban, de nem a fejlesztéssel kapcsolatban. a vasról. Külön-külön az adatbázisokról és arról, hogy mi van helyette a VK-val, a naplók gyűjtéséről és a teljes projekt egészének felügyeletéről. Részletek a vágás alatt.



Több mint négy éve foglalkozom mindenféle backenddel kapcsolatos feladattal.

  • Média feltöltése, tárolása, feldolgozása, terjesztése: videó, élő közvetítés, hang, fotók, dokumentumok.
  • Infrastruktúra, platform, fejlesztői figyelés, naplók, regionális gyorsítótárak, CDN, saját RPC protokoll.
  • Integráció külső szolgáltatásokkal: push értesítések, külső hivatkozások elemzése, RSS feed.
  • Kollégáinak segítése különböző kérdésekben, amelyekre a válaszok ismeretlen kódba merülni kell.

Ez idő alatt az oldal számos összetevőjébe beleszóltam. Ezt az élményt szeretném megosztani.

Általános építészet

Minden, mint általában, egy szerverrel vagy szervercsoporttal kezdődik, amely fogadja a kéréseket.

Elülső szerver

Az elülső szerver HTTPS-en, RTMP-n és WSS-en keresztül fogad kéréseket.

HTTPS - ezek a webhely fő és mobil webes verzióira vonatkozó kérések: vk.com és m.vk.com, valamint API-nk egyéb hivatalos és nem hivatalos kliensei: mobil kliensek, messengerek. Van egy fogadásunk RTMP-forgalom élő adásokhoz külön frontszerverekkel és WSS- kapcsolatok a Streaming API-hoz.

A szervereken lévő HTTPS és WSS esetén megéri nginx. Az RTMP adásoknál nemrégiben saját megoldásunkra váltottunk kive, de ez meghaladja a jelentés kereteit. A hibatűrés érdekében ezek a szerverek közös IP-címeket hirdetnek, és csoportosan működnek, így ha valamelyik szerveren probléma adódik, a felhasználói kérések ne vesszenek el. A HTTPS és a WSS esetében ugyanezek a szerverek titkosítják a forgalmat, hogy a CPU-terhelés egy részét magukra vegyék.

A WSS-ről és az RTMP-ről nem fogunk tovább beszélni, hanem csak a szabványos HTTPS-kérésekről, amelyek általában egy webprojekthez kapcsolódnak.

háttér

Az előlap mögött általában háttérkiszolgálók találhatók. Feldolgozzák azokat a kéréseket, amelyeket az elülső szerver kap az ügyfelektől.

Ezt kPHP szerverek, amelyen a HTTP démon fut, mert a HTTPS már visszafejtve van. A kPHP egy szerver, amelyen fut prefork modellek: elindít egy mesterfolyamatot, egy csomó gyerek feldolgozást, lehallgató socketeket ad át nekik, és ők feldolgozzák a kéréseiket. Ebben az esetben a folyamatok nem indulnak újra a felhasználótól érkező egyes kérések között, hanem egyszerűen visszaállítják állapotukat az eredeti nulla értékű állapotra – kérésről kérésre, az újraindítás helyett.

Terhelés-elosztás

Az összes háttérrendszerünk nem egy hatalmas gépkészlet, amely bármilyen kérést képes feldolgozni. Mi őket külön csoportokra osztva: általános, mobil, api, videó, stádium... A probléma egy külön gépcsoportnál nem érinti az összes többit. A videóval kapcsolatos problémák esetén a zenét hallgató felhasználó nem is tud a problémákról. Hogy melyik háttérrendszerre küldje a kérést, azt az előlapon lévő nginx dönti el a konfigurációnak megfelelően.

Metrikagyűjtés és kiegyensúlyozás

Ahhoz, hogy megértsük, hány autóra van szükségünk az egyes csoportokban, mi ne hagyatkozzon a QPS-re. A háttérprogramok különbözőek, eltérő kérésekkel rendelkeznek, minden kérésnek más a QPS kiszámításának bonyolultsága. Ezért mi a szerver egészén – a CPU-n és a perf-en – a terhelés fogalmával működünk.

Több ezer ilyen szerverünk van. Minden fizikai szerver egy kPHP csoportot futtat az összes mag újrahasznosítására (mivel a kPHP egyszálú).

Tartalomszerver

A CS vagy Content Server egy tárhely. A CS egy kiszolgáló, amely tárolja a fájlokat, és feldolgozza a feltöltött fájlokat és mindenféle háttérszinkron feladatot, amelyet a fő webes felület hozzárendel hozzá.

Több tízezer fizikai szerverünk van, amelyek fájlokat tárolnak. A felhasználók szeretnek fájlokat feltölteni, mi pedig szeretjük tárolni és megosztani őket. Néhány ilyen szervert speciális pu/pp szerverek zárnak le.

pu/pp

Ha megnyitotta a hálózat lapot a VK-ban, akkor látta a pu/pp-t.

GYIK a VKontakte építészetéről és munkájáról

Mi az a pu/pp? Ha egyik szervert a másik után zárjuk be, akkor két lehetőség van a fájl feltöltésére és letöltésére a bezárt szerverre: közvetlenül keresztül http://cs100500.userapi.com/path vagy közbenső szerveren keresztül - http://pu.vk.com/c100500/path.

A Pu a fotófeltöltés történelmi neve, a pp pedig a fotóproxy. Vagyis az egyik szerver a fényképek feltöltésére szolgál, a másik pedig a feltöltésre. Most már nem csak a fényképek töltődnek be, hanem a név is megmaradt.

Ezek a szerverek megszakítja a HTTPS munkamenetekethogy eltávolítsa a processzorterhelést a tárolóból. Továbbá, mivel a felhasználói fájlokat ezeken a szervereken dolgozzák fel, minél kevésbé érzékeny információkat tárolnak ezeken a gépeken, annál jobb. Például HTTPS titkosítási kulcsok.

Mivel a gépeket a többi gépünk zárja, megengedhetjük magunknak, hogy ne adjunk nekik „fehér” külső IP-t, ill. adj "szürkét". Így spóroltunk az IP-készleten, és garantáltan megvédjük a gépeket a külső hozzáféréstől – egyszerűen nincs IP, amibe be lehetne jutni.

Rugalmasság megosztott IP-címeken. A hibatűrés szempontjából a séma ugyanúgy működik - több fizikai szervernek közös fizikai IP-je van, és az előttük lévő hardver választja ki, hogy hova küldje a kérést. A többi lehetőségről később beszélek.

A vitatott pont az, hogy ebben az esetben a kliens kevesebb kapcsolatot tart fenn. Ha több gépnek ugyanaz az IP-címe – ugyanazzal a gazdagéppel: pu.vk.com vagy pp.vk.com, akkor az ügyfélböngésző korlátozza az egy géphez intézett egyidejű kérések számát. De a mindenütt jelenlévő HTTP/2 idején úgy gondolom, hogy ez már nem annyira releváns.

A séma nyilvánvaló hátránya, hogy muszáj pumpálja az összes forgalmat, amely egy másik szerveren keresztül megy a tárolóba. Mivel a forgalmat gépeken keresztül pumpáljuk, még nem tudjuk ugyanazt a sémát használni a nagy forgalmat, például a videót. Közvetlenül továbbítjuk - külön közvetlen kapcsolat a különálló tárolókhoz, kifejezetten videóhoz. A könnyebb tartalmakat proxyn keresztül továbbítjuk.

Nem sokkal ezelőtt megkaptuk a proxy továbbfejlesztett verzióját. Most elmondom, miben különböznek a szokásostól, és miért van erre szükség.

nap

2017 szeptemberében az Oracle, amely korábban megvásárolta a Sun-t, rengeteg Sun alkalmazottat bocsátott el. Elmondhatjuk, hogy ebben a pillanatban a cég megszűnt. Az új rendszer nevének kiválasztásakor rendszergazdáink úgy döntöttek, hogy tisztelegnek a cég emléke előtt, és az új rendszert Sunnak nevezték el. Magunk között egyszerűen „napoknak” hívjuk.

GYIK a VKontakte építészetéről és munkájáról

pp volt néhány probléma. Csoportonként egy IP – nem hatékony gyorsítótár. Számos fizikai szerver közös IP-címen osztozik, és nincs mód annak szabályozására, hogy a kérés melyik szerverre kerüljön. Ezért, ha ugyanazt a fájlt különböző felhasználók keresik, akkor ha ezeken a kiszolgálókon van gyorsítótár, a fájl az egyes kiszolgálók gyorsítótárába kerül. Ez egy nagyon nem hatékony rendszer, de semmit sem lehet tenni.

Következésképpen - nem tudjuk feldarabolni a tartalmat, mert ehhez a csoporthoz nem tudunk konkrét szervert kiválasztani - közös IP-jük van. Bizonyos belső okok miatt is régiókban nem lehetett ilyen szervereket telepíteni. Csak Szentpéterváron álltak.

A napokkal megváltoztattuk a kiválasztási rendszert. Most megvan anycast útválasztás: dinamikus útválasztás, anycast, önellenőrző démon. Minden szervernek megvan a saját egyedi IP-címe, de közös alhálózata. Minden úgy van beállítva, hogy ha az egyik szerver meghibásodik, a forgalom automatikusan szétoszlik ugyanazon csoport többi szerverén. Most már lehetőség van egy adott szerver kiválasztására, nincs redundáns gyorsítótár, és a megbízhatóság nem változott.

Súly támogatás. Most már megengedhetjük magunknak, hogy igény szerint különböző teljesítményű gépeket szereljünk be, illetve átmeneti problémák esetén a működő „napok” súlyát is cseréljük, hogy csökkentsük a terhelést, hogy „pihenjenek” és újra működjenek.

Megosztás tartalomazonosító szerint. Egy vicces dolog a felosztással kapcsolatban: általában azért tördeljük a tartalmat, hogy a különböző felhasználók ugyanazon a „napon” keresztül ugyanahhoz a fájlhoz menjenek, hogy közös gyorsítótáruk legyen.

Nemrég elindítottuk a „Clover” alkalmazást. Ez egy online kvíz élő adásban, ahol a műsorvezető kérdéseket tesz fel, a felhasználók pedig valós időben válaszolnak a lehetőségek kiválasztásával. Az alkalmazásban van egy chat, ahol a felhasználók cseveghetnek. Egyidejűleg csatlakozhat a közvetítéshez több mint 100 ezer ember. Mindannyian üzeneteket írnak, amelyeket minden résztvevőnek elküldenek, és egy avatar is érkezik az üzenethez. Ha 100 ezer ember jön egy avatárért egy „napon”, akkor az néha egy felhő mögé gurulhat.

Annak érdekében, hogy ellenálljunk az ugyanarra a fájlra irányuló kéréseknek, egy bizonyos típusú tartalomnál bekapcsolunk egy olyan hülye sémát, amely a régió összes elérhető „napján” szétosztja a fájlokat.

Nap belülről

Fordított proxy nginx-en, gyorsítótár a RAM-ban vagy a gyors Optane/NVMe lemezeken. Példa: http://sun4-2.userapi.com/c100500/path — hivatkozás a „nap”-hoz, amely a negyedik régióban, a második szervercsoportban található. Bezárja az elérési út fájlt, amely fizikailag az 100500 szerveren található.

Gyorsítótár

Hozzáadunk még egy csomópontot az építészeti sémánkhoz - a gyorsítótárazási környezethez.

GYIK a VKontakte építészetéről és munkájáról

Alább látható az elrendezési diagram regionális gyorsítótárak, körülbelül 20 van belőlük. Ezek azok a helyek, ahol gyorsítótárak és „napok” találhatók, amelyek magukon keresztül gyorsítótárazhatják a forgalmat.

GYIK a VKontakte építészetéről és munkájáról

Ez a multimédiás tartalom gyorsítótárazása; itt nem tárolódnak felhasználói adatok – csak zenék, videók, fényképek.

A felhasználó régiójának meghatározásához mi a régiókban bejelentett BGP hálózati előtagokat gyűjtjük. Backback esetén a geoip adatbázist is elemezni kell, ha nem találtuk meg az IP-t előtagok alapján. A régiót a felhasználó IP-címe alapján határozzuk meg. A kódban megtekinthetjük a felhasználó egy vagy több régióját - azokat a pontokat, amelyekhez földrajzilag a legközelebb van.

Hogyan működik?

A fájlok népszerűségét régiónként számoljuk. Számos regionális gyorsítótár található, ahol a felhasználó tartózkodik, és egy fájlazonosító – ezt a párat vesszük, és minden letöltésnél növeljük az értékelést.

Ugyanakkor a démonok - a régiókban lévő szolgáltatások - időről időre jönnek az API-hoz, és azt mondják: „Ilyen és ilyen gyorsítótár vagyok, adjon listát a régióm legnépszerűbb fájljairól, amelyek még nincsenek rajtam. ” Az API egy rakás fájlt szállít minősítés szerint rendezve, a démon letölti őket, elviszi a régiókba, és onnan kézbesíti a fájlokat. Ez az alapvető különbség a pu/pp és a Sun között a cache-ekből: azonnal átadják magukon a fájlt, még akkor is, ha ez a fájl nincs a cache-ben, és a cache először letölti a fájlt magának, majd elkezdi visszaadni.

Ebben az esetben megkapjuk a tartalom közelebb kerül a felhasználókhoz és a hálózati terhelés szétosztása. Például csak a moszkvai gyorsítótárból osztunk ki 1 Tbit/s-nál többet csúcsidőben.

De vannak problémák - a cache szerverek nem gumiból vannak. A rendkívül népszerű tartalmak esetében néha nincs elég hálózat egy külön szerver számára. A cache szervereink 40-50 Gbit/s-osak, de van olyan tartalom, ami teljesen eltömíti az ilyen csatornát. A régióban népszerű fájlok egynél több példányának tárolása felé haladunk. Remélem, hogy az év végéig megvalósítjuk.

Megnéztük az általános építészetet.

  • Elülső szerverek, amelyek fogadják a kéréseket.
  • A kéréseket feldolgozó háttérprogramok.
  • Kétféle proxy által lezárt tárolók.
  • Regionális gyorsítótárak.

Mi hiányzik ebből a diagramból? Természetesen az adatbázisok, amelyekben adatokat tárolunk.

Adatbázisok vagy motorok

Ezeket nem adatbázisoknak, hanem motoroknak – motoroknak hívjuk, mert gyakorlatilag nem rendelkezünk az általánosan elfogadott értelemben vett adatbázisokkal.

GYIK a VKontakte építészetéről és munkájáról

Ez szükséges intézkedés.. Ez azért történt, mert 2008-2009-ben, amikor a VK népszerűsége robbanásszerűen nőtt, a projekt teljes egészében a MySQL-en és a Memcache-en működött, és voltak problémák. A MySQL szeretett összeomlani és megrontani a fájlokat, ami után nem állt helyre, és a Memcache teljesítménye fokozatosan romlott, és újra kellett indítani.

Kiderült, hogy az egyre népszerűbb projektnek volt állandó tárolója, ami rontja az adatokat, és gyorsítótár, ami lelassul. Ilyen körülmények között nehéz egy növekvő projektet kidolgozni. Elhatároztuk, hogy megpróbáljuk újraírni azokat a kritikus dolgokat, amelyekre a projekt a saját kerékpárjainkra összpontosított.

A megoldás sikeres volt. Erre adott volt a lehetőség, és egyben extrém szükség is, mert más skálázási módok akkor még nem léteztek. Nem volt egy csomó adatbázis, a NoSQL még nem létezett, csak MySQL, Memcache, PostrgreSQL volt – és ennyi.

Univerzális működés. A fejlesztést C fejlesztői csapatunk vezette, és minden következetesen történt. Motortól függetlenül mindegyik megközelítőleg azonos fájlformátumot írt a lemezre, ugyanazokat az indítási paramétereket, azonos módon dolgozták fel a jeleket, és megközelítőleg ugyanúgy viselkedtek élhelyzetek és problémák esetén. A motorok számának növekedésével az adminisztrátorok számára kényelmesebb a rendszer kezelése - nincs állatkert, amelyet karban kell tartani, és minden új, harmadik féltől származó adatbázis kezelését újra kell tanulniuk, ami lehetővé tette a gyors és kényelmes bővítést. számukat.

A motorok típusai

A csapat jó néhány motort írt. Íme néhány ezek közül: barát, tippek, kép, ipdb, levelek, listák, naplók, memcached, meowdb, hírek, nostradamus, fénykép, lejátszási listák, pmemcached, sandbox, keresés, tárhely, kedvelések, feladatok,…

Minden olyan feladathoz, amely meghatározott adatstruktúrát igényel, vagy atipikus kéréseket dolgoz fel, a C-csapat új motort ír. Miért ne.

Külön motorunk van memcached, ami a szokásoshoz hasonló, de egy rakás finomsággal, és ami nem lassít. Nem ClickHouse, de működik is. Külön rendelhető pmemcached - Van kitartóan memcached, amely a lemezen is képes adatokat tárolni, ráadásul a RAM-ba is belefér, hogy ne veszítsen adatot újraindításkor. Különféle motorok állnak rendelkezésre az egyes feladatokhoz: sorok, listák, készletek - minden, amit projektünk igényel.

Klaszterek

A kód szempontjából nincs szükség arra, hogy a motorokat vagy adatbázisokat folyamatokként, entitásokként vagy példányokként tekintsük. A kód kifejezetten klaszterekkel, motorcsoportokkal működik - klaszterenként egy típus. Tegyük fel, hogy van egy memcached fürt – ez csak egy gépcsoport.

A kódnak egyáltalán nem kell tudnia a kiszolgálók fizikai helyét, méretét vagy számát. Egy bizonyos azonosító használatával megy a klaszterbe.

Ahhoz, hogy ez működjön, hozzá kell adni egy további entitást, amely a kód és a motorok között található - meghatalmazott.

RPC proxy

Meghatalmazott összekötő busz, amelyen szinte az egész oldal fut. Ugyanakkor van nincs szolgáltatás felfedezés — ehelyett van egy konfig ehhez a proxyhoz, amely ismeri a fürt összes fürtjének és minden szilánkjának helyét. Ezt csinálják az adminok.

A programozókat egyáltalán nem érdekli, hogy mennyibe, hol és mibe kerül – csak a klaszterhez mennek. Ez sok mindent lehetővé tesz számunkra. Kérés fogadásakor a proxy átirányítja a kérést, tudva, hogy hova - ezt maga határozza meg.

GYIK a VKontakte építészetéről és munkájáról

Ebben az esetben a proxy egy védelmi pont a szolgáltatás meghibásodása ellen. Ha valamelyik motor lelassul vagy összeomlik, akkor a proxy megérti ezt, és ennek megfelelően reagál az ügyféloldalra. Ez lehetővé teszi az időtúllépés eltávolítását - a kód nem várja meg a motor válaszát, hanem megérti, hogy nem működik, és valahogy másképp kell viselkednie. A kódot fel kell készíteni arra, hogy az adatbázisok nem mindig működnek.

Konkrét megvalósítások

Néha még mindig nagyon szeretnénk valami nem szabványos megoldást motorként. Ezzel egyidejűleg úgy döntöttek, hogy nem a kifejezetten motorjaink számára készített, kész rpc-proxynkat használjuk, hanem külön proxyt készítünk a feladathoz.

A MySQL-hez, ami még mindig van itt-ott, db-proxyt használunk, a ClickHouse-hoz pedig - Cicaház.

Általában így működik. Van egy bizonyos szerver, azon fut a kPHP, Go, Python – általában minden olyan kód, amely használhatja az RPC protokollunkat. A kód helyileg egy RPC proxyn fut – minden kiszolgáló, ahol a kód található, saját helyi proxyját futtatja. Kérésre a meghatalmazott megérti, hová kell mennie.

GYIK a VKontakte építészetéről és munkájáról

Ha az egyik motor egy másikhoz akar menni, még ha szomszéd is, akkor egy proxy-n keresztül megy, mert lehet, hogy a szomszéd egy másik adatközpontban van. A motornak nem szabad arra hagyatkoznia, hogy önmagán kívül másnak tudja a helyét – ez a mi standard megoldásunk. De persze vannak kivételek :)

Példa egy TL-sémára, amely szerint minden motor működik.

memcache.not_found                                = memcache.Value;
memcache.strvalue	value:string flags:int = memcache.Value;
memcache.addOrIncr key:string flags:int delay:int value:long = memcache.Value;

tasks.task
    fields_mask:#
    flags:int
    tag:%(Vector int)
    data:string
    id:fields_mask.0?long
    retries:fields_mask.1?int
    scheduled_time:fields_mask.2?int
    deadline:fields_mask.3?int
    = tasks.Task;
 
tasks.addTask type_name:string queue_id:%(Vector int) task:%tasks.Task = Long;

Ez egy bináris protokoll, amelynek a legközelebbi analógja protobuf. A séma opcionális mezőket, összetett típusokat – a beépített skalárok kiterjesztéseit és lekérdezéseket – írja elő. Minden ennek a protokollnak megfelelően működik.

RPC TL felett TCP/UDP felett… UDP?

Van egy RPC protokollunk a motorkérelmek végrehajtására, amely a TL sémán felül fut. Mindez TCP/UDP kapcsolaton keresztül működik. A TCP érthető, de miért van szükségünk gyakran az UDP-re?

Az UDP segít elkerülhető a szerverek közötti nagyszámú kapcsolat problémája. Ha minden szerver rendelkezik RPC-proxyval, és általában bármelyik motorhoz tud kapcsolódni, akkor szerverenként több tízezer TCP-kapcsolat létezik. Terhelés van, de használhatatlan. UDP esetén ez a probléma nem áll fenn.

Nincs redundáns TCP kézfogás. Ez egy tipikus probléma: amikor új motort vagy új szervert indítanak el, egyszerre sok TCP-kapcsolat jön létre. Kis könnyed kérések esetén, például UDP hasznos terhelés esetén, a kód és a motor között minden kommunikáció megtörténik két UDP csomag: az egyik az egyik, a másik a másik irányba repül. Egy oda-vissza út - és a kód kézfogás nélkül kapott választ a motortól.

Igen, minden csak működik nagyon kis százalékos csomagvesztés mellett. A protokoll támogatja az újraküldést és az időtúllépést, de ha sokat veszítünk, szinte TCP-t kapunk, ami nem előnyös. Az UDP-t nem hajtjuk át az óceánokon.

Több ezer ilyen szerverünk van, és a séma ugyanaz: minden fizikai szerverre egy-egy motorcsomag van telepítve. Többnyire egyszálasak, hogy a lehető leggyorsabban, blokkolás nélkül futhassanak, és egyszálú megoldásként vannak szétdarabolva. Ugyanakkor ezeknél a motoroknál nincs megbízhatóbb, és nagy figyelmet fordítanak a tartós adattárolásra.

Állandó adattárolás

A motorok binlogokat írnak. A binlog egy fájl, amelynek végén egy állapot- vagy adatváltozási esemény kerül hozzáadásra. Különböző megoldásokban másképpen hívják: bináris napló, WAL, AOF, de az elv ugyanaz.

Hogy a motor ne olvassa újra a teljes binlogot sok éven át újraindításkor, a motorok írnak pillanatképek – aktuális állapot. Ha szükséges, először abból olvasnak, majd a binlogból fejezik be az olvasást. Minden binlog ugyanabban a bináris formátumban van írva - a TL séma szerint, hogy az adminisztrátorok egyformán kezelhessék őket eszközeikkel. Nincs szükség pillanatképekre. Van egy általános fejléc, amely jelzi, hogy kinek a pillanatképe az int, a motor varázsa, és melyik test nem fontos senkinek. Ez a pillanatfelvételt rögzítő motorral van probléma.

Gyorsan leírom a működési elvet. Van egy szerver, amin a motor fut. Új üres binlogot nyit meg íráshoz, és eseményt ír a változtatáshoz.

GYIK a VKontakte építészetéről és munkájáról

Egy ponton vagy úgy dönt, hogy saját maga készít egy pillanatfelvételt, vagy jelet kap. A szerver létrehoz egy új fájlt, beleírja a teljes állapotát, a fájl végéhez hozzáfűzi az aktuális binlog méretet - offset - és folytatja az írást. Új binlog nem jön létre.

GYIK a VKontakte építészetéről és munkájáról

Egy bizonyos ponton, amikor a motor újraindul, egy binlog és egy pillanatkép is lesz a lemezen. A motor beolvassa a teljes pillanatképet, és egy bizonyos ponton megemeli az állapotát.

GYIK a VKontakte építészetéről és munkájáról

Beolvassa azt a pozíciót, amely a pillanatkép létrehozásakor volt, és a binlog méretét.

GYIK a VKontakte építészetéről és munkájáról

Beolvassa a binlog végét, hogy megkapja az aktuális állapotot, és folytatja a további események írását. Ez egy egyszerű séma, minden motorunk ennek megfelelően működik.

Adatreplikáció

Ennek eredményeként az adatok replikációja a mi nyilatkozat alapú — a binlogba nem akármilyen oldalváltozást írunk, hanem mégpedig változtatási kérelmek. Nagyon hasonló ahhoz, ami a hálózaton keresztül érkezik, csak kissé módosítva.

Ugyanezt a sémát nem csak a replikációhoz használják, hanem biztonsági másolatok készítéséhez. Van egy motorunk - egy írómesterünk, amely a binlogba ír. Bármilyen más helyen, ahol az adminisztrátor beállította, ez a binlog másolásra kerül, és ennyi – van egy biztonsági másolatunk.

GYIK a VKontakte építészetéről és munkájáról

Ha szükséges replika olvasásaA CPU olvasási terhelésének csökkentése érdekében egyszerűen elindul az olvasómotor, amely beolvassa a binlog végét, és helyileg végrehajtja ezeket a parancsokat.

A lemaradás itt nagyon kicsi, és ki lehet deríteni, hogy a replika mennyivel marad el a mestertől.

Adatfelosztás az RPC proxyban

Hogyan működik a sharding? Hogyan érti meg a proxy, hogy melyik fürt szilánkjára küldje el? A kódban nem szerepel: „Küldj 15 szilánkért!” - nem, ezt a meghatalmazott végzi.

A legegyszerűbb séma a firstint — a kérelem első száma.

get(photo100_500) => 100 % N.

Ez egy példa egy egyszerű memcached szöveges protokollra, de természetesen a lekérdezések lehetnek összetettek és strukturáltak. A példa a lekérdezés első számát veszi fel, a maradékot pedig a fürt méretével osztva.

Ez akkor hasznos, ha egyetlen entitás adathelyét szeretnénk elérni. Tegyük fel, hogy a 100 egy felhasználói vagy csoportazonosító, és azt szeretnénk, hogy egy entitás összes adata egy shardon legyen összetett lekérdezések esetén.

Ha nem törődünk azzal, hogy a kérések hogyan oszlanak el a fürtben, van egy másik lehetőség – az egész szilánk kivonatolása.

hash(photo100_500) => 3539886280 % N

Megkapjuk a hash-t, az osztás maradékát és a szilánkszámot is.

Mindkét lehetőség csak akkor működik, ha fel vagyunk készülve arra, hogy a klaszter méretének növelésekor felosztjuk, vagy többszörösére növeljük. Például 16 szilánkunk volt, nincs elég, többet akarunk - nyugodtan szerezhetünk 32-t leállás nélkül. Ha nem többszörösét akarjuk növelni, akkor leállások lesznek, mert nem tudunk mindent pontosan felosztani veszteség nélkül. Ezek a lehetőségek hasznosak, de nem mindig.

Ha tetszőleges számú szervert kell hozzáadnunk vagy eltávolítanunk, akkor ezt használjuk Következetes hash a gyűrűn a la Ketama. Ugyanakkor teljesen elveszítjük az adatok lokalizációját, össze kell vonnunk a kérést a fürttel, hogy minden egyes darab a saját kis válaszát adja vissza, majd a válaszokat összevonjuk a proxyval.

Vannak szuperspecifikus kérések. Így néz ki: Az RPC-proxy fogadja a kérést, meghatározza, hogy melyik fürthöz lépjen, és meghatározza a szilánkot. Aztán vannak írási mesterek, vagy ha a fürt rendelkezik replika támogatással, akkor kérésre küld egy replikának. A proxy teszi mindezt.

GYIK a VKontakte építészetéről és munkájáról

Naplók

A naplókat többféleképpen írjuk. A legnyilvánvalóbb és legegyszerűbb az naplók írása a memcache-be.

ring-buffer: prefix.idx = line

Van egy kulcs előtag - a napló neve, egy sor, és van ennek a naplónak a mérete - a sorok száma. Vegyünk egy véletlen számot 0-tól a sorok számának mínusz 1-ig. A memcache kulcsa egy ezzel a véletlenszámmal összefűzött előtag. Az értékhez mentjük a naplósort és az aktuális időt.

Ha szükséges a naplók leolvasása, akkor elvégezzük Multi Get minden kulcsot idő szerint rendezve, így valós időben kap egy gyártási naplót. A sémát akkor használják, ha valamit valós időben kell hibakeresnie a termelésben, anélkül, hogy bármit eltörne, anélkül, hogy leállítaná vagy engedélyezné a forgalmat más gépekhez, de ez a napló nem tart sokáig.

A rönkök megbízható tárolására motorral rendelkezünk rönk-motor. Pontosan ezért hozták létre, és széles körben használják számos klaszterben. Az általam ismert legnagyobb klaszter 600 TB csomagolt rönköt tárol.

Nagyon régi a motor, vannak már 6-7 éves klaszterek. Vannak vele problémák, amelyeket megpróbálunk megoldani, például elkezdtük aktívan használni a ClickHouse-t a naplók tárolására.

Naplógyűjtés a ClickHouse-ban

Ez a diagram megmutatja, hogyan lépünk be a motorjainkba.

GYIK a VKontakte építészetéről és munkájáról

Létezik olyan kód, amely helyileg az RPC-n keresztül megy az RPC-proxyhoz, és megérti, hová kell menni a motorhoz. Ha naplókat akarunk írni a ClickHouse-ban, két részt kell módosítanunk ebben a sémában:

  • cseréljen ki néhány motort ClickHouse-ra;
  • cserélje ki az RPC proxyt, amely nem tud hozzáférni a ClickHouse-hoz, valamilyen megoldásra, amely képes rá, és RPC-n keresztül.

A motor egyszerű - kicseréljük egy szerverre vagy egy szervercsoportra a ClickHouse-szal.

És hogy a ClickHouse-hoz menjünk, megtettük KittenHouse. Ha a KittenHouse-ból közvetlenül a ClickHouse-ba megyünk, az nem fog megbirkózni. Még kérések nélkül is rengeteg gép HTTP-kapcsolataiból adódik össze. A séma működéséhez egy ClickHouse-szal rendelkező szerveren helyi fordított proxy fel van emelve, amely úgy van megírva, hogy elbírja a szükséges csatlakozási mennyiségeket. Viszonylag megbízhatóan képes pufferelni is az adatokat magában.

GYIK a VKontakte építészetéről és munkájáról

Néha nem akarjuk megvalósítani az RPC sémát nem szabványos megoldásokban, például az nginxben. Ezért a KittenHouse képes naplókat fogadni UDP-n keresztül.

GYIK a VKontakte építészetéről és munkájáról

Ha a naplók küldője és címzettje ugyanazon a gépen dolgozik, akkor meglehetősen kicsi annak a valószínűsége, hogy egy UDP-csomag elveszik a helyi gazdagépen belül. Kompromisszumként az RPC harmadik féltől származó megoldásokban való megvalósításának szükségessége és a megbízhatóság között egyszerűen UDP-küldést használunk. Erre a sémára később visszatérünk.

megfigyelés

Kétféle naplónk van: azokat, amelyeket a rendszergazdák gyűjtenek össze a szervereiken, és azokat, amelyeket a fejlesztők írnak kódból. Kétféle mérőszámnak felelnek meg: rendszer és termék.

Rendszermetrikák

Minden szerverünkön működik netdata, amely statisztikákat gyűjt és elküldi a címre Grafit szén. Ezért a ClickHouse-t tárolórendszerként használják, és nem például a Whisper-t. Ha szükséges, közvetlenül a ClickHouse-ból olvashat, vagy használhatja grafana mérőszámokhoz, grafikonokhoz és jelentésekhez. Fejlesztőként elegendő hozzáférésünk van a Netdatához és a Grafanához.

Termékmutatók

A kényelem kedvéért sok mindent leírtunk. Például van egy sor közönséges függvény, amely lehetővé teszi, hogy Counts, UniqueCounts értékeket írjon be a statisztikákba, amelyeket elküldenek valahova tovább.

statlogsCountEvent   ( ‘stat_name’,            $key1, $key2, …)
statlogsUniqueCount ( ‘stat_name’, $uid,    $key1, $key2, …)
statlogsValuetEvent  ( ‘stat_name’, $value, $key1, $key2, …)

$stats = statlogsStatData($params)

Ezt követően válogató és csoportosító szűrőket használhatunk, és mindent megtehetünk a statisztikákból, amit csak akarunk – grafikonokat készíthetünk, őrzőkutyákat konfigurálhatunk.

Nagyon írunk sok mérőszám az események száma napi 600 milliárdtól 1 billióig terjed. Ezeket azonban szeretnénk megtartani legalább pár évea mutatók trendjeinek megértéséhez. Mindezt összerakni egy nagy probléma, amelyet még nem sikerült megoldanunk. Elmondom, hogyan működött az elmúlt években.

Vannak függvényeink, amelyek ezeket a mérőszámokat írják a helyi memcache-bea bejegyzések számának csökkentése érdekében. Egyszer rövid időn belül helyben indult stats-daemon összegyűjti az összes rekordot. Ezután a démon a metrikákat két szerverrétegbe egyesíti rönk-gyűjtők, amely egy csomó gépünkről összesíti a statisztikákat, hogy a mögöttük lévő réteg ne haljon meg.

GYIK a VKontakte építészetéről és munkájáról

Ha szükséges, írhatunk közvetlenül a naplógyűjtőknek.

GYIK a VKontakte építészetéről és munkájáról

De a kódból közvetlenül a gyűjtőkre írás, a stas-daemom megkerülésével rosszul skálázható megoldás, mert növeli a gyűjtő terhelését. A megoldás csak akkor megfelelő, ha valamilyen oknál fogva nem tudjuk felemelni a memcache stats-daemont a gépen, vagy lefagyott és direkt mentünk.

Ezután a naplógyűjtők összevonják a statisztikákat miauDB - ez az adatbázisunk, amely mérőszámokat is tárolhat.

GYIK a VKontakte építészetéről és munkájáról

Ezután a kódból bináris „közel SQL” kijelöléseket végezhetünk.

GYIK a VKontakte építészetéről és munkájáról

Kísérlet

2018 nyarán volt egy belső hackathonunk, és felmerült az ötlet, hogy megpróbáljuk a diagram piros részét lecserélni valamire, ami mérőszámokat tárolhat a ClickHouse-ban. Vannak naplóink ​​a ClickHouse-on – miért ne próbálná ki?

GYIK a VKontakte építészetéről és munkájáról

Volt egy sémánk, amely a KittenHouse-on keresztül írt naplókat.

GYIK a VKontakte építészetéről és munkájáról

Eldöntöttük adjunk hozzá egy másik „*Ház”-t a diagramhoz, amely pontosan abban a formátumban fogja megkapni a mérőszámokat, ahogyan a kódunk írja őket UDP-n keresztül. Aztán ez a *Ház betétekké alakítja őket, mint a rönkök, amiket a KittenHouse megért. Tökéletesen el tudja juttatni ezeket a naplókat a ClickHouse-nak, amelynek képesnek kell lennie elolvasni őket.

GYIK a VKontakte építészetéről és munkájáról

A memcache, stats-daemon és logs-collectors adatbázist tartalmazó sémát ez váltja fel.

GYIK a VKontakte építészetéről és munkájáról

A memcache, stats-daemon és logs-collectors adatbázist tartalmazó sémát ez váltja fel.

  • Itt van egy feladás a kódból, amely helyben van megírva a StatsHouse-ban.
  • A StatsHouse kötegekben írja a KittenHouse-ba a már SQL-beszúrásokká konvertált UDP-metrikákat.
  • A KittenHouse elküldi őket a ClickHouse-nak.
  • Ha el akarjuk olvasni őket, akkor a StatsHouse megkerülésével - közvetlenül a ClickHouse-ból, normál SQL-lel.

Még mindig kísérlet, de szeretjük, ahogy kiderül. Ha megoldjuk a problémákat a sémával, akkor talán teljesen áttérünk rá. Én személy szerint remélem.

A rendszer nem takarít meg vasat. Kevesebb szerverre van szükség, helyi stats-démonokra és naplógyűjtőkre nincs szükség, de a ClickHouse-hoz nagyobb szerverre van szükség, mint a jelenlegi rendszerben. Kevesebb szerverre van szükség, de drágábbnak és erősebbnek kell lenniük.

Telepítés

Először nézzük meg a PHP telepítését. ben fejlődünk csoportos it: használ GitLab и TeamCity bevetésre. A fejlesztési ágak beolvadnak a master ágba, a tesztelési mesterből a stagingbe, a stagingből pedig a termelésbe.

Üzembe helyezés előtt az aktuális és az előző termelési ágat veszik, és figyelembe veszik bennük a diff fájlokat - változások: létrehozva, törölve, módosítva. Ezt a változást egy speciális copyfast motor binlogjában rögzítjük, amely gyorsan képes replikálni a változtatásokat a teljes szerverflottánkra. Itt nem közvetlenül másolást használnak, hanem pletyka replikációja, amikor az egyik szerver elküldi a módosításokat a legközelebbi szomszédjainak, azokat a szomszédjaiknak stb. Ez lehetővé teszi a kód frissítését tíz és másodpercek alatt a teljes flottán. Amikor a változás eléri a helyi replikát, alkalmazza ezeket a javításokat annak helyi fájlrendszer. A visszaállítást is ugyanezen séma szerint hajtják végre.

A kPHP-t is sokat telepítjük, és saját fejlesztése is van csoportos it a fenti diagram szerint. Ettől kezdve HTTP szerver bináris, akkor nem tudunk diff-et előállítani - a kiadási bináris tömege több száz MB. Ezért van itt egy másik lehetőség - a verzióra van írva binlog copyfast. Minden felépítéssel növekszik, és a visszaállítás során is nő. Változat replikálva a szerverekre. A helyi copyfasták látják, hogy egy új verzió lépett be a binlogba, és ugyanazzal a pletyka-replikációval veszik át maguknak a bináris legfrissebb verzióját, anélkül, hogy fárasztanák főszerverünket, de gondosan szétosztják a terhelést a hálózaton. Ami ezután következik kecses újraindítás az új verzióhoz.

Motorjaink esetében, amelyek szintén alapvetően binárisak, a séma nagyon hasonló:

  • git master ág;
  • bináris be . Deb;
  • a verzió a binlog copyfastba van írva;
  • replikálva szerverekre;
  • a szerver kivesz egy friss .dep fájlt;
  • dpkg -i;
  • kecses újraindítás az új verzióra.

A különbség az, hogy a bináris fájlunk archívumban van csomagolva . Deb, és kiszivattyúzásakor azokat dpkg -i kerülnek a rendszerbe. Miért van a kPHP bináris, a motorok pedig dpkg formátumban? Így történt. Működik – ne nyúljon hozzá.

Hasznos linkek:

Alekszej Akulovics egyike azoknak, akik a Programbizottság tagjaként segítik PHP Oroszország május 17-én lesz az utóbbi idők legnagyobb eseménye a PHP fejlesztők számára. Nézd, milyen menő PC-nk van, milyen hangszórók (Kettő közülük PHP magot fejleszt!) - olyannak tűnik, amit nem lehet kihagyni, ha PHP-t írsz.

Forrás: will.com

Hozzászólás