FAQ o architektuře a práci VKontakte

Historie vzniku VKontakte je na Wikipedii, řekl ji sám Pavel. Zdá se, že ji už všichni znají. O vnitřnostech, architektuře a struktuře webu na HighLoad++ Pavel řekl mi to v roce 2010. Od té doby uniklo mnoho serverů, takže informace aktualizujeme: rozebereme je, vyjmeme vnitřnosti, zvážíme a podíváme se na zařízení VK z technického hlediska.

FAQ o architektuře a práci VKontakte

Alexej Akulovič (AterCattus) backendový vývojář v týmu VKontakte. Přepis této zprávy je souhrnnou odpovědí na často kladené otázky týkající se provozu platformy, infrastruktury, serverů a interakce mezi nimi, nikoli však o vývoji, jmenovitě o železe. Samostatně o databázích a o tom, co má VK místo toho, o shromažďování protokolů a sledování celého projektu jako celku. Detaily pod střihem.



Více než čtyři roky se zabývám všemožnými úkoly souvisejícími s backendem.

  • Nahrávání, ukládání, zpracování, distribuce médií: video, živé vysílání, zvuk, fotografie, dokumenty.
  • Infrastruktura, platforma, monitorování vývojářů, logy, regionální mezipaměti, CDN, proprietární RPC protokol.
  • Integrace s externími službami: push notifikace, analýza externích odkazů, RSS feed.
  • Pomoc kolegům s různými otázkami, jejichž zodpovězení vyžaduje ponořit se do neznámého kódu.

Během této doby jsem se podílel na mnoha součástech webu. Chci se o tuto zkušenost podělit.

Obecná architektura

Vše, jako obvykle, začíná serverem nebo skupinou serverů, které přijímají požadavky.

Přední server

Přední server přijímá požadavky přes HTTPS, RTMP a WSS.

HTTPS - jedná se o požadavky na hlavní a mobilní webové verze webu: vk.com a m.vk.com a další oficiální a neoficiální klienty našeho API: mobilní klienti, poslové. Máme recepci RTMP-provoz pro živé vysílání se samostatnými předními servery a WSS- připojení pro Streaming API.

Pro HTTPS a WSS na serverech se to vyplatí Nginx. U vysílání RTMP jsme nedávno přešli na vlastní řešení kive, ale to je nad rámec zprávy. Kvůli odolnosti proti chybám tyto servery inzerují společné adresy IP a jednají ve skupinách, takže v případě problému na jednom ze serverů se požadavky uživatelů neztratí. Pro HTTPS a WSS tytéž servery šifrují provoz, aby přenesly část zátěže CPU na sebe.

Nebudeme dále mluvit o WSS a RTMP, ale pouze o standardních HTTPS požadavcích, které jsou obvykle spojeny s webovým projektem.

backend

Za přední stranou jsou obvykle backend servery. Zpracovávají požadavky, které přední server obdrží od klientů.

To kPHP servery, na kterém běží HTTP démon, protože HTTPS je již dešifrováno. kPHP je server, který běží na modely předvidle: spustí hlavní proces, hromadu podřízených procesů, předá jim naslouchací sokety a oni zpracují jejich požadavky. V tomto případě se procesy mezi každým požadavkem od uživatele nerestartují, ale jednoduše místo restartu resetují jejich stav na původní stav s nulovou hodnotou – požadavek za požadavkem.

Rozložení zatížení

Všechny naše backendy nepředstavují obrovský fond strojů, které dokážou zpracovat jakýkoli požadavek. My je rozděleny do samostatných skupin: obecné, mobilní, api, video, staging... Problém na samostatné skupině strojů neovlivní všechny ostatní. V případě problémů s videem se uživatel, který poslouchá hudbu, o problémech ani nedozví. Na který backend poslat požadavek, rozhoduje nginx na přední straně podle konfigurace.

Sběr a rebalancování metrických údajů

Abychom pochopili, kolik aut potřebujeme mít v každé skupině nespoléhejte na QPS. Backendy jsou různé, mají různé požadavky, každý požadavek má jinou složitost výpočtu QPS. Proto my pracujeme s konceptem zátěže na serveru jako celku - na CPU a výkonu.

Takových serverů máme tisíce. Každý fyzický server provozuje skupinu kPHP pro recyklaci všech jader (protože kPHP je jednovláknový).

Server obsahu

