Mihail Salosin. Golang susret. Korištenje Go-a u pozadini aplikacije Look+

Mikhail Salosin (u daljnjem tekstu – MS): - Bok svima! Moje ime je Michael. Radim kao backend developer u MC2 Softwareu, a govorit ću o korištenju Go-a u backendu mobilne aplikacije Look+.

Mihail Salosin. Golang susret. Korištenje Go-a u pozadini aplikacije Look+

Voli li netko ovdje hokej?

Mihail Salosin. Golang susret. Korištenje Go-a u pozadini aplikacije Look+

Onda je ova aplikacija za vas. Namijenjen je za Android i iOS i koristi se za gledanje prijenosa raznih sportskih događaja online i snimljenih. Aplikacija također sadrži razne statistike, tekstualne prijenose, tablice za konferencije, turnire i druge informacije korisne za navijače.

Mihail Salosin. Golang susret. Korištenje Go-a u pozadini aplikacije Look+

Također u aplikaciji postoji nešto poput video trenutaka, tj. možete gledati najvažnije trenutke utakmica (golove, borbe, raspucavanja itd.). Ako ne želite gledati cijeli prijenos, možete pogledati samo najzanimljivije.

Što ste koristili u razvoju?

Glavni dio je napisan u Go. API s kojim mobilni klijenti komuniciraju napisan je u Go. U Gou je napisana i usluga za slanje push obavijesti na mobitele. Također smo morali napisati vlastiti ORM, o kojem ćemo možda jednog dana razgovarati. Pa, neke male usluge su napisane u Go-u: promjena veličine i učitavanje slika za urednike...

Kao bazu podataka koristili smo PostgreSQL. Sučelje uređivača napisano je u Ruby on Rails pomoću dragulja ActiveAdmin. Uvoz statistike od pružatelja statistike također je napisan u Rubyju.

Za sistemske API testove koristili smo Python unittest. Memcached se koristi za prigušivanje API poziva plaćanja, "Chef" se koristi za kontrolu konfiguracije, Zabbix se koristi za prikupljanje i praćenje statistike internog sustava. Graylog2 je za prikupljanje zapisa, Slate je API dokumentacija za klijente.

Mihail Salosin. Golang susret. Korištenje Go-a u pozadini aplikacije Look+

Izbor protokola

Prvi problem na koji smo naišli: trebali smo odabrati protokol za interakciju između pozadinskog i mobilnog klijenata, na temelju sljedećih točaka...

  • Najvažniji zahtjev: podaci o klijentima moraju se ažurirati u stvarnom vremenu. Odnosno, svi koji trenutno gledaju prijenos trebali bi primati ažuriranja gotovo trenutno.
  • Da pojednostavimo stvari, pretpostavili smo da se podaci koji su sinkronizirani s klijentima ne brišu, već se skrivaju pomoću posebnih oznaka.
  • Sve vrste rijetkih zahtjeva (kao što su statistike, sastavi momčadi, statistike momčadi) dobivaju se običnim GET zahtjevima.
  • Plus, sustav je morao lako podržavati 100 tisuća korisnika u isto vrijeme.

Na temelju toga imali smo dvije mogućnosti protokola:

  1. Websockets. Ali nismo trebali kanale od klijenta do poslužitelja. Trebali smo samo slati ažuriranja s poslužitelja na klijenta, tako da je websocket suvišna opcija.
  2. Događaji poslani s poslužitelja (SSE) ispali su kako treba! Vrlo je jednostavan i u biti zadovoljava sve što nam je potrebno.

Događaji poslani s poslužitelja

Par riječi o tome kako ova stvar radi...

Radi povrh http veze. Klijent šalje zahtjev, poslužitelj odgovara Content-Type: text/event-stream i ne zatvara vezu s klijentom, već nastavlja pisati podatke na vezu:

Mihail Salosin. Golang susret. Korištenje Go-a u pozadini aplikacije Look+

Podaci se mogu slati u formatu dogovorenom s klijentima. U našem slučaju poslali smo ga u ovom obliku: ime promijenjene strukture (osoba, igrač) poslano je u polje događaja, a JSON s novim, promijenjenim poljima za igrača u polje podataka.

