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

Mihail Salosin (u daljnjem tekstu MS): Pozdrav svima! Moje ime je Mihail. Ja sam backend developer u MC2 Softwareu i govorit ću o korištenju Goa u backendu mobilne aplikacije "Smotri+".

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

Voli li ovdje itko hokej?

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

Onda je ova aplikacija za vas. Dostupna za Android i iOS, omogućuje vam gledanje prijenosa uživo i snimljenih prijenosa raznih sportskih događaja. Aplikacija također sadrži razne statistike, tekstualne prijenose uživo, tablice konferencija i turnira te druge korisne informacije za navijače.

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

Aplikacija također sadrži video snimke najvažnijih trenutaka, što vam omogućuje gledanje ključnih trenutaka s utakmica (golovi, borbe, izvođenje pucnjava itd.). Ako ne želite gledati cijeli prijenos, možete pogledati samo najzanimljivije trenutke.

Što je korišteno u razvoju?

Glavni dio je napisan u Gou. API s kojim su mobilni klijenti komunicirali napisan je u Gou. Usluga za slanje push obavijesti na mobilne uređaje također je napisana u Gou. Također smo morali napisati vlastiti ORM, o kojem bismo mogli pričati jednog dana. I neke manje usluge su napisane u Gou: promjena veličine i prijenos slika za urednike...

Kao bazu podataka koristili smo PostgreSQL. Sučelje za uređivanje napisano je u Ruby on Rails koristeći ActiveAdmin gem. Uvoznik statistike iz pružatelja statistike također je napisan u Rubyju.

Za testove sistemskog API-ja koristili smo Python-ov unittest. Memcached se koristi za ograničavanje API zahtjeva za plaćanje, Chef se koristi za kontrolu konfiguracije, Zabbix se koristi za prikupljanje i praćenje interne statistike sustava, Graylog2 se koristi za prikupljanje logova, a Slate je API dokumentacija za klijente.

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

Odabir protokola

Prvi problem s kojim smo se suočili bio je odabir protokola za interakciju s mobilnim klijentima na temelju sljedećih točaka…

  • Najvažniji zahtjev je da se podaci klijenata moraju ažurirati u stvarnom vremenu. To znači da svi koji gledaju prijenos moraju primati ažuriranja gotovo trenutno.
  • Radi jednostavnosti, pretpostavili smo da se podaci sinkronizirani s klijentima ne brišu, već skrivaju pomoću posebnih zastavica.
  • Svi rijetki zahtjevi (kao što su statistike, popisi igrača, statistike igrača) primaju se putem redovnih GET zahtjeva.
  • Osim toga, sustav je morao lako podnijeti 100 000 istovremenih korisnika.

Na temelju toga imali smo dvije mogućnosti protokola:

  1. Websocketi. Ali nisu nam trebali kanali od klijenta do poslužitelja. Trebali smo samo slati ažuriranja sa poslužitelja klijentu, pa je websocket bio pretjeran.
  2. Događaji poslani od poslužitelja (SSE) bili su savršen izbor! Prilično su jednostavni i u osnovi ispunjavaju sve što nam treba.

Događaji poslani s poslužitelja

Nekoliko riječi o tome kako ovo funkcionira...

Radi preko HTTP veze. Klijent šalje zahtjev, poslužitelj odgovara s Content-Type: text/event-stream i ne zatvara vezu s klijentom, već nastavlja pisati podatke u 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 ih na ovaj način: polje događaja sadržavalo je naziv promijenjene strukture (osoba, igrač), a polje podataka sadržavalo je JSON s novim, modificiranim poljima za igrača.

Sada o tome kako sama interakcija funkcionira.

  • Prvo što klijent radi jest utvrditi kada se dogodila posljednja sinkronizacija s uslugom: pregledava svoju lokalnu bazu podataka i određuje datum posljednje zabilježene promjene.
  • On šalje zahtjev s ovim datumom.
  • Kao odgovor, šaljemo mu sva ažuriranja koja su se dogodila od tog datuma.
  • Nakon toga se povezuje s kanalom uživo i ne zatvara ga dok mu ne budu potrebna ova ažuriranja:

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