CS nebo Content Server je úložiště. CS je server, který ukládá soubory a také zpracovává nahrané soubory a všechny druhy synchronních úloh na pozadí, které mu přiděluje hlavní webový frontend.

Máme desítky tisíc fyzických serverů, které ukládají soubory. Uživatelé rádi nahrávají soubory a my je rádi ukládáme a sdílíme. Některé z těchto serverů jsou uzavřeny speciálními servery pu/pp.

pu/pp

Pokud jste otevřeli kartu sítě ve VK, viděli jste pu/pp.

FAQ o architektuře a práci VKontakte

Co je pu/pp? Pokud zavíráme jeden server za druhým, existují dvě možnosti, jak nahrát a stáhnout soubor na server, který byl uzavřen: přímo přes http://cs100500.userapi.com/path nebo přes zprostředkující server - http://pu.vk.com/c100500/path.

Pu je historický název pro nahrávání fotografií a pp je proxy fotografií. To znamená, že jeden server je pro nahrávání fotografií a druhý pro nahrávání. Nyní jsou načteny nejen fotografie, ale název zůstal zachován.

Tyto servery ukončit HTTPS relacek odstranění zátěže procesoru z úložiště. Vzhledem k tomu, že uživatelské soubory jsou zpracovávány na těchto serverech, platí, že čím méně citlivých informací je na těchto počítačích uloženo, tím lépe. Například šifrovací klíče HTTPS.

Vzhledem k tomu, že stroje jsou uzavřeny našimi dalšími stroji, můžeme si dovolit nedávat jim „bílé“ externí IP a dát "šedý". Tímto způsobem jsme ušetřili na fondu IP a zaručili ochranu strojů před přístupem zvenčí – jednoduše neexistuje žádná IP adresa, která by se do něj dostala.

Odolnost přes sdílené IP adresy. Pokud jde o odolnost proti chybám, schéma funguje stejně - několik fyzických serverů má společnou fyzickou IP a hardware před nimi si vybírá, kam poslat požadavek. O dalších možnostech se zmíním později.

Kontroverzní bod je, že v tomto případě klient udržuje méně spojení. Pokud existuje stejná IP pro několik počítačů - se stejným hostitelem: pu.vk.com nebo pp.vk.com, má klientský prohlížeč limit na počet současných požadavků na jednoho hostitele. Ale v době všudypřítomného HTTP/2 se domnívám, že to už není tak aktuální.

Zjevnou nevýhodou schématu je, že musí pumpovat veškerý provoz, který jde do úložiště přes jiný server. Vzhledem k tomu, že provoz pumpujeme přes stroje, nemůžeme zatím pumpovat hustý provoz, například video, pomocí stejného schématu. Přenášíme to přímo - samostatné přímé připojení pro samostatná úložiště speciálně pro video. Lehčí obsah přenášíme prostřednictvím proxy.

Není to tak dávno, co jsme dostali vylepšenou verzi proxy. Nyní vám řeknu, jak se liší od běžných a proč je to nutné.

Neděle

V září 2017 společnost Oracle, která dříve koupila Sun, propustil obrovské množství zaměstnanců Sunu. Dá se říci, že v tomto okamžiku společnost zanikla. Při výběru názvu nového systému se naši administrátoři rozhodli vzdát hold památce této společnosti a nový systém pojmenovali Sun. Mezi sebou jí říkáme jednoduše „slunce“.

FAQ o architektuře a práci VKontakte

pp měl několik problémů. Jedna IP na skupinu - neúčinná cache. Několik fyzických serverů sdílí společnou IP adresu a neexistuje způsob, jak řídit, na který server bude požadavek směřovat. Pokud si tedy různí uživatelé přijdou pro stejný soubor, pak pokud je na těchto serverech mezipaměť, soubor skončí v mezipaměti každého serveru. Toto je velmi neefektivní schéma, ale nedalo se nic dělat.

Tudíž - nemůžeme obsah stříhat, protože pro tuto skupinu nemůžeme vybrat konkrétní server - mají společnou IP. Také z nějakých interních důvodů máme v regionech nebylo možné takové servery nainstalovat. Stáli jen v Petrohradě.

Se sluníčkama jsme změnili systém výběru. Teď máme anycast směrování: dynamické směrování, anycast, samokontrolní démon. Každý server má svou vlastní IP adresu, ale společnou podsíť. Vše je nakonfigurováno tak, že pokud jeden server selže, provoz se automaticky rozloží na další servery stejné skupiny. Nyní je možné vybrat konkrétní server, žádné redundantní ukládání do mezipamětia spolehlivost nebyla ovlivněna.