Razgovarajmo sada o tome kako funkcionira sama interakcija.

  • Prvo što klijent radi je utvrđivanje zadnjeg vremena sinkronizacije sa servisom: pregledava svoju lokalnu bazu podataka i utvrđuje datum zadnje promjene koju je zabilježio.
  • Šalje zahtjev s ovim datumom.
  • Kao odgovor, šaljemo mu sva ažuriranja koja su se dogodila od tog datuma.
  • Nakon toga uspostavlja vezu s kanalom uživo i ne zatvara se dok ne zatreba ova ažuriranja:

Mihail Salosin. Golang susret. Korištenje Go-a u pozadini aplikacije Look+

Šaljemo mu listu promjena: ako netko zabije gol, mijenjamo rezultat utakmice, ako se ozlijedi, to se također šalje u realnom vremenu. Stoga klijenti trenutno dobivaju ažurne podatke u feedu događaja utakmice. Povremeno, kako bi klijent shvatio da poslužitelj nije umro, da mu se ništa nije dogodilo, šaljemo vremensku oznaku svakih 15 sekundi - da zna da je sve u redu i da nema potrebe za ponovnim spajanjem.

Kako se servisira veza uživo?

  • Prije svega, stvaramo kanal u koji će se primati ažuriranja u međuspremniku.
  • Nakon toga se pretplaćujemo na ovaj kanal kako bismo primali ažuriranja.
  • Postavljamo ispravno zaglavlje kako bi klijent znao da je sve u redu.
  • Pošalji prvi ping. Jednostavno bilježimo trenutnu vremensku oznaku veze.
  • Nakon toga čitamo s kanala u petlji dok se kanal ažuriranja ne zatvori. Kanal povremeno prima trenutnu vremensku oznaku ili promjene koje već pišemo za otvorene veze.

Mihail Salosin. Golang susret. Korištenje Go-a u pozadini aplikacije Look+

Prvi problem na koji smo naišli bio je sljedeći: za svaku vezu otvorenu s klijentom kreirali smo mjerač vremena koji je otkucavao jednom svakih 15 sekundi - ispada da ako smo imali 6 tisuća otvorenih veza s jednim strojem (s jednim API poslužiteljem), 6 stvoreno je tisuće mjerača vremena. To je dovelo do toga da stroj nije držao potrebno opterećenje. Problem nam nije bio toliko očit, ali dobili smo malu pomoć i riješili smo ga.

Kao rezultat toga, sada naš ping dolazi s istog kanala s kojeg dolazi ažuriranje.

Sukladno tome, postoji samo jedan mjerač vremena koji otkucava svakih 15 sekundi.

Ovdje postoji nekoliko pomoćnih funkcija - slanje zaglavlja, pinga i same strukture. Odnosno, naziv tablice (osoba, utakmica, sezona) i informacije o ovom unosu prenose se ovdje:

Mihail Salosin. Golang susret. Korištenje Go-a u pozadini aplikacije Look+

Mehanizam za slanje ažuriranja

Sada malo o tome odakle dolaze promjene. Imamo nekoliko ljudi, urednika, koji prate prijenos u realnom vremenu. Oni kreiraju sve događaje: netko je isključen, netko ozlijeđen, neka zamjena...

Pomoću CMS-a podaci ulaze u bazu podataka. Nakon toga baza podataka o tome obavještava API poslužitelje pomoću mehanizma Listen/Notify. API poslužitelji već šalju te informacije klijentima. Dakle, u biti imamo samo nekoliko poslužitelja povezanih s bazom podataka i nema posebnog opterećenja baze podataka, jer klijent ni na koji način ne komunicira izravno s bazom podataka:

Mihail Salosin. Golang susret. Korištenje Go-a u pozadini aplikacije Look+

PostgreSQL: Slušaj/obavijesti

Listen/Notify mehanizam u Postgresu omogućuje da obavijestite pretplatnike događaja da se neki događaj promijenio – neki zapis je kreiran u bazi podataka. Da bismo to učinili, napisali smo jednostavan okidač i funkciju:

Mihail Salosin. Golang susret. Korištenje Go-a u pozadini aplikacije Look+

