Mikhail Salosin. Golang Meetup. Korištenje Go u pozadini aplikacije Look+

Mihail Salosin (u daljem tekstu – MS): - Zdravo svima! Moje ime je Michael. Radim kao backend programer u MC2 Software, i govorit ću o korištenju Go u pozadini mobilne aplikacije Look+.

Mikhail Salosin. Golang Meetup. Korištenje Go u pozadini aplikacije Look+

Da li neko ovde voli hokej?

Mikhail Salosin. Golang Meetup. Korištenje Go 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 na mreži i za snimanje. Aplikacija također sadrži razne statistike, tekstualne prijenose, tabele za konferencije, turnire i druge informacije korisne za navijače.

Mikhail Salosin. Golang Meetup. Korištenje Go u pozadini aplikacije Look+

Također u aplikaciji postoji i video trenuci, odnosno možete gledati najvažnije trenutke mečeva (golovi, borbe, raspucavanja, itd.). Ako ne želite da gledate cijeli prijenos, možete pogledati samo one najzanimljivije.

Šta ste koristili u razvoju?

Glavni dio je napisan na Go. API sa kojim su mobilni klijenti komunicirali napisan je u Go. U Go je napisan i servis za slanje push notifikacija na mobilne telefone. Takođe smo morali da napišemo sopstveni ORM, o čemu ćemo jednog dana možda pričati. Pa, neki mali servisi su napisani u Go: promjena veličine i učitavanje slika za urednike...

Koristili smo PostgreSQL kao bazu podataka. Interfejs uređivača je napisan u Ruby on Rails koristeći ActiveAdmin dragulj. Uvoz statistike iz dobavljača statistike je takođe napisan u Ruby-u.

Za sistemske API testove koristili smo Python unittest. Memcached se koristi za prigušivanje poziva API plaćanja, “Chef” se koristi za kontrolu konfiguracije, Zabbix se koristi za prikupljanje i praćenje interne statistike sistema. Graylog2 je za prikupljanje logova, Slate je API dokumentacija za klijente.

Mikhail Salosin. Golang Meetup. Korištenje Go u pozadini aplikacije Look+

Izbor protokola

Prvi problem na koji smo naišli: morali smo odabrati protokol za interakciju između backend i mobilnih klijenata, na osnovu sljedećih tačaka...

  • Najvažniji zahtjev: podaci o klijentima moraju se ažurirati u realnom vremenu. Odnosno, svi koji trenutno gledaju emisiju bi trebali primati ažuriranja gotovo trenutno.
  • Da bismo pojednostavili 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 statistika, sastav timova, statistika tima) dobijaju se običnim GET zahtjevima.
  • Osim toga, sistem je morao lako podržavati 100 hiljada korisnika u isto vrijeme.

Na osnovu toga, imali smo dvije opcije protokola:

  1. Websockets. Ali nisu nam bili potrebni kanali od klijenta do servera. Trebali smo samo da šaljemo ažuriranja sa servera na klijenta, tako da je websocket redundantna opcija.
  2. Server-Sent Events (SSE) su se pojavili baš kako treba! Prilično je jednostavan i u osnovi zadovoljava sve što nam treba.

Događaji poslani serverom

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

Radi na vrhu http konekcije. Klijent šalje zahtjev, server odgovara sa Content-Type: text/event-stream i ne zatvara vezu s klijentom, već nastavlja pisati podatke na vezu:

Mikhail Salosin. Golang Meetup. Korištenje Go u pozadini aplikacije Look+

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

Hajde sada da razgovaramo o tome kako funkcioniše sama interakcija.

  • Prva stvar koju klijent radi je da odredi kada je poslednji put izvršena sinhronizacija sa uslugom: on gleda svoju lokalnu bazu podataka i određuje datum poslednje promene koju je zabeležio.
  • Šalje zahtjev sa ovim datumom.
  • Kao odgovor, šaljemo mu sva ažuriranja koja su se dogodila od tog datuma.
  • Nakon toga se povezuje sa kanalom uživo i ne zatvara se sve dok ne zatreba ova ažuriranja:

Mikhail Salosin. Golang Meetup. Korištenje Go u pozadini aplikacije Look+

Šaljemo mu spisak izmjena: ako neko postigne gol, mijenjamo rezultat utakmice, ako se povrijedi i to se šalje u realnom vremenu. Tako klijenti odmah primaju ažurirane podatke u feedu događaja utakmice. Periodično, kako bi klijent shvatio da server nije umro, da mu se ništa nije dogodilo, šaljemo vremensku oznaku svakih 15 sekundi - kako bi znao da je sve u redu i da nema potrebe za ponovnim povezivanjem.