Podpora hmotnosti. Nyní si můžeme dovolit instalovat stroje různého výkonu podle potřeby a také v případě dočasných problémů změnit hmotnosti pracovních „sluníčků“, aby se snížilo jejich zatížení, aby si „odpočinuly“ a začaly znovu pracovat.

Sdílení podle ID obsahu. Zajímavá věc na shardování: obsah obvykle skartujeme tak, že různí uživatelé jdou ke stejnému souboru přes stejné „slunce“, takže mají společnou mezipaměť.

Nedávno jsme spustili aplikaci „Jetel“. Jedná se o online kvíz v živém vysílání, kde hostitel klade otázky a uživatelé odpovídají v reálném čase a volí možnosti. Aplikace má chat, kde mohou uživatelé chatovat. Může se současně připojit k vysílání více než 100 tisíc lidí. Všichni píší zprávy, které jsou odeslány všem účastníkům, a se zprávou přichází avatar. Pokud si za jedno „slunce“ přijde pro jednoho avatara 100 tisíc lidí, pak se to někdy může válet za mrakem.

Abychom vydrželi návaly žádostí o stejný soubor, zapínáme pro určitý typ obsahu hloupé schéma, které šíří soubory mezi všechna dostupná „slunce“ v regionu.

Slunce zevnitř

Reverzní proxy na nginx, cache buď v RAM nebo na rychlých Optane/NVMe discích. Příklad: http://sun4-2.userapi.com/c100500/path — odkaz na „slunce“, které se nachází ve čtvrté oblasti, druhé skupině serverů. Uzavře soubor cesty, který fyzicky leží na serveru 100500.

Cache

Do našeho architektonického schématu přidáváme ještě jeden uzel – prostředí mezipaměti.

FAQ o architektuře a práci VKontakte

Níže je schéma rozložení regionální kešky, je jich asi 20. Jsou to místa, kde se nacházejí keše a „slunce“, která mohou přes sebe cachovat provoz.

FAQ o architektuře a práci VKontakte

Jedná se o ukládání multimediálního obsahu do mezipaměti, neukládají se zde žádná uživatelská data – pouze hudba, video, fotografie.

Abychom určili region uživatele, my shromažďujeme předpony sítě BGP oznámené v regionech. V případě fallbacku musíme také analyzovat geoip databázi, pokud jsme nemohli najít IP podle prefixů. Region určujeme podle IP uživatele. V kódu se můžeme podívat na jeden nebo více regionů uživatele – ty body, kterým je geograficky nejblíže.

Jak to funguje?

Počítáme oblíbenost souborů podle regionu. Existuje číslo regionální mezipaměti, kde se uživatel nachází, a identifikátor souboru – vezmeme tento pár a při každém stažení zvyšujeme hodnocení.

Zároveň démoni - služby v regionech - čas od času přicházejí do API a říkají: „Jsem taková a taková mezipaměť, dejte mi seznam nejoblíbenějších souborů v mém regionu, které ještě nejsou na mně. “ API dodává spoustu souborů seřazených podle hodnocení, démon si je stáhne, vezme je do regionů a odtud soubory doručí. To je zásadní rozdíl mezi pu/pp a Sun z mezipaměti: soubor si okamžitě dají skrz sebe, i když tento soubor v mezipaměti není, a mezipaměť si soubor nejprve stáhne a pak ho začne dávat zpět.

V tomto případě dostáváme obsah blíže uživatelům a rozložení zátěže sítě. Například pouze z moskevské cache distribuujeme ve špičce více než 1 Tbit/s.

Ale jsou tu problémy - cache servery nejsou gumové. U super oblíbeného obsahu někdy není dostatek sítě pro samostatný server. Naše cache servery jsou 40-50 Gbit/s, ale existuje obsah, který takový kanál úplně ucpe. Směřujeme k implementaci úložiště více než jedné kopie oblíbených souborů v regionu. Doufám, že to do konce roku zrealizujeme.

Podívali jsme se na obecnou architekturu.

  • Přední servery, které přijímají požadavky.
  • Backendy, které zpracovávají požadavky.
  • Úložiště, která jsou uzavřena dvěma typy proxy.
  • Regionální kešky.

Co v tomto diagramu chybí? Samozřejmostí jsou databáze, do kterých data ukládáme.

Databáze nebo motory