Prilikom umetanja ili mijenjanja zapisa, pozivamo funkciju obavijesti na kanalu data_updates, prosljeđujući tamo naziv tablice i identifikator zapisa koji je promijenjen ili umetnut.

Za sve tablice koje se moraju sinkronizirati s klijentom, definiramo okidač, koji nakon promjene / ažuriranja zapisa poziva funkciju naznačenu na slajdu ispod.
Kako se API pretplaćuje na ove promjene?

Stvoren je Fanout mehanizam - šalje poruke klijentu. Prikuplja sve korisničke kanale i šalje ažuriranja koja je primila putem ovih kanala:

Mihail Salosin. Golang susret. Korištenje Go-a u pozadini aplikacije Look+

Ovdje standardna biblioteka pq, koja se spaja na bazu i kaže da želi slušati kanal (data_updates), provjerava da li je veza otvorena i da je sve u redu. Izostavljam provjeru pogrešaka radi uštede prostora (neprovjeravanje je opasno).

Zatim asinkrono postavljamo Ticker koji će slati ping svakih 15 sekundi i počinjemo slušati kanal na koji smo pretplaćeni. Ako primimo ping, objavit ćemo ga. Ako primimo neku vrstu unosa, tada ćemo ga objaviti svim pretplatnicima ovog Fanouta.

Kako funkcionira Fan-out?

Na ruskom se ovo prevodi kao "razdjelnik". Imamo jedan objekt koji registrira pretplatnike koji žele primati neka ažuriranja. I čim ažuriranje stigne u ovaj objekt, on ga distribuira svim svojim pretplatnicima. Dovoljno jednostavno:

Mihail Salosin. Golang susret. Korištenje Go-a u pozadini aplikacije Look+

Kako je to implementirano u Go:

Mihail Salosin. Golang susret. Korištenje Go-a u pozadini aplikacije Look+

Postoji struktura, sinkronizirana je pomoću Mutexa. Ima polje koje sprema stanje veze Fanouta na bazu, tj. trenutno sluša i dobivat će ažuriranja, kao i popis svih dostupnih kanala - mapu, čiji je ključ kanal i struktura u obliku vrijednosti (u biti se ne koristi ni na koji način).

Dvije metode - Connected i Disconnected - omogućuju nam da kažemo Fanoutu da imamo vezu s bazom, pojavila se i da je veza s bazom prekinuta. U drugom slučaju trebate odspojiti sve klijente i reći im da više ne mogu ništa slušati i da se ponovno spoje jer je veza s njima prekinuta.

Postoji i metoda Pretplati se koja kanal dodaje u “slušatelje”:

Mihail Salosin. Golang susret. Korištenje Go-a u pozadini aplikacije Look+

Postoji metoda Unsubscribe, koja uklanja kanal od slušatelja ako se klijent prekine, kao i metoda Publish, koja vam omogućuje slanje poruke svim pretplatnicima.

Pitanje: – Što se prenosi ovim kanalom?

MS: – Model koji se promijenio ili se prenosi ping (u suštini samo broj, cijeli broj).

MS: – Možete poslati bilo što, poslati bilo koju strukturu, objaviti – samo se pretvori u JSON i to je to.

MS: – Primamo obavijest od Postgresa – sadrži naziv tablice i identifikator. Na temelju naziva tablice i identifikatora dobivamo zapis koji nam je potreban, a zatim tu strukturu šaljemo na objavu.

Infrastruktura

Kako to izgleda iz perspektive infrastrukture? Imamo 7 hardverskih poslužitelja: jedan od njih je potpuno posvećen bazi podataka, ostalih šest pokreće virtualne strojeve. Postoji 6 kopija API-ja: svaki virtualni stroj s API-jem radi na zasebnom hardverskom poslužitelju - ovo je radi pouzdanosti.

Mihail Salosin. Golang susret. Korištenje Go-a u pozadini aplikacije Look+

Imamo dva sučelja s instaliranim Keepalivedom radi poboljšanja pristupačnosti, tako da ako se nešto dogodi, jedno sučelje može zamijeniti drugo. Također – dvije kopije CMS-a.

Tu je i uvoznik statistike. Postoji DB Slave iz kojeg se povremeno rade sigurnosne kopije. Tu je Pigeon Pusher, aplikacija koja šalje push obavijesti klijentima, kao i infrastrukturne stvari: Zabbix, Graylog2 i Chef.

