Michail Salosin. Golang Meetup. Využití Go v backendu aplikace "Sleduj+"

Michaela Salosina (dále – MS): – Ahoj všichni! Jmenuji se Michal. Pracuji jako backend vývojář ve společnosti MC2 Software a povím vám o použití Go v backendu mobilní aplikace „Sleduj+“.

Michail Salosin. Golang Meetup. Využití Go v backendu aplikace "Sleduj+"

Má někdo z přítomných rád hokej?

Michail Salosin. Golang Meetup. Využití Go v backendu aplikace "Sleduj+"

Pak je tato aplikace pro vás. Je určena pro systémy Android a iOS a slouží k prohlížení přenosů různých sportovních událostí online i ze záznamu. V aplikaci se také nachází různá statistika, textové přenosy, tabulky konferencí, turnajů a další informace užitečné pro fanoušky.

Michail Salosin. Golang Meetup. Využití Go v backendu aplikace "Sleduj+"

V aplikaci je také funkce videomomentů, tedy můžete se podívat na ty nejzajímavější okamžiky zápasů (branky, bitky, trestné střílení atd.). Pokud se vám nechce sledovat celý přenos, můžete si prohlédnout pouze to nejzajímavější.

Co jsme použili při vývoji?

Hlavní část byla napsána v Go. Ten API, se kterým komunikovaly mobilní klienty, byl napsán v Go. Také byl napsán v Go servis pro zasílání push notifikací na mobilní zařízení. Navíc jsme museli napsat své vlastní ORM, o kterém možná někdy povíme. A napsali jsme v Go také několik drobných služeb: resize a nahrávání obrázků pro straně editorů…

Jako databázi jsme použili PostgreSQL. Rozhraní pro editory bylo napsáno v Ruby on Rails s využitím gemu ActiveAdmin. Na Ruby byl napsán i import statistik od dodavatele statistik.

Pro systémové testy API jsme použili jednotkový test framework v Pythonu. Memcached je používán pro omezení API plateb, Chef – pro správu konfigurací, Zabbix – pro shromažďování a monitorování interních statistických dat systému. Graylog2 – pro shromažďování logů, Slate – to je dokumentace API pro zákazníky.

Michail Salosin. Golang Meetup. Využití Go v backendu aplikace "Sleduj+"

Výběr protokolu

První problém, se kterým jsme se potýkali: museli jsme vybrat protokol pro interakci backendu s mobilními klienty, vycházející z následujících bodů…

  • Nejdůležitější požadavek: data na klientech musí být aktualizována v reálném čase. To znamená, že všichni, kteří v tuto chvíli sledují přenos, by měli dostávat aktualizace téměř okamžitě.
  • Pro zjednodušení jsme předpokládali, že data, která se synchronizují s klienty, nejsou mazána, ale skrývána pomocí speciálních příznaků.
  • Různé specifické dotazy (například statistiky, složení týmů, týmové statistiky) jsou obdržené pomocí běžných GET dotazů.
  • Navíc, systém měl bez problémů zvládnout 100 tisíc uživatelů současně.

Z toho jsme měli dvě možnosti protokolu:

  1. Websockety. Ale nepotřebovali jsme kanály od klienta k serveru. Potřebovali jsme pouze odesílat aktualizace ze serveru na klienta, takže websocket byl nadbytečná možnost.
  2. Server-Sent Events (SSE) byly ideální! Jsou dostatečně jednoduché a v podstatě splňují vše, co potřebujeme.

Server-Sent Events

Několik slov o tom, jak to funguje...

Funguje to na vrcholu http připojení. Klient odešle požadavek, na který server odpovídá Content-Type: text/event-stream a neuzavírá připojení s klientem, ale pokračuje v zapisování dat do připojení:

Michail Salosin. Golang Meetup. Využití Go v backendu aplikace "Sleduj+"

Data lze odesílat v formátu dohodnutém s klienty. V našem případě jsme je odesílali tímto způsobem: do pole event se uvádělo jméno změněné struktury (člověk, hráč) a do pole data – JSON s novými, změněnými poli pro hráče.