Neříkáme jim databáze, ale motory – Engines, protože databáze v obecně přijímaném smyslu prakticky nemáme.

FAQ o architektuře a práci VKontakte

Toto je nezbytné opatření.. Stalo se to proto, že v letech 2008-2009, kdy VK zaznamenal prudký nárůst popularity, projekt fungoval výhradně na MySQL a Memcache a nastaly problémy. MySQL milovalo pády a poškození souborů, po kterých se neobnovilo, a Memcache postupně snižoval výkon a bylo nutné jej restartovat.

Ukazuje se, že stále populárnější projekt měl trvalé úložiště, které poškozuje data, a mezipaměť, která se zpomaluje. V takových podmínkách je obtížné vyvinout rostoucí projekt. Bylo rozhodnuto pokusit se přepsat kritické věci, na které byl projekt zaměřen, na našich vlastních kolech.

Řešení bylo úspěšné. Byla k tomu příležitost a zároveň krajní nutnost, protože jiné způsoby škálování v té době neexistovaly. Nebyla spousta databází, NoSQL ještě neexistovalo, existovaly jen MySQL, Memcache, PostrgreSQL – a to je vše.

Univerzální provoz. Vývoj vedl náš tým vývojářů v jazyce C a vše probíhalo konzistentním způsobem. Bez ohledu na engine měly všechny přibližně stejný formát souboru zapsaný na disk, stejné spouštěcí parametry, zpracovávaly signály stejným způsobem a chovaly se přibližně stejně v případě okrajových situací a problémů. S nárůstem enginů je pro administrátory pohodlné provozovat systém - není zde žádná zoologická zahrada, kterou by bylo třeba udržovat, a s každou novou databází třetích stran se musí znovu naučit ovládat, což umožnilo rychle a pohodlně zvýšit jejich počet.

Typy motorů

Tým napsal několik motorů. Zde jsou jen některé z nich: přítel, rady, obrázek, ipdb, písmena, seznamy, protokoly, memcached, meowdb, zprávy, nostradamus, fotografie, seznamy skladeb, pmemcached, sandbox, vyhledávání, úložiště, lajky, úkoly, …

Pro každý úkol, který vyžaduje specifickou datovou strukturu nebo zpracovává atypické požadavky, napíše C tým nový engine. Proč ne.

Máme samostatný motor memcached, který je podobný běžnému, ale s hromadou dobrot, a který nepolevuje. Ne ClickHouse, ale také to funguje. K dispozici samostatně pmemcached - Je perzistentní memcached, který umí i ukládat data na disk, navíc než se vejde do RAM, aby o data při restartu nepřišel. Pro jednotlivé úkoly existují různé enginy: fronty, seznamy, sady – vše, co náš projekt vyžaduje.

Shluky

Z hlediska kódu není třeba chápat motory nebo databáze jako procesy, entity nebo instance. Kód pracuje konkrétně s clustery, se skupinami motorů - jeden typ na cluster. Řekněme, že existuje cluster memcached – je to jen skupina strojů.

Kód vůbec nemusí znát fyzické umístění, velikost nebo počet serverů. Jde do clusteru pomocí určitého identifikátoru.

Aby to fungovalo, musíte přidat ještě jednu entitu, která se nachází mezi kódem a motory - zastupování.

RPC proxy

Proxy spojovací autobus, na kterém běží téměř celý web. Zároveň máme žádný objev služby — místo toho existuje konfigurace pro tento proxy, která zná umístění všech clusterů a všech fragmentů tohoto clusteru. Toto dělají administrátoři.

Programátory vůbec nezajímá, kolik, kde a co to stojí – prostě jdou do clusteru. To nám hodně umožňuje. Při přijetí požadavku proxy přesměruje požadavek, ví kam - to sám určí.

FAQ o architektuře a práci VKontakte

V tomto případě je proxy bodem ochrany proti selhání služby. Pokud se některý motor zpomalí nebo selže, proxy to pochopí a odpovídajícím způsobem zareaguje na stranu klienta. To vám umožní odstranit timeout – kód nečeká na reakci motoru, ale chápe, že nefunguje a potřebuje se chovat nějak jinak. Kód musí být připraven na to, že databáze ne vždy fungují.

Konkrétní implementace

Někdy opravdu chceme mít nějaké nestandardní řešení jako motor. Zároveň bylo rozhodnuto nepoužít náš hotový rpc-proxy, vytvořený speciálně pro naše motory, ale vytvořit pro tento úkol samostatný proxy.