Zapravo, ova je infrastruktura suvišna, jer se 100 tisuća može poslužiti s manje poslužitelja. Ali bilo je željeza - koristili smo ga (rečeno nam je da je moguće - zašto ne).

Prednosti Go

Nakon što smo radili na ovoj aplikaciji, pojavile su se tako očite prednosti Goa.

  • Cool http biblioteka. S njim možete stvoriti dosta toga izvan okvira.
  • Plus, kanali koji su nam omogućili da vrlo jednostavno implementiramo mehanizam za slanje obavijesti klijentima.
  • Prekrasna stvar Race detektor nam je omogućila da eliminiramo nekoliko kritičnih bugova (scenska infrastruktura). Sve što radi na stagingu je pokrenuto, kompajlirano s Race ključem; i mi, sukladno tome, možemo pogledati scensku infrastrukturu da vidimo koje potencijalne probleme imamo.
  • Minimalizam i jednostavnost jezika.

Mihail Salosin. Golang susret. Korištenje Go-a u pozadini aplikacije Look+

Tražimo programere! Ako netko želi, izvolite.

pitanja

Pitanje iz publike (u daljnjem tekstu – B): – Čini mi se da ste propustili jednu važnu točku u vezi Fan-outa. Jesam li ispravno shvatio da kada pošaljete odgovor klijentu, blokirate ga ako klijent ne želi čitati?

MS: - Ne, ne blokiramo. Prvo, sve to imamo iza nginxa, odnosno nema problema sa sporim klijentima. Drugo, klijent ima kanal s međuspremnikom - zapravo, tamo možemo staviti do stotinu ažuriranja... Ako ne možemo pisati na kanal, on ga briše. Ako vidimo da je kanal blokiran, jednostavno ćemo zatvoriti kanal i to je to - klijent će se ponovno spojiti ako dođe do problema. Stoga, u načelu, ovdje nema blokade.

NA: – Nije li moguće odmah poslati zapis u Listen/Notify, a ne tablicu identifikatora?

MS: – Listen/Notify ima ograničenje od 8 tisuća bajtova na predučitavanje koje šalje. U principu bi bilo moguće slati da se radi o maloj količini podataka, ali čini mi se da je ovaj način [kako mi to radimo] jednostavno pouzdaniji. Ograničenja su u samom Postgresu.

NA: – Primaju li kupci ažuriranja o utakmicama koje ih ne zanimaju?

MS: - Općenito, da. U pravilu idu 2-3 utakmice paralelno, ali i to dosta rijetko. Ako klijent nešto gleda, onda obično gleda utakmicu koja se odvija. Zatim, klijent ima lokalnu bazu podataka u koju se zbrajaju sva ta ažuriranja, a čak i bez internetske veze klijent može vidjeti sve prošle utakmice za koje ima ažuriranja. U biti, sinkroniziramo našu bazu podataka na poslužitelju s klijentovom lokalnom bazom podataka kako bi on mogao raditi izvan mreže.

NA: – Zašto ste napravili svoj ORM?

Alexey (jedan od programera Look+): – U to vrijeme (bilo je to prije godinu dana) bilo je manje ORM-ova nego sada, kada ih je dosta. Moja omiljena stvar kod većine ORM-ova vani je da većina njih radi na praznim sučeljima. To jest, metode u tim ORM-ovima spremne su preuzeti bilo što: strukturu, pokazivač strukture, broj, nešto potpuno nebitno...

Naš ORM generira strukture na temelju podatkovnog modela. Sebe. I zato su sve metode konkretne, ne koriste refleksiju itd. Oni prihvaćaju strukture i očekuju da će koristiti te strukture koje dolaze.

NA: – Koliko je ljudi sudjelovalo?

MS: – U početnoj fazi sudjelovale su dvije osobe. Počeli smo negdje u lipnju, au kolovozu je glavni dio bio gotov (prva verzija). U rujnu je bilo izdanje.

NA: – Gdje opisujete SSE, ne koristite timeout. Zašto je to?