Kako se servisira veza uživo?

  • Prije svega, kreiramo kanal u koji će se primati ažuriranja iz bafera.
  • Nakon toga, pretplatimo se na ovaj kanal kako bismo primali ažuriranja.
  • Postavljamo ispravno zaglavlje tako da klijent zna da je sve u redu.
  • Pošalji prvi ping. Jednostavno snimamo trenutnu vremensku oznaku veze.
  • Nakon toga, čitamo sa kanala u petlji dok se kanal za ažuriranje ne zatvori. Kanal povremeno prima ili trenutnu vremensku oznaku ili promjene koje već upisujemo na otvorene veze.

Mikhail Salosin. Golang Meetup. Korištenje Go u pozadini aplikacije Look+

Prvi problem na koji smo naišli je sljedeći: za svaku otvorenu vezu sa klijentom, kreirali smo tajmer koji je otkucavao svakih 15 sekundi - ispada da ako imamo 6 hiljada otvorenih veza sa jednom mašinom (sa jednim API serverom), 6 stvoreno je hiljada tajmera. To je dovelo do toga da mašina nije izdržala potrebno opterećenje. Problem nam nije bio toliko očigledan, ali smo dobili malu pomoć i riješili ga.

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

Prema tome, postoji samo jedan tajmer koji otkucava svakih 15 sekundi.

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

Mikhail Salosin. Golang Meetup. Korištenje Go u pozadini aplikacije Look+

Mehanizam za slanje ažuriranja

Sada malo o tome odakle dolaze promjene. Imamo nekoliko ljudi, urednika, koji gledaju prenos u realnom vremenu. Oni kreiraju sve događaje: neko je isključen, neko je povređen, neka zamena...

Pomoću CMS-a podaci ulaze u bazu podataka. Nakon toga, baza podataka obavještava API servere o tome koristeći mehanizam Listen/Notify. API serveri već šalju ove informacije klijentima. Dakle, u suštini imamo samo nekoliko servera povezanih na bazu podataka i nema posebnog opterećenja baze podataka, jer klijent ni na koji način ne komunicira direktno sa bazom:

Mikhail Salosin. Golang Meetup. Korištenje Go u pozadini aplikacije Look+

PostgreSQL: Slušaj/Obavijesti

Mehanizam Listen/Notify u Postgresu vam omogućava 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:

Mikhail Salosin. Golang Meetup. Korištenje Go u pozadini aplikacije Look+

Kada ubacujemo ili mijenjamo zapis, pozivamo funkciju notify na kanalu data_updates, prosljeđujući joj naziv tablice i identifikator zapisa koji je promijenjen ili umetnut.

Za sve tabele koje se moraju sinhronizovati sa klijentom, definišemo okidač, koji nakon promene/ažuriranja zapisa poziva funkciju naznačenu na donjem slajdu.
Kako se API pretplaćuje na ove promjene?

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

Mikhail Salosin. Golang Meetup. Korištenje Go u pozadini aplikacije Look+

Ovdje standardna pq biblioteka, koja se povezuje sa bazom podataka i kaže da želi da sluša kanal (data_updates), provjerava da li je veza otvorena i sve je u redu. Izostavljam provjeru grešaka radi uštede prostora (neprovjera je opasno).

Zatim, asinhrono postavljamo Ticker, koji će slati ping svakih 15 sekundi, i počinjemo slušati kanal na koji smo pretplaćeni. Ako primimo ping, objavljujemo ovaj ping. Ako dobijemo neku vrstu unosa, onda objavljujemo ovaj unos svim pretplatnicima ovog Fanouta.

Kako funkcioniše Fan-out?

Na ruskom se ovo prevodi kao "razdjelnik". Imamo jedan objekat koji registruje pretplatnike koji žele da primaju neka ažuriranja. I čim ažuriranje stigne na ovaj objekt, distribuira ga svim svojim pretplatnicima. dovoljno jednostavno:

Mikhail Salosin. Golang Meetup. Korištenje Go u pozadini aplikacije Look+

Kako se implementira u Go:

Mikhail Salosin. Golang Meetup. Korištenje Go u pozadini aplikacije Look+

Postoji struktura, sinhronizovana je pomoću muteksa. Ima polje koje čuva stanje Fanoute veze sa bazom podataka, odnosno trenutno sluša i primaće ažuriranja, kao i listu svih dostupnih kanala - mapu čiji je ključ kanal i struktura u obliku vrijednosti (u suštini se ne koristi ni na koji način).

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

Postoji i metoda pretplate koja dodaje kanal "slušateljima":

Mikhail Salosin. Golang Meetup. Korištenje Go u pozadini aplikacije Look+