Pro MySQL, který tu a tam stále máme, používáme db-proxy a pro ClickHouse - Kittenhouse.

Obecně to funguje takto. Existuje určitý server, na kterém běží kPHP, Go, Python - obecně jakýkoli kód, který může používat náš protokol RPC. Kód běží lokálně na RPC proxy – každý server, kde je kód umístěn, provozuje svůj vlastní lokální proxy. Na požádání proxy rozumí, kam má jít.

FAQ o architektuře a práci VKontakte

Pokud chce jeden engine přejít k jinému, i když je to soused, jde přes proxy, protože soused může být v jiném datovém centru. Motor by se neměl spoléhat na to, že zná polohu čehokoli jiného než sebe sama – to je naše standardní řešení. Ale samozřejmě existují výjimky :)

Příklad schématu TL, podle kterého fungují všechny motory.

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;

Jedná se o binární protokol, jehož nejbližší analog je protobuf. Schéma předepisuje volitelná pole, komplexní typy - rozšíření vestavěných skalárů a dotazy. Vše funguje podle tohoto protokolu.

RPC přes TL přes TCP/UDP… UDP?

Máme protokol RPC pro provádění požadavků motoru, který běží nad schématem TL. To vše funguje přes TCP/UDP připojení. TCP je pochopitelné, ale proč často potřebujeme UDP?

UDP pomáhá vyhnout se problému velkého počtu spojení mezi servery. Pokud má každý server proxy RPC a obecně může přejít na jakýkoli stroj, pak na jeden server připadají desítky tisíc připojení TCP. Je tam zátěž, ale je to zbytečné. V případě UDP tento problém neexistuje.

Žádné nadbytečné TCP handshake. Toto je typický problém: když je spuštěn nový engine nebo nový server, je navázáno mnoho TCP spojení najednou. U malých odlehčených požadavků, například užitečného zatížení UDP, probíhá veškerá komunikace mezi kódem a enginem dva UDP pakety: jeden letí jedním směrem, druhý druhým. Jedna cesta tam a zpět - a kód obdržel odpověď od motoru bez podání ruky.

Ano, všechno to prostě funguje s velmi malým procentem ztráty paketů. Protokol má podporu pro opakované přenosy a timeouty, ale pokud hodně ztratíme, získáme téměř TCP, což není ziskové. Nevozíme UDP přes oceány.

Máme tisíce takových serverů a schéma je stejné: na každém fyzickém serveru je nainstalován balíček motorů. Většinou jsou jednovláknové, aby běžely co nejrychleji bez blokování, a jsou shardovány jako jednovláknová řešení. Přitom nemáme nic spolehlivějšího než tyto motory a velká pozornost je věnována trvalému ukládání dat.

Trvalé ukládání dat

Motory píší bilogy. Binlog je soubor, na jehož konec je přidána událost pro změnu stavu nebo dat. V různých řešeních se nazývá jinak: binární log, WAL, AOF, ale princip je stejný.

Aby motor při restartu nemohl znovu číst celý binlog po mnoho let, zapisují motory momentky - aktuální stav. V případě potřeby z něj nejprve přečtou a poté dokončí čtení z binlogu. Všechny binlogy jsou psány ve stejném binárním formátu - podle schématu TL, takže je administrátoři mohou spravovat stejně svými nástroji. O momentky není taková nouze. Existuje obecná hlavička, která označuje, čí snímek je int, kouzlo enginu a které tělo není pro nikoho důležité. Toto je problém s motorem, který snímek zaznamenal.

Rychle popíšu princip fungování. Existuje server, na kterém běží motor. Otevře nový prázdný binlog pro zápis a zapíše do něj událost pro změnu.

FAQ o architektuře a práci VKontakte

V určitém okamžiku se buď sám rozhodne pořídit snímek, nebo obdrží signál. Server vytvoří nový soubor, zapíše do něj celý jeho stav, na konec souboru připojí aktuální velikost binlogu – offset – a pokračuje v zápisu. Nový binlog se nevytvoří.

FAQ o architektuře a práci VKontakte

V určitém okamžiku, když se motor restartuje, bude na disku jak binlog, tak snímek. Motor načte celý snímek a v určitém okamžiku zvýší jeho stav.

FAQ o architektuře a práci VKontakte

Přečte pozici, která byla v době vytvoření snímku, a velikost binlogu.