MS: – Da budem iskren, SSE je još uvijek html5 protokol: SSE standard je dizajniran za komunikaciju s preglednicima, koliko ja razumijem. Ima dodatne značajke kako bi se preglednici mogli ponovno spojiti (i tako dalje), ali mi ih ne trebamo, jer smo imali klijente koji su mogli implementirati bilo kakvu logiku za povezivanje i primanje informacija. Nismo napravili SSE, nego nešto slično SSE-u. Ovo nije sam protokol.
Nije bilo potrebe. Koliko ja razumijem, klijenti su implementirali mehanizam povezivanja gotovo od nule. Nije im baš bilo svejedno.

NA: – Koje ste dodatne alate koristili?

MS: – Najaktivnije smo koristili govet i golint kako bismo stilski unificirali, kao i gofmt. Ništa drugo nije korišteno.

NA: – Što ste koristili za otklanjanje pogrešaka?

MS: – Otklanjanje pogrešaka većim je dijelom provedeno pomoću testova. Nismo koristili nikakav debugger ili GOP.

NA: – Možete li vratiti slajd na kojem je implementirana funkcija Objavi? Zbunjuju li vas nazivi varijabli od jednog slova?

MS: - Ne. Imaju prilično "uzak" opseg vidljivosti. Ne koriste se nigdje drugdje osim ovdje (osim za unutarnje uređaje ove klase), a vrlo je kompaktan - zauzima samo 7 redaka.

NA: – Nekako još uvijek nije intuitivno...

MS: - Ne, ne, ovo je prava šifra! Ne radi se o stilu. To je jednostavno tako utilitarna, vrlo mala klasa - samo 3 polja unutar klase...

Mihail Salosin. Golang susret. Korištenje Go-a u pozadini aplikacije Look+

MS: – Uglavnom, svi podaci koji se sinkroniziraju s klijentima (sezonske utakmice, igrači) se ne mijenjaju. Grubo rečeno, ako napravimo neki drugi sport u kojem trebamo promijeniti meč, jednostavno ćemo sve uzeti u obzir u novoj verziji klijenta, a stare verzije klijenta će biti banirane.

NA: – Postoje li paketi za upravljanje ovisnosti trećih strana?

MS: – Koristili smo go dep.

NA: – U temi reportaže bilo je nešto o videu, ali u reportaži nije bilo ništa o videu.

MS: – Ne, nemam ništa u temi o videu. Zove se "Look+" - to je naziv aplikacije.

NA: – Rekli ste da se streama klijentima?..

MS: – Nismo se bavili streamingom videa. To je u potpunosti napravio Megafon. Da, nisam rekao da je aplikacija MegaFon.

MS: – Go – za slanje svih podataka – o rezultatu, o događajima na utakmici, statistici... Go je cijela pozadina za aplikaciju. Klijent mora odnekud znati koji link koristiti za igrača kako bi korisnik mogao gledati utakmicu. Imamo veze na videozapise i streamove koji su pripremljeni.

Neki oglasi 🙂

Hvala što ste ostali s nama. Sviđaju li vam se naši članci? Želite li vidjeti više zanimljivog sadržaja? Podržite nas narudžbom ili preporukom prijateljima, cloud VPS za programere od 4.99 USD, jedinstveni analog poslužitelja početne razine, koji smo izmislili za vas: Cijela istina o VPS (KVM) E5-2697 v3 (6 jezgri) 10GB DDR4 480GB SSD 1Gbps od 19 USD ili kako podijeliti poslužitelj? (dostupno s RAID1 i RAID10, do 24 jezgre i do 40 GB DDR4).

Dell R730xd 2 puta jeftiniji u Equinix Tier IV podatkovnom centru u Amsterdamu? Samo ovdje 2 x Intel TetraDeca-Core Xeon 2x E5-2697v3 2.6GHz 14C 64GB DDR4 4x960GB SSD 1Gbps 100 TV od 199 USD u Nizozemskoj! Dell R420 - 2x E5-2430 2.2 Ghz 6C 128 GB DDR3 2x960 GB SSD 1 Gbps 100 TB - od 99 USD! Pročitaj o Kako izgraditi infrastrukturu corp. klase uz korištenje Dell R730xd E5-2650 v4 servera vrijednih 9000 eura za lipu?

Izvor: www.habr.com

Dodajte komentar