Teď k tomu, jak probíhá samotná interakce.

  • Nejprve klient určuje, kdy naposledy proběhla synchronizace se službou: podívá se do své lokální databáze a určí datum poslední změny, kterou má zaznamenanou.
  • Odešle požadavek s tímto datem.
  • Na oplátku mu pošleme všechna aktualizace, které nastaly od tohoto data.
  • Poté se spojí s live kanálem a neuzavírá ho, dokud potřebuje tyto aktualizace:

Michail Salosin. Golang Meetup. Využití Go v backendu aplikace "Sleduj+"

Posíláme mu seznam změn: pokud někdo dal gól – měníme skóre zápasu, pokud někdo dostal zranění – to je také odesláno v reálném čase. Takto klienti okamžitě získávají aktuální data v toku událostí zápasu. Periodicky, aby klient věděl, že server nezkolaboval, že se nic nestalo, posíláme jednou za 15 sekund timestamp – aby věděl, že je vše v pořádku a není třeba se znovu připojovat.

Jak se spravuje live připojení?

  • Nejprve vytvoříme kanál, do kterého budou přicházet aktualizace s bufferem.
  • Poté se přihlásíme k odběru aktualizací pro tento kanál.
  • Nastavíme správný záhlaví, aby klient věděl, že je vše v pořádku.
  • Odesíláme první ping. Jednoduše zapisujeme aktuální timestamp připojení.
  • Po tomto kroku čteme z kanálu v cyklu, dokud není kanál aktualizací uzavřen. Do kanálu pravidelně přichází buď aktuální timestamp, nebo změny, které již zapisujeme do otevřených spojení.

Michail Salosin. Golang Meetup. Využití Go v backendu aplikace "Sleduj+"

První problém, se kterým jsme se setkali, spočíval v tom, že na každé otevřené spojení s klientem jsme vytvářeli časovač, který tikal jednou za 15 sekund – to znamená, že pokud jsme měli otevřených 6000 spojení s jedním serverem (s jedním API serverem), bylo vytvořeno 6000 časovačů. To mělo za následek, že stroj nezvládal potřebné zatížení. Problém nebyl pro nás tak zřejmý, ale trochu nám pomohli a my jsme jej odstranili.

V důsledku toho nyní ping přichází ze stejného kanálu, ze kterého přichází update.

Celkově tedy máme jen jeden časovač, který tiká každých 15 sekund.

Zde je několik pomocných funkcí – odeslání hlavičky, pingu a samotné struktury. To znamená, že zde je předáván název tabulky (person, match, season) a informace o této položce:

Michail Salosin. Golang Meetup. Využití Go v backendu aplikace "Sleduj+"

Mechanismus odesílání aktualizací

Nyní trochu o tom, odkud se změny berou. Máme několik lidí, editorů, kteří v reálném čase sledují přenos. Ti vytvářejí všechny události: někoho vyloučili, někdo se zranil, nějaká výměna...

Pomocí CMS se data dostávají do databáze. Poté databáze pomocí mechanismu Listen/Notify informuje o tom API servery. API servery již rozesílají tyto informace klientům. Tímto způsobem máme v podstatě k databázi připojeno jen několik serverů a na databázi není žádná zvláštní zátěž, protože klient s databází nijak přímo neinteraguje:

Michail Salosin. Golang Meetup. Využití Go v backendu aplikace "Sleduj+"

PostgreSQL: Listen/Notify

Mechanismus Listen/Notify v PostgreSQL umožňuje informovat odběratele událostí o tom, že došlo k nějaké změně – byla vytvořena nějaká položka v databázi. Pro toto jsme napsali jednoduchý trigger a funkci:

Michail Salosin. Golang Meetup. Využití Go v backendu aplikace "Sleduj+"

Při insertu nebo změně položky voláme funkci notify na kanálu data_updates, předáváme tam název tabulky a identifikátor položky, která byla změněna nebo vložena.

Na všechny tabulky, které mají být synchronizovány s klientem, definujeme trigger, který po změně/aktualizaci položky volá funkci uvedenou na snímku níže.
Jak se API přihlašuje k těmto změnám?