Postoji metoda Unsubscribe, koja uklanja kanal od slušalaca ako se klijent prekine, kao i metoda Publish, koja vam omogućava da pošaljete poruku svim pretplatnicima.

Pitanje: – Šta se prenosi ovim kanalom?

GOSPOĐA: – Prenosi se model koji se promijenio ili ping (u suštini samo broj, cijeli broj).

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

GOSPOĐA: – Primamo obaveštenje od Postgresa – sadrži naziv tabele i identifikator. Na osnovu imena tabele i identifikatora dobijamo zapis koji nam je potreban, a zatim šaljemo ovu strukturu na objavu.

Infrastruktura

Kako ovo izgleda iz perspektive infrastrukture? Imamo 7 hardverskih servera: jedan od njih je u potpunosti posvećen bazi podataka, a ostalih šest pokreću virtuelne mašine. Postoji 6 kopija API-ja: svaka virtuelna mašina sa API-jem radi na zasebnom hardverskom serveru - ovo je zbog pouzdanosti.

Mikhail Salosin. Golang Meetup. Korištenje Go u pozadini aplikacije Look+

Imamo dva frontenda s instaliranim Keepalivedom radi poboljšanja pristupačnosti, tako da ako se nešto dogodi, jedan frontend može zamijeniti drugi. Također, dvije kopije CMS-a.

Postoji i uvoznik statistike. Postoji DB Slave iz kojeg se periodično prave sigurnosne kopije. Postoji Pigeon Pusher, aplikacija koja šalje push obavijesti klijentima, kao i infrastrukturne stvari: Zabbix, Graylog2 i Chef.

Zapravo, ova infrastruktura je suvišna, jer 100 hiljada može da se opsluži sa manje servera. Ali bilo je gvožđa - koristili smo ga (rečeno nam je da je moguće - zašto da ne).

Prednosti Go

Nakon što smo radili na ovoj aplikaciji, pojavile su se tako očigledne prednosti Go-a.

  • Cool http biblioteka. Uz to možete kreirati dosta toga iz kutije.
  • Plus, kanali koji su nam omogućili da vrlo lako implementiramo mehanizam za slanje obavještenja klijentima.
  • Divna stvar Race detektor nam je omogućio da eliminišemo nekoliko kritičnih grešaka (infrastruktura za postavljanje). Pokreće se sve što radi na postavljanju, kompajlirano sa Race ključem; i mi, shodno tome, možemo pogledati infrastrukturu za scenu da vidimo kakve potencijalne probleme imamo.
  • Minimalizam i jednostavnost jezika.

Mikhail Salosin. Golang Meetup. Korištenje Go u pozadini aplikacije Look+

Tražimo programere! Ako neko želi, molim.

Vaša pitanja

Pitanje iz publike (u daljem tekstu – B): – Čini mi se da ste propustili jednu bitnu stvar vezano za Fan-out. Da li sam u pravu kada sam shvatio da kada pošaljete odgovor klijentu, blokirate ako klijent ne želi da čita?

GOSPOĐA: - Ne, ne blokiramo. Prvo, sve ovo imamo iza nginxa, odnosno nema problema sa sporim klijentima. Drugo, klijent ima kanal sa baferom - u stvari, tamo možemo staviti do stotinu ažuriranja... Ako ne možemo pisati na kanal, onda ga briše. Ako vidimo da je kanal blokiran, onda ćemo jednostavno zatvoriti kanal i to je to - klijent će se ponovo povezati ako se pojavi bilo kakav problem. Stoga, u principu, ovdje nema blokiranja.

AT: – Zar nije bilo moguće odmah poslati zapis na Listen/Notify, a ne tabelu identifikatora?

GOSPOĐA: – Listen/Notify ima ograničenje od 8 hiljada bajtova za prethodno učitavanje koje šalje. U principu, bilo bi moguće poslati da imamo posla sa malom količinom podataka, ali čini mi se da je ovaj način (način na koji to radimo) jednostavno pouzdaniji. Ograničenja su u samom Postgresu.

AT: – Da li klijenti dobijaju novosti o utakmicama koje ih ne zanimaju?

GOSPOĐA: - Generalno, da. U pravilu se odvijaju 2-3 utakmice paralelno, a i tada vrlo rijetko. Ako klijent nešto gleda, onda obično gleda utakmicu koja se dešava. Zatim, klijent ima lokalnu bazu podataka u koju se zbrajaju sva ova ažuriranja, a čak i bez internetske veze, klijent može vidjeti sve prošle utakmice za koje ima ažuriranja. U suštini, sinhronizujemo našu bazu podataka na serveru sa lokalnom bazom podataka klijenta kako bi on mogao da radi van mreže.