Šaljemo mu popis promjena: ako netko postigne gol, ako se rezultat promijeni ili ako se netko ozlijedi, također se šalje u stvarnom vremenu. Na taj način klijenti odmah primaju ažurirane podatke u feedu utakmice. Povremeno, kako bismo klijenta obavijestili da poslužitelj nije mrtav, da mu se ništa nije dogodilo, šaljemo vremensku oznaku svakih 15 sekundi - tako da znaju da je sve u redu i ne moraju se ponovno spajati.

Kako se pruža usluga žive veze?

  • Prije svega, stvaramo kanal koji će primati ažuriranja s međuspremnikom.
  • Nakon toga, pretplatit ćemo se na ovaj kanal kako bismo primali novosti.
  • Postavljamo ispravan naslov kako bi klijent znao da je sve u redu.
  • Šaljemo prvi ping. Jednostavno bilježimo trenutnu vremensku oznaku veze.
  • Nakon toga, čitamo iz kanala u petlji sve dok se kanal za ažuriranje ne zatvori. Kanal periodično prima ili trenutnu vremensku oznaku ili promjene, koje zatim zapisujemo u otvorene veze.

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

Prvi problem s kojim smo se susreli bio je sljedeći: za svaku otvorenu vezu s klijentom, kreirali smo timer koji je otkucavao svakih 15 sekundi. Dakle, ako smo imali 6 otvorenih veza s jednim računalom (jedan API poslužitelj), kreirano je 6 timera. To je značilo da računalo nije moglo podnijeti potrebno opterećenje. Problem nam nije bio odmah očit, ali smo dobili pomoć i riješili smo ga.

Kao rezultat toga, sada imamo ping koji dolazi s istog kanala s kojeg dolazi ažuriranje.

Sukladno tome, postoji samo jedan timer koji otkucava svakih 15 sekundi.

Ovdje postoji nekoliko pomoćnih funkcija - slanje zaglavlja, pinga i same strukture. To jest, ovdje se prosljeđuju naziv tablice (osoba, utakmica, sezona) i informacije o ovom zapisu:

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 stvarnom vremenu. Oni kreiraju sve događaje: netko dobiva crveni karton, netko se ozlijedi, neka zamjena...

CMS pohranjuje podatke u bazu podataka. Baza podataka zatim koristi mehanizam Listen/Notify za obavještavanje API poslužitelja. API poslužitelji zatim šalju te informacije klijentima. Dakle, u biti imamo samo nekoliko poslužitelja spojenih na bazu podataka i nema značajnog opterećenja baze podataka jer klijent ne komunicira izravno s bazom podataka.

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

PostgreSQL: Slušanje/Obavještavanje

Mehanizam Listen/Notify u PostgreSQL-u omogućuje vam obavještavanje pretplatnika događaja kada se događaj promijeni - kreiran je zapis 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 promjene zapisa, pozivamo funkciju notify na kanalu data_updates, prosljeđujući joj naziv tablice i ID zapisa koji je promijenjen ili umetnut.

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

Stvara se mehanizam Fanout - šalje poruke klijentima. Prikuplja sve klijentske kanale i šalje ažuriranja primljena putem tih kanala:

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

Evo standardne pq biblioteke koja se spaja na bazu podataka i pokazuje da želi slušati kanal (data_updates) te provjerava je li veza otvorena i je li 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, objavljujemo ga. Ako primimo snimku, objavljujemo je svim pretplatnicima ovog Fanouta.

Kako funkcionira Fan-out?

Na ruskom se to prevodi kao "razdjelnik". Imamo jedan objekt koji registrira pretplatnike koji žele primati određena ažuriranja. Čim ažuriranje stigne do ovog objekta, on ga distribuira svim svojim pretplatnicima. Prilično je jednostavno:

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

Kako je implementirano u Gou:

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

Postoji struktura sinkronizirana pomoću Mutexa. Ima polje koje pohranjuje Fanoutovu vezu s bazom podataka - to jest, trenutno sluša i primat će ažuriranja - kao i popis svih dostupnih kanala - mapu čiji je ključ kanal i strukturu koja sadrži vrijednosti (koje se zapravo ne koriste).

Dvije metode - Connected i Disconnected - omogućuju nam da Fanoutu kažemo da imamo vezu s bazom podataka, da je uspostavljena i da je veza s bazom podataka prekinuta. U drugom slučaju moramo odspojiti sve klijente i obavijestiti ih da više ne mogu ništa slušati te da se trebaju ponovno spojiti jer je veza s njima prekinuta.