Vytváří se mechanismus Fanout – ten rozesílá zprávy klientům. Shromažďuje všechny kanály klientů a rozesílá aktualizace, které obdržel přes tyto kanály:

Michail Salosin. Golang Meetup. Využití Go v backendu aplikace "Sleduj+"

Zde je standardní knihovna pq, která se připojuje k databázi a říká, že chce sledovat kanál (data_updates), kontroluje, zda je spojení otevřené a vše v pořádku. Přeskakuji kontrolu chyb, abych ušetřil místo (kontrola chyb může být riskantní).

Dále asynchronně nastavíme Ticker, který bude posílat ping každých 15 sekund, a začneme poslouchat kanál, na který jsme se přihlásili. Pokud obdržíme ping, publikujeme tento ping. Pokud obdržíme nějaký záznam, zveřejníme tento záznam všem předplatitelům tohoto Fanoutu.

Jak funguje Fan-out?

Česky se to překládá jako „rozbočovač“. Máme jeden objekt, který registruje předplatitele, kteří chtějí dostávat nějaké aktualizace. A jakmile k tomuto objektu dorazí aktualizace, rozloží tuto aktualizaci všem stávajícím předplatitelům. Je to dost jednoduché:

Michail Salosin. Golang Meetup. Využití Go v backendu aplikace "Sleduj+"

Jak je to realizováno v Go:

Michail Salosin. Golang Meetup. Využití Go v backendu aplikace "Sleduj+"

Existuje struktura, která se synchronizuje pomocí Mutexů. Má pole, které uchovává stav připojení Fanoutu k databázi, tj. v tuto chvíli naslouchá a bude přijímat aktualizace, a také seznam všech stávajících kanálů – mapa, jejíž klíčem je kanál a struct ve formě hodnot (v podstatě se v žádném případě nepoužívá).

Dva metody – Connected a Disconnected – umožňují Fanoutu oznámit, že máme spojení s databází, že se objevilo, a že spojení s databází bylo přerušeno. Ve druhém případě je třeba všechny klienty odpojit a informovat je, že již nemohou nic poslouchat a aby se znovu připojili, protože spojení s nimi bylo ukončeno.

Existuje také metoda Subscribe, která přidává kanál do „posluchačů“:

Michail Salosin. Golang Meetup. Využití Go v backendu aplikace "Sleduj+"

Existuje metoda Unsubscribe, která odstraňuje kanál z posluchačů, pokud se klient odpojil, a také metoda Publish, která umožňuje rozeslat zprávu všem předplatitelům.

Otázka: – Co se přes tento kanál přenáší?

MC: – Přenáší se model, který se změnil, nebo ping (v podstatě pouze číslo, целое значение).

MC: – Můžete posílat cokoliv, jakoukoli strukturu publikovat – ta se jednoduše převede na JSON a to je vše.

MC: – Dostáváme notifikaci z „Postgresu“ – obsahuje název tabulky a identifikátor. Podle názvu tabulky získáme a podle identifikátoru získáme požadovaný záznam, a tuto strukturu posíláme na publikaci.

Infrastruktura

Jak to vypadá z pohledu infrastruktury? Máme 7 fyzických serverů: jeden z nich je zcela vyhrazen pro databázi, na ostatních šesti běží virtuální stroje. Máme 6 kopií API: každá virtuální mašina s API běží na samostatném fyzickém serveru – to pro spolehlivost.

Michail Salosin. Golang Meetup. Využití Go v backendu aplikace "Sleduj+"

Máme dvě frontendy, na kterých je nainstalován Keepalived pro zlepšení dostupnosti, aby v případě potřeby mohl jeden frontend nahradit druhý. Dále – dvě kopie CMS.

K dispozici je také importér statistik. Existuje DB Slave, ze kterého se pravidelně dělají zálohy. Je tu Pigeon Pusher – aplikace, která rozesílá push notifikace klientům, a také infrastruktura: Zabbix, Graylog2 a Chef.