AT: – Zašto ste napravili sopstveni ORM?

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

Naš ORM generiše strukture zasnovane na modelu podataka. Sebe. I stoga su sve metode konkretne, ne koriste refleksiju, itd. Oni prihvataju strukture i očekuju da koriste one strukture koje dolaze.

AT: – Koliko je ljudi učestvovalo?

GOSPOĐA: – U početnoj fazi su učestvovale dve osobe. Počeli smo negdje u junu, au avgustu je glavni dio bio gotov (prva verzija). Izdanje je bilo u septembru.

AT: – Tamo gdje opisujete SSE, ne koristite timeout. Žašto je to?

GOSPOĐA: – Da budem iskren, SSE je i dalje html5 protokol: SSE standard je dizajniran za komunikaciju sa pretraživačima, koliko ja razumem. Ima dodatne mogućnosti tako da se pretraživači mogu ponovo povezati (i tako dalje), ali nam nisu potrebni, jer smo imali klijente koji su mogli implementirati bilo koju logiku za povezivanje i primanje informacija. Nismo napravili SSE, već nešto slično SSE. Ovo nije sam protokol.
Nije bilo potrebe. Koliko sam shvatio, klijenti su implementirali mehanizam povezivanja gotovo od nule. Nije ih bilo briga.

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

GOSPOĐA: – Najaktivnije smo koristili govet i golint da ujednačimo stil, kao i gofmt. Ništa drugo nije korišteno.

AT: – Šta ste koristili za otklanjanje grešaka?

GOSPOĐA: – Otklanjanje grešaka je uglavnom vršeno pomoću testova. Nismo koristili nikakav program za otklanjanje grešaka ili GOP.

AT: – Možete li vratiti slajd na kojem je implementirana funkcija Publish? Da li vas zbunjuju jednoslovni nazivi varijabli?

GOSPOĐA: - Ne. Imaju prilično „uzak“ opseg vidljivosti. Ne koriste se nigdje drugdje osim ovdje (osim internih elemenata ove klase), a vrlo je kompaktan - traje samo 7 redova.

AT: – Nekako još uvek nije intuitivno...

GOSPOĐA: - Ne, ne, ovo je prava šifra! Ne radi se o stilu. To je baš tako utilitaran, vrlo mali razred - samo 3 polja unutar razreda...

Mikhail Salosin. Golang Meetup. Korištenje Go u pozadini aplikacije Look+

GOSPOĐA: – Uglavnom, svi podaci koji se sinhronizuju sa klijentima (utakmice sezone, igrači) se ne menjaju. Grubo rečeno, ako napravimo još jedan sport u kojem trebamo promijeniti meč, jednostavno ćemo sve uzeti u obzir u novoj verziji klijenta, a stare verzije klijenta će biti zabranjene.

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

GOSPOĐA: – Koristili smo go dep.

AT: – Bilo je nešto o videu u temi izveštaja, ali u izveštaju o videu nije bilo ništa.

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

AT: – Rekli ste da se prenosi klijentima?..

GOSPOĐA: – Nismo bili uključeni u striming videa. To je u potpunosti uradio Megafon. Da, nisam rekao da je aplikacija MegaFon.

GOSPOĐA: – Go – za slanje svih podataka – o rezultatu, događajima na utakmicama, statistici... Go je cijeli backend za aplikaciju. Klijent mora odnekud znati koji link koristiti za igrača kako bi korisnik mogao gledati utakmicu. Imamo linkove na pripremljene video zapise i streamove.

Neke reklame 🙂

Hvala vam što ste ostali s nama. Da li vam se sviđaju naši članci? Želite li vidjeti još zanimljivih sadržaja? Podržite nas naručivanjem ili preporukom prijateljima, cloud VPS za programere od 4.99 USD, jedinstveni analog servera početnog nivoa, koji smo mi izmislili za vas: Cijela istina o VPS (KVM) E5-2697 v3 (6 Cores) 10GB DDR4 480GB SSD 1Gbps od 19$ ili kako dijeliti server? (dostupno sa RAID1 i RAID10, do 24 jezgra i do 40GB DDR4).

Dell R730xd 2 puta jeftiniji u Equinix Tier IV data 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 Holandiji! Dell R420 - 2x E5-2430 2.2Ghz 6C 128GB DDR3 2x960GB SSD 1Gbps 100TB - od 99 USD! Pročitajte o Kako izgraditi infrastrukturnu kompaniju. klase uz korišćenje Dell R730xd E5-2650 v4 servera u vrednosti od 9000 evra za peni?

izvor: www.habr.com

Dodajte komentar