Postoji i metoda Subscribe koja dodaje kanal "slušačima":

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

Postoji metoda Unsubscribe koja uklanja kanal s popisa slušanja ako se klijent prekine veza i metoda Publish koja vam omogućuje slanje poruke svim pretplatnicima.

Pitanje: – Što se prenosi ovim kanalom?

MS: – Prenosi se model koji se promijenio ili ping (u biti samo broj, cijeli broj).

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

MS: Primamo obavijest od PostgreSQL-a - ona sadrži naziv tablice i identifikator. Koristeći naziv tablice i identifikator, dohvaćamo zapis koji nam je potreban, a zatim šaljemo tu strukturu na objavu.

Infrastruktura

Kako to izgleda iz perspektive infrastrukture? Imamo sedam hardverskih poslužitelja: jedan je u potpunosti posvećen bazi podataka, a ostalih šest pokreće virtualne strojeve. Postoji šest API instanci: svaki virtualni stroj koji pokreće API radi na zasebnom hardverskom poslužitelju radi pouzdanosti.

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

Imamo dva frontenda na kojima se izvodi Keepalived radi pristupačnosti, tako da jedan frontend može zamijeniti drugi ako je potrebno. Također imamo dvije kopije CMS-a.

Tu je i uvoznik statistike. Tu je DB Slave koji periodički izrađuje sigurnosne kopije podataka. Tu je Pigeon Pusher, aplikacija koja šalje push obavijesti klijentima, kao i komponente infrastrukture: Zabbix, Graylog2 i Chef.

U stvarnosti, ova infrastruktura je redundantna, jer bi se 100 000 korisnika moglo opslužiti s manje poslužitelja. Ali imali smo hardver - koristili smo ga (rečeno nam je da je to moguće - pa zašto ne).

Prednosti Goa

Nakon rada na ovoj aplikaciji, postale su očite sljedeće prednosti Goa.

  • Izvrsna HTTP biblioteka. Omogućuje vam da kreirate dosta toga odmah nakon instalacije.
  • Osim toga, kanali su nam omogućili vrlo jednostavnu implementaciju mehanizma za slanje obavijesti klijentima.
  • Detektor utrke je izvrsna značajka koja nam je omogućila uklanjanje nekoliko kritičnih grešaka (infrastruktura za pripremu). Sve što se izvodi na pripremi se izvodi i kompilira s ključem utrke; stoga možemo koristiti infrastrukturu za pripremu kako bismo vidjeli koje potencijalne probleme bismo mogli imati.
  • Minimalizam i jednostavnost jezika.

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

Tražimo developere! Ako je netko zainteresiran, pridružite nam se.

pitanja

Pitanje publike (u daljnjem tekstu "Pitanje publike"): Mislim da ste propustili jednu važnu točku u vezi s Fan-outom. Jesam li ispravno shvatio da kada pošaljete odgovor klijentu, blokirate ga ako ga ne želi pročitati?

MS: „Ne, ne blokiramo se. Prvo, sve imamo iza Nginxa, tako da nema problema sa sporim klijentima. Drugo, klijent ima kanal s međuspremnikom - u biti možemo tamo pohraniti do stotinu ažuriranja... Ako ne možemo pisati na kanal, on ga briše. Ako vidimo da je kanal blokiran, jednostavno ga zatvorimo i to je to - klijent će se ponovno spojiti ako se pojave bilo kakvi problemi. Dakle, u principu, ovdje nema blokiranja.“

NA: – Nije li bilo moguće odmah poslati zapis na Listen/Notify, umjesto tablice identifikatora?

MS: – Listen/Notify ima ograničenje od 8 bajtova po prethodnom učitavanju koje šalje. U principu, bilo bi moguće poslati ga ako bismo imali posla s malom količinom podataka, ali mislim da je na ovaj način jednostavno pouzdanije. Ograničenja su u samom PostgreSQL-u.

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

MS: – Općenito govoreći, da. Obično se istovremeno odvijaju dvije ili tri utakmice, a čak i tada je to prilično rijetko. Ako klijent nešto gleda, obično gleda utakmicu koja se trenutno igra. Zatim, klijent ima lokalnu bazu podataka u kojoj su pohranjena sva ta ažuriranja, pa čak i bez internetske veze, klijent može gledati sve prošle utakmice za koje ima ažuriranja. U osnovi, sinkroniziramo našu bazu podataka na poslužitelju s lokalnom bazom podataka klijenta, tako da može raditi izvan mreže.