Tato infrastruktura je ve skutečnosti nadbytečná, protože 100 tisíc lze obsluhovat i s menším počtem serverů. Ale hardware byl k dispozici – využili jsme ho (řekli nám, že to jde – proč ne).

Výhody Go

Poté, co jsme na této aplikaci pracovali, se ukázaly tyto zřejmé výhody Go.

  • Skvělá http-knihovna. Pomocí ní lze vytvořit spoustu věcí již „z krabice“.
  • A také kanály, které nám velmi snadno umožnily implementovat mechanismus zasílání upozornění klientům.
  • Úžasná věc Race detector nám umožnila odstranit několik kritických chyb (stagingová infrastruktura). Všechno, co běží na stagingu – je spuštěno a zkompilováno s klíčem Race; a my můžeme na stagingové infrastruktuře vidět, jaké máme potenciální problémy.
  • Minimalismus a jednoduchost jazyka.

Michail Salosin. Golang Meetup. Využití Go v backendu aplikace "Sleduj+"

Hledáme vývojáře! Pokud někdo chce – prosím.

Otázky

Otázka z publika (dále – O): – Mám dojem, že jste přehlédli jeden důležitý bod ohledně Fan-out. Chápu správně, že když posíláte klientovi odpověď, zablokujete se, pokud klient nechce číst?

MC: – Ne, nezablokováváme se. Za prvé, všechno máme za nginxem, což znamená, že s pomalými klienty nejsou žádné problémy. Za druhé, klient má kanál s bufferem – v podstatě tam můžeme poslat až stovku aktualizací... Pokud nemůžeme zapisovat do kanálu, ten se odmazává. Pokud vidíme, že se kanál zablokoval, jednoduše ho zavřeme a hotovo – klient se znovu připojí, pokud dojde k nějakému problému. Takže blokace zde v podstatě nevznikají.

Otázka: – Nebylo by možné posílat přímo do Listen/Notify zápis, místo identifikátoru tabulky?

MC: – Listen/Notify má omezení na 8000 bajtů pro preload, který posílá. V podstatě by to bylo možné, pokud bychom pracovali s menším množstvím dat, ale myslím, že tak [jak to děláme my] je to prostě spolehlivější. Omezení je v samotném "Postgresu".

Otázka: – Dostávají klienti aktualizace k zápasům, které je nezajímají?

MC: – V podstatě ano. Obvykle probíhá 2-3 zápasy současně, a to je poměrně vzácné. Pokud klient sleduje něco, obvykle se dívá na ten zápas, který probíhá. Potom má klient místní databázi, do které se ukládají všechny tyto aktualizace, a i bez připojení k internetu si klient může prohlédnout všechny proběhlé zápasy, o kterých má aktualizace. V zásadě synchronizujeme naši databázi na serveru s místní databází klienta, aby mohl pracovat i offline.

Otázka: – Proč jste vytvořili svou ORM?

Alexej (jeden z vývojářů „Smutri+“): – V té době (to bylo před rokem) bylo ORM méně, než je nyní, kdy jich je docela hodně. Z většiny existujících ORM se mi nejvíc nelíbí to, že většina z nich pracuje na prázdných rozhraních. To znamená, že metody, které mají tato ORM, jsou připraveny přijmout cokoliv: strukturu, ukazatel na strukturu, číslo, něco zcela nesouvisejícího...

Naše ORM generuje struktury na základě datového modelu. Sama. A proto jsou všechny metody konkrétní, nepoužívají reflexi atd. Přijímají struktury a očekávají, že použijí ty struktury, které přijdou.

Otázka: – Kolik lidí se zúčastnilo?

MC: – V počátečním stádiu se zúčastnili dva lidé. Asi v červnu jsme začali, v srpnu byla většina hotová (první verze). V září byl vydán.

Otázka: – Tam, kde popisujete SSE, nepoužíváte timeout. Proč ne?