FAQ o architektuře a práci VKontakte

Přečte konec binlogu, aby získal aktuální stav, a pokračuje v psaní dalších událostí. Toto je jednoduché schéma, podle kterého fungují všechny naše motory.

Replikace dat

V důsledku toho replikace dat v našem na základě prohlášení — do binlogu nepíšeme žádné změny stránky, ale jmenovitě žádosti o změnu. Velmi podobné tomu, co přichází přes síť, jen mírně upravené.

Stejné schéma se používá nejen pro replikaci, ale také k vytváření záloh. Máme engine - psací mistr, který zapisuje do binlogu. Na jakémkoli jiném místě, kde to administrátoři nastavili, se tento binlog zkopíruje a je to – máme zálohu.

FAQ o architektuře a práci VKontakte

V případě potřeby čtecí replikaAby se snížilo zatížení CPU čtením, jednoduše se spustí čtecí jádro, které přečte konec binlogu a provede tyto příkazy lokálně.

Zpoždění je zde velmi malé a je možné zjistit, jak moc replika zaostává za předlohou.

Sdílení dat v RPC proxy

Jak funguje sharding? Jak proxy rozumí, do kterého klastrového fragmentu se má odeslat? Kód neříká: "Pošli pro 15 úlomků!" - Ne, to dělá proxy.

Nejjednodušší schéma je firstint — první číslo v žádosti.

get(photo100_500) => 100 % N.

Toto je příklad jednoduchého textového protokolu memcached, ale dotazy mohou být samozřejmě složité a strukturované. Příklad přebírá první číslo v dotazu a zbytek, když se vydělí velikostí clusteru.

To je užitečné, když chceme mít datovou lokalitu jedné entity. Řekněme, že 100 je ID uživatele nebo skupiny a chceme, aby všechna data jedné entity byla na jednom datovém fragmentu pro složité dotazy.

Pokud nás nezajímá, jak jsou požadavky v clusteru rozloženy, existuje další možnost – hašování celého střepu.

hash(photo100_500) => 3539886280 % N

Získáme také hash, zbytek dělení a číslo úlomku.

Obě tyto možnosti fungují pouze v případě, že jsme připraveni na to, že když shluk zvětšíme, rozdělíme jej nebo násobně zvětšíme. Měli jsme například 16 úlomků, nemáme dost, chceme více - můžeme bezpečně získat 32 bez prostojů. Pokud budeme chtít zvýšit ne násobky, dojde k výpadkům, protože nebudeme schopni vše přesně rozdělit bez ztrát. Tyto možnosti jsou užitečné, ale ne vždy.

Pokud potřebujeme přidat nebo odebrat libovolný počet serverů, použijeme Důsledné hašování na prstenu a la Ketama. Zároveň ale úplně ztrácíme lokalitu dat, požadavek musíme sloučit do clusteru tak, aby každý kus vrátil svou malou odpověď, a poté sloučit odpovědi do proxy.

Existují superspecifické požadavky. Vypadá to takto: RPC proxy přijme požadavek, určí, do kterého clusteru se má přejít, a určí shard. Pak existují buď předlohy zápisu, nebo, pokud má cluster podporu replik, odešle na vyžádání repliku. To vše dělá proxy.

FAQ o architektuře a práci VKontakte

Protokoly

Logy zapisujeme několika způsoby. Nejviditelnější a nejjednodušší je zapisovat protokoly do memcache.

ring-buffer: prefix.idx = line

Je tam předpona klíče - název logu, řádek a je tam velikost tohoto logu - počet řádků. Vezmeme náhodné číslo od 0 do počtu řádků mínus 1. Klíč v memcache je předpona zřetězená s tímto náhodným číslem. Do hodnoty uložíme řádek logu a aktuální čas.

Když je potřeba číst protokoly, provádíme Multi Get všechny klíče, seřazené podle času, a tím získat produkční protokol v reálném čase. Schéma se používá, když potřebujete něco odladit ve výrobě v reálném čase, aniž byste cokoli porušili, aniž byste zastavili nebo povolili provoz na jiné stroje, ale tento protokol netrvá dlouho.

Pro spolehlivé uložení kulatiny máme motor kulatiny-motor. To je přesně důvod, proč byl vytvořen a je široce používán v obrovském množství clusterů. Největší cluster, který znám, ukládá 600 TB zabalených protokolů.

Motor je hodně starý, jsou klastry staré už 6-7 let. Jsou s tím problémy, které se snažíme řešit, začali jsme například aktivně využívat ClickHouse k ukládání logů.