NA: – Zašto ste stvorili vlastiti ORM?

Aleksej (jedan od programera "Smotri+"): – U to vrijeme (ovo je bilo prije godinu dana), bilo je manje ORM-ova nego sada, kada ih ima poprilično. Od svih postojećih ORM-ova, ono što mi se najviše ne sviđa jest to što većina njih radi na praznim sučeljima. To jest, metode u tim ORM-ovima spremne su prihvatiti bilo što: strukturu, pokazivač na strukturu, broj, bilo što potpuno nebitno…

Naš ORM generira strukture na temelju samog modela podataka. Stoga su sve metode konkretne, ne koriste refleksiju itd. One prihvaćaju strukture i očekuju da će koristiti dane strukture.

NA: – Koliko je ljudi sudjelovalo?

MS: – U početnoj fazi bile su uključene dvije osobe. Počeli smo oko lipnja, a glavni dio (prva verzija) bio je gotov do kolovoza. Izdanje je bilo u rujnu.

NA: – Tamo gdje opisujete SSE, ne koristite timeout. Zašto je to tako?

MS: „Iskreno, SSE je još uvijek HTML5 protokol: SSE standard je dizajniran za komunikaciju s preglednicima, koliko ja razumijem. Ima dodatne značajke koje omogućuju preglednicima ponovno povezivanje (i tako dalje), ali nam nisu trebale jer smo imali klijente koji su mogli implementirati bilo koju logiku povezivanja i pronalaženja informacija. Nismo stvorili SSE, već nešto slično SSE-u. To nije sam protokol.“
Nije bilo potrebe. Koliko ja razumijem, klijenti su implementirali mehanizam povezivanja praktički od nule. Uglavnom ih nije bilo briga.

NA: – Koje ste dodatne uslužne programe koristili?

MS: – Najviše smo koristili govet i golint kako bismo održali dosljedan stil, kao i gofmt. Nismo koristili ništa drugo.

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

MS: – Otklanjanje pogrešaka uglavnom se obavljalo putem testova. Nismo koristili nikakve programe za otklanjanje pogrešaka ili GOP.

NA: – Možete li vratiti slajd na kojem je implementirana funkcija Objavi? Jesu li nazivi varijabli od jednog slova zbunjujući?

MS: "Ne. Imaju prilično uzak opseg. Ne koriste se nigdje drugdje osim ovdje (osim unutar internih dijelova ove klase), i vrlo je kompaktan - zauzima samo 7 redaka."

NA: – Nekako se još uvijek ne čini intuitivnim…

MS: „Ne, ne, ovo je pravi kod! Nije stvar stila. To je samo vrlo utilitarna, vrlo mala klasa - samo tri polja unutar klase...“

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

MS: – Općenito, svi podaci sinkronizirani s klijentima (sezonske utakmice, igrači) ostaju nepromijenjeni. Grubo govoreći, ako bismo razvili još jedan sport koji zahtijeva modifikacije utakmica, jednostavno bismo sve uzeli u obzir u novoj verziji klijenta, a starije verzije bi bile zabranjene.

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

MS: – Koristili smo go dep.

NA: – Tema izvješća spominjala je nešto o videu, ali izvješće nije spomenulo video.

MS: "Ne, nemam ništa o videozapisima u svojoj temi. Zove se 'Watch+' - to je naziv aplikacije."

NA: - Rekao si da streamaš klijentima?..

MS: "Nismo se bavili streamingom videa. To je u potpunosti rješavao Megafon. Da, nisam rekao da je aplikacija Megafonova."

MS: – Go – za slanje svih podataka – rezultata, događaja s utakmica, statistike… Go je cijeli backend za aplikaciju. Klijent treba negdje znati koju poveznicu koristiti za igrača kako bi korisnik mogao gledati utakmicu. Imamo poveznice na videozapise i streamove koji su već pripremljeni.

Reproduciraj videozapis

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

Kupite pouzdan hosting za stranice s DDoS zaštitom, VPS VDS poslužiteljima 🔥 Kupite pouzdan web hosting sa DDoS zaštitom, VPS VDS servere | ProHoster