MC: – Pokud to vezmeme upřímně, SSE je v podstatě protokol html5: standard SSE je určen pro komunikaci s prohlížeči, jak chápu. Má doplňkové funkce, aby se prohlížeče mohly znovu připojit (a tak dále), ale ty nejsou potřeba, protože jsme měli klienty, kteří mohli realizovat jakoukoli logiku připojení a získávání informací. Vytvořili jsme spíše něco jako SSE.
Nebylo to nutné. Jak rozumím, klienti implementovali mechanismus připojení prakticky od základů. Bylo jim to v podstatě jedno.

Otázka: – Jaké další nástroje jste používali?

MC: – Nejaktivněji jsme používali govet a golint, aby byl styl jednotný, a také gofmt. Nic víc jsme nepoužívali.

Otázka: – S čím jste prováděli ladění?

MC: – Ladění probíhalo většinou pomocí testů. Žádný debugger, GOP jsme nepoužívali.

Otázka: – Můžete vrátit snímek, kde je implementována funkce Publish? Nezlobí vás jednoznakové názvy proměnných?

MC: – Ne. Mají dost "úzkou" viditelnost. Kromě tohoto místa se nikde jinde nepoužívají (kromě vnitřností této třídy), a je velmi kompaktní – zabírá pouze 7 řádků.

Otázka: – Připadá mi to nějak neintuitivní...

MC: – Ne-ne, to je opravdu kód! Není to otázka stylu. Je to prostě taková utilitární, úplně malá třída – má pouze 3 pole uvnitř třídy...

Michail Salosin. Golang Meetup. Využití Go v backendu aplikace "Sleduj+"

MC: – V zásadě všechny ty údaje, které se synchronizují s klienty (sezónní zápasy, hráči), se nemění. Jinými slovy, pokud budeme dělat nějaký jiný sport, kde bude potřeba měnit zápas, jednoduše to zohledníme v nové verzi klienta, zatímco staré verze klienta budou zablokovány.

Otázka: – Existují nějaké externí balíčky pro správu závislostí?

MC: – Používali jsme go dep.

Otázka: – V tématu přednášky bylo něco o videu, ale v přednášce o videu nic není.

MC: – Ne, v tématu o videu nemám nic. Jmenuje se to "Sleduj+" – tak se aplikace jmenuje.

Otázka: – Říkali jste, že to streamujete klientům?..

MC: – Streamingovým videem jsme se nezabývali. To plně dělala "Megafon". Ano, neřekl jsem, že aplikace patří Megafonu.

MC: – Go – pro odesílání všech dat – o účtu, událostech zápasu, statistikách... Go – je kompletní backend pro aplikaci. Klient se musí dozvědět, jaký odkaz použít pro přehrávač, aby uživatel mohl sledovat zápas. Máme odkazy na videa a streamy, které jsou připravené.

Přehrát video

Malá reklama 🙂

Děkujeme, že s námi zůstáváte. Líbí se vám naše články? Chcete vidět více zajímavých materiálů? Podpořte nás objednávkou nebo doporučením známým, cloudové VPS pro vývojáře od 4,99 $, unikátní alternativa entry-level serverů, kterou jsme pro vás vymysleli: Všechny pravdy o VPS (KVM) E5-2697 v3 (6 jader) 10GB DDR4 480GB SSD 1Gbps od 19 $ nebo jak správně rozdělit server? (k dispozici varianty s RAID1 a RAID10, až 24 jader a až 40GB DDR4).

Dell R730xd je dvakrát levnější v datovém centru Equinix Tier IV v Amsterdamu? Jen u nás 2 x Intel TetraDeca-Core Xeon 2x E5-2697v3 2.6GHz 14C 64GB DDR4 4x960GB SSD 1Gbps 100 TB od 199 $ v Nizozemsku! Dell R420 — 2x E5-2430 2.2GHz 6C 128GB DDR3 2x960GB SSD 1Gbps 100TB — od 99 $! Čtěte o tom Jak postavit infrastrukturu podnikové třídy s použitím serverů Dell R730xd E5-2650 v4 v hodnotě 9000 eur za pakatel?

Zdroj: habr.com

Koupit spolehlivý hosting pro webové stránky s ochranou proti DDoS, VPS VDS servery 🔥 Koupit spolehlivý hosting pro webové stránky s ochranou proti DDoS, VPS VDS servery | ProHoster