Sběr protokolů v ClickHouse

Tento diagram ukazuje, jak vstupujeme do našich motorů.

FAQ o architektuře a práci VKontakte

Existuje kód, který jde lokálně přes RPC do RPC-proxy a ten rozumí, kam jít do enginu. Pokud chceme v ClickHouse zapisovat protokoly, musíme v tomto schématu změnit dvě části:

  • vyměnit nějaký motor za ClickHouse;
  • nahradit RPC proxy, která nemá přístup ke ClickHouse, nějakým řešením, které to umí, a přes RPC.

Engine je jednoduchý – nahradíme ho serverem nebo clusterem serverů s ClickHouse.

A jít do ClickHouse, udělali jsme to Kotěcí dům. Pokud půjdeme přímo z KittenHouse do ClickHouse, nezvládne to. I bez požadavků se sčítá z HTTP připojení obrovského množství strojů. Aby schéma fungovalo, na serveru s ClickHouse místní reverzní proxy je aktivován, který je napsán tak, aby snesl požadované objemy spojů. Dokáže také poměrně spolehlivě ukládat data do sebe.

FAQ o architektuře a práci VKontakte

Někdy nechceme implementovat schéma RPC v nestandardních řešeních, například v nginx. KittenHouse má proto možnost přijímat protokoly přes UDP.

FAQ o architektuře a práci VKontakte

Pokud odesílatel a příjemce protokolů pracují na stejném počítači, pak je pravděpodobnost ztráty paketu UDP v rámci místního hostitele poměrně nízká. Jako kompromis mezi nutností implementovat RPC v řešení třetí strany a spolehlivostí používáme jednoduše odesílání UDP. K tomuto schématu se vrátíme později.

Sledování

Máme dva typy protokolů: protokoly shromážděné správci na jejich serverech a protokoly napsané vývojáři z kódu. Odpovídají dvěma typům metrik: systém a produkt.

Systémové metriky

Funguje na všech našich serverech netdata, která shromažďuje statistiky a odesílá je na Grafitový uhlík. Proto se jako úložný systém používá ClickHouse a ne například Whisper. V případě potřeby můžete přímo číst z ClickHouse nebo použít grafana pro metriky, grafy a přehledy. Jako vývojáři máme dostatečný přístup k Netdata a Grafaně.

Metriky produktu

Pro pohodlí jsme napsali spoustu věcí. Existuje například sada běžných funkcí, které umožňují zapisovat Counts, UniqueCounts hodnoty do statistik, které se odesílají někam dál.

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

$stats = statlogsStatData($params)

Následně můžeme používat třídicí a seskupovací filtry a dělat vše, co od statistik chceme – sestavovat grafy, konfigurovat Watchdogy.

Píšeme velmi mnoho metrik počet událostí je od 600 miliard do 1 bilionu za den. My je však chceme zachovat alespoň pár letpochopit trendy v metrikách. Dát to všechno dohromady je velký problém, který jsme zatím nevyřešili. Řeknu vám, jak to funguje posledních pár let.

Máme funkce, které zapisují tyto metriky do místní memcachesnížit počet vstupů. Jednou za krátkou dobu spuštěn lokálně stats-daemon shromažďuje všechny záznamy. Dále démon sloučí metriky do dvou vrstev serverů sběrače kulatiny, který agreguje statistiky z hromady našich strojů, aby vrstva za nimi neodemřela.

FAQ o architektuře a práci VKontakte

V případě potřeby můžeme zapisovat přímo do logů-sběratelů.

FAQ o architektuře a práci VKontakte

Ale zápis z kódu přímo do kolektorů, obcházení stas-daemom, je špatně škálovatelné řešení, protože zvyšuje zatížení kolektoru. Řešení je vhodné pouze v případě, že z nějakého důvodu nemůžeme na počítači vyvolat démona memcache stats-daemon, nebo se zhroutil a šli jsme přímo.

Dále logs-collectors sloučí statistiky do mňauDB - toto je naše databáze, do které lze ukládat i metriky.

FAQ o architektuře a práci VKontakte

Poté můžeme z kódu provést binární výběry „blízko SQL“.

FAQ o architektuře a práci VKontakte

Experiment

V létě 2018 jsme měli interní hackathon a přišel nápad zkusit nahradit červenou část diagramu něčím, co by mohlo ukládat metriky v ClickHouse. Máme logy na ClickHouse - proč to nezkusit?

FAQ o architektuře a práci VKontakte

Měli jsme schéma, které zapisovalo protokoly přes KittenHouse.

FAQ o architektuře a práci VKontakte

Rozhodli jsme se přidejte do diagramu další „*Dům“., který obdrží přesně metriky ve formátu, jak je zapisuje náš kód přes UDP. Pak je tento *House promění na vložky, jako klády, kterým KittenHouse rozumí. Tyto protokoly umí perfektně doručit do ClickHouse, který by je měl umět přečíst.

FAQ o architektuře a práci VKontakte

Schéma s databází memcache, stats-daemon a logs-collectors je nahrazeno tímto.

FAQ o architektuře a práci VKontakte

Schéma s databází memcache, stats-daemon a logs-collectors je nahrazeno tímto.

  • Zde je odeslání z kódu, který je napsán lokálně v StatsHouse.
  • StatsHouse zapisuje metriky UDP, již převedené na SQL inserty, do KittenHouse v dávkách.
  • KittenHouse je pošle do ClickHouse.
  • Pokud je chceme číst, pak je čteme vynecháním StatsHouse – přímo z ClickHouse pomocí běžného SQL.

Je to ještě? experiment, ale líbí se nám, jak to dopadne. Pokud problémy se schématem opravíme, možná na něj přejdeme úplně. Osobně v to doufám.

systém nešetří železo. Je potřeba méně serverů, nejsou potřeba místní démoni statistik a sběrače protokolů, ale ClickHouse vyžaduje větší server než ty v aktuálním schématu. Je potřeba méně serverů, ale musí být dražší a výkonnější.

Nasadit

Nejprve se podívejme na nasazení PHP. Vyvíjíme se v git: použití GitLab и TeamCity pro nasazení. Vývojové větve jsou sloučeny do hlavní větve, z masteru pro testování jsou sloučeny do stagingu a ze stagingu do výroby.

Před nasazením se vezme aktuální produkční větev a předchozí a v nich se zvažují diff soubory - změny: vytvořeno, odstraněno, změněno. Tato změna je zaznamenána v binlogu speciálního copyfast enginu, který dokáže rychle replikovat změny na celou naši serverovou flotilu. To, co je zde použito, není kopírování přímo, ale replikace drbů, když jeden server posílá změny svým nejbližším sousedům, ty svým sousedům a tak dále. To vám umožní aktualizovat kód v desítkách a jednotkách sekund napříč celou flotilou. Když změna dosáhne místní repliky, aplikuje tyto záplaty na svou lokální souborový systém. Vrácení zpět se také provádí podle stejného schématu.

Hodně nasazujeme i kPHP a má na sobě i vlastní vývoj git podle výše uvedeného schématu. Od tohoto Binární HTTP server, pak nemůžeme vytvořit diff - binární soubor vydání váží stovky MB. Proto je zde další možnost - verze je zapsána binlog copyfast. S každým sestavením se zvyšuje a během rollbacku se také zvyšuje. Verze replikovány na servery. Místní copyfastové vidí, že do binlogu vstoupila nová verze, a stejnou replikací klepů si vezmou nejnovější verzi binárního souboru pro sebe, aniž by unavili náš hlavní server, ale pečlivě rozložili zátěž po síti. Co následuje ladné opětovné spuštění pro novou verzi.

Pro naše motory, které jsou také v podstatě binární, je schéma velmi podobné:

  • git hlavní větev;
  • binární v deb;
  • verze je zapsána do binlog copyfast;
  • replikovány na servery;
  • server vytáhne nový soubor .dep;
  • dpkg -i;
  • elegantní restart na novou verzi.

Rozdíl je v tom, že náš binární soubor je zabalen v archivech deba při jejich odčerpávání dpkg -i jsou umístěny v systému. Proč je kPHP nasazen jako binární a motory jsou nasazeny jako dpkg? Stalo se to tak. Funguje to - nesahejte na to.

Užitečné odkazy:

Alexey Akulovich je jedním z těch, kteří jako součást Programového výboru pomáhají PHP Rusko 17. května se stane největší událostí pro vývojáře PHP v poslední době. Podívejte se, jaké máme skvělé PC, jaké Řečníci (dva z nich vyvíjejí jádro PHP!) - vypadá to jako něco, co nemůžete minout, pokud píšete PHP.

Zdroj: www.habr.com

Přidat komentář