Mikhail Salosin. Golang Meetup. Benotzt Go am Backend vun der Look+ Applikatioun

Mikhail Salosin (nodréiglech - MS): - Moien alleguer! Mäin Numm ass Michael. Ech schaffen als Backend Entwéckler bei MC2 Software, an ech wäert iwwer d'Benotzung Go am Backend vun der Look+ mobiler Applikatioun schwätzen.

Mikhail Salosin. Golang Meetup. Benotzt Go am Backend vun der Look+ Applikatioun

Huet iergendeen hei gär Hockey?

Mikhail Salosin. Golang Meetup. Benotzt Go am Backend vun der Look+ Applikatioun

Dann ass dës Applikatioun fir Iech. Et ass fir Android an iOS a gëtt benotzt fir Emissioune vu verschidde Sportsevenementer online ze kucken an opgeholl. D'Applikatioun enthält och verschidde Statistiken, Text Sendungen, Dëscher fir Konferenzen, Turnéier an aner Informatioun nëtzlech fir Fans.

Mikhail Salosin. Golang Meetup. Benotzt Go am Backend vun der Look+ Applikatioun

Och an der Applikatioun gëtt et sou eppes wéi Videomomenter, dh Dir kënnt déi wichtegst Momenter vu Matcher kucken (Ziler, Kämpf, Schéisserei, asw.). Wann Dir net déi ganz Sendung kucke wëllt, kënnt Dir nëmmen déi interessantst kucken.

Wat hutt Dir an der Entwécklung benotzt?

Den Haaptdeel gouf am Go geschriwwen. D'API, mat deem mobil Clienten kommunizéiert hunn, gouf a Go geschriwwen. E Service fir Push Notifikatiounen op Handyen ze schécken gouf och a Go geschriwwen. Mir hunn och missen eisen eegenen ORM schreiwen, iwwer dee mir vläicht iergendwann schwätzen. Gutt, e puer kleng Servicer goufen am Go geschriwwen: d'Gréisst änneren an d'Biller fir d'Redaktoren lueden ...

Mir hunn PostgreSQL als Datebank benotzt. D'Editor-Interface gouf a Ruby on Rails geschriwwen mat dem ActiveAdmin Bijou. D'Importéiere vun Statistike vun engem Statistikprovider gëtt och a Ruby geschriwwen.

Fir System API Tester hu mir Python unittest benotzt. Memcached gëtt benotzt fir API Bezuelungsuriff ze drosselen, "Chef" gëtt benotzt fir d'Konfiguratioun ze kontrolléieren, Zabbix gëtt benotzt fir intern Systemstatistiken ze sammelen an ze iwwerwaachen. Graylog2 ass fir Logbicher ze sammelen, Slate ass API Dokumentatioun fir Clienten.

Mikhail Salosin. Golang Meetup. Benotzt Go am Backend vun der Look+ Applikatioun

Protokoll Auswiel

Den éischte Problem dee mir begéint hunn: mir hu misse e Protokoll fir Interaktioun tëscht dem Backend a mobilen Clienten wielen, baséiert op de folgende Punkten ...

  • Déi wichtegst Fuerderung: Daten iwwer Clienten mussen an Echtzäit aktualiséiert ginn. Dat heescht, jidderee deen de Moment d'Emissioun kuckt, soll bal direkt Updates kréien.
  • Fir d'Saachen ze vereinfachen, hu mir ugeholl datt Daten, déi mat Clienten synchroniséiert sinn, net geläscht ginn, mee verstoppt mat spezielle Fändelen.
  • All Zorte vu rare Ufroen (wéi Statistiken, Teamkompositiounen, Teamstatistiken) ginn duerch normal GET Ufroe kritt.
  • Plus, de System huet einfach 100 dausend Benotzer gläichzäiteg ze ënnerstëtzen.

Baséierend op dësem hu mir zwou Protokolloptiounen:

  1. Websockets. Awer mir hu keng Kanäl vum Client op de Server gebraucht. Mir brauche just Updates vum Server op de Client ze schécken, sou datt e Websocket eng redundante Optioun ass.
  2. Server-Sent Events (SSE) koumen just richteg! Et ass ganz einfach an entsprécht am Fong alles wat mir brauchen.

Server-geschéckt Evenementer

E puer Wierder iwwer wéi dës Saach funktionnéiert ...

Et leeft uewen op enger http Verbindung. De Client schéckt eng Ufro, de Server reagéiert mat Content-Type: Text/Event-Stream an mécht d'Verbindung mam Client net zou, awer schreift weider Daten un d'Verbindung:

Mikhail Salosin. Golang Meetup. Benotzt Go am Backend vun der Look+ Applikatioun

D'Donnéeë kënnen an engem Format geschéckt ginn, dee mat de Clienten ausgemaach ass. An eisem Fall hu mir et an dëser Form geschéckt: den Numm vun der geännerter Struktur (Persoun, Spiller) gouf op den Eventfeld geschéckt, an JSON mat neien, geännerten Felder fir de Spiller gouf an den Datefeld geschéckt.

Loosst eis elo schwätzen iwwer wéi d'Interaktioun selwer funktionnéiert.

  • Dat éischt wat de Client mécht ass d'lescht Kéier d'Synchroniséierung mam Service ze bestëmmen: et kuckt op seng lokal Datebank a bestëmmt den Datum vun der leschter Ännerung, déi et opgeholl huet.
  • Et schéckt eng Demande mat dësem Datum.
  • Als Äntwert schécken mir him all d'Aktualiséierungen déi zënter deem Datum geschitt sinn.
  • Duerno mécht et eng Verbindung mam Live Kanal an ass net zou bis et dës Updates brauch:

Mikhail Salosin. Golang Meetup. Benotzt Go am Backend vun der Look+ Applikatioun

Mir schécken him eng Lëscht vun Ännerungen: wann een e Goal geschoss huet, änneren mir de Score vum Match, wann e blesséiert gëtt, gëtt dat och an Echtzäit geschéckt. Sou kréien Clienten direkt aktuell Daten am Match Event Feed. Periodesch, sou datt de Client versteet datt de Server net gestuerwen ass, datt näischt mat him geschitt ass, schécken mir all 15 Sekonnen en Zäitstempel - sou datt et weess datt alles an der Rei ass an et net néideg ass erëm ze konnektéieren.

Wéi gëtt d'Liveverbindung servéiert?

  • Als éischt erstelle mir e Kanal an deem gebufferten Updates kritt ginn.
  • Duerno abonnéiere mir dëse Kanal fir Updates ze kréien.
  • Mir setzen de richtege Header sou datt de Client weess datt alles ok ass.
  • Schéckt den éischte Ping. Mir notéieren einfach den aktuelle Verbindungszäitstempel.
  • Duerno liesen mir vum Kanal an enger Loop bis den Updatekanal zou ass. De Kanal kritt periodesch entweder den aktuellen Zäitstempel oder Ännerungen déi mir scho schreiwen fir Verbindungen opzemaachen.

Mikhail Salosin. Golang Meetup. Benotzt Go am Backend vun der Look+ Applikatioun

Den éischte Problem, dee mir begéint hunn, war déi folgend: fir all Verbindung mam Client opgemaach, hu mir en Timer erstallt deen eemol all 15 Sekonnen gekickt huet - et stellt sech eraus datt wa mir 6 dausend Verbindunge mat enger Maschinn opgemaach hunn (mat engem API Server), 6 dausend Timer goufen erstallt. Dëst huet dozou gefouert datt d'Maschinn net déi néideg Laascht hält. De Problem war fir eis net esou offensichtlech, mä mir kruten e bëssen Hëllef a fixéiert.

Als Resultat, elo kënnt eise Ping vum selwechte Kanal aus deem Update kënnt.

Deementspriechend gëtt et nëmmen een Timer deen eemol all 15 Sekonnen tickt.

Et gi verschidde Hëllefsfunktiounen hei - den Header, de Ping an d'Struktur selwer schécken. Dat ass, den Numm vum Dësch (Persoun, Match, Saison) an d'Informatiounen iwwer dës Entrée ginn hei iwwerdroen:

Mikhail Salosin. Golang Meetup. Benotzt Go am Backend vun der Look+ Applikatioun

Mechanismus fir Updates ze schécken

Elo e bëssen iwwer wou d'Ännerungen hierkommen. Mir hunn e puer Leit, Redaktoren, déi d'Sendung an Echtzäit kucken. Si kreéieren all d'Evenementer: een gouf geschéckt, ee gouf blesséiert, eng Zort Ersatz ...

Mat engem CMS ginn Daten an d'Datebank an. Duerno informéiert d'Datebank d'API Serveren iwwer dëst mam Listen / Notify Mechanismus. API Server schécken dës Informatioun scho fir Clienten. Also hu mir am Fong nëmmen e puer Server verbonne mat der Datebank an et gëtt keng speziell Belaaschtung op der Datebank, well de Client op iergendeng Manéier net direkt mat der Datebank interagéiert:

Mikhail Salosin. Golang Meetup. Benotzt Go am Backend vun der Look+ Applikatioun

PostgreSQL: Lauschtert / Notifikatioun

Den Listen/Notify Mechanismus am Postgres erlaabt Iech Event Abonnenten z'informéieren datt e puer Event geännert huet - e puer Rekord gouf an der Datebank erstallt. Fir dëst ze maachen, hu mir en einfachen Ausléiser a Funktioun geschriwwen:

Mikhail Salosin. Golang Meetup. Benotzt Go am Backend vun der Look+ Applikatioun

Wann Dir e Rekord setzt oder ännert, ruffe mir d'Notifikatiounsfunktioun um Data_updates Kanal, andeems Dir den Numm vun der Tabell an den Identifizéierer vum Rekord deen geännert oder agefouert gouf.

Fir all Dëscher, déi mam Client synchroniséiert musse ginn, definéiere mir en Ausléiser, deen, nodeems e Rekord geännert / aktualiséiert gëtt, d'Funktioun op der Rutsch hei ënnen nennt.
Wéi abonnéiert d'API op dës Ännerungen?

E Fanout Mechanismus gëtt erstallt - et schéckt Messagen un de Client. Et sammelt all Clientskanäl a schéckt Updates déi se iwwer dës Kanäl kritt hunn:

Mikhail Salosin. Golang Meetup. Benotzt Go am Backend vun der Look+ Applikatioun

Hei ass d'Standard pq-Bibliothéik, déi mat der Datebank verbënnt a seet datt et de Kanal lauschtere wëll (data_updates), kontrolléiert datt d'Verbindung op ass an alles gutt ass. Ech loosse Feeler iwwerpréiwen fir Plaz ze spueren (net kontrolléieren ass geféierlech).

Als nächst setzen mir den Ticker asynchron, deen all 15 Sekonnen e Ping schéckt, a fänkt un de Kanal ze lauschteren op dee mir abonnéiert hunn. Wa mir e Ping kréien, publizéieren mir dëse Ping. Wa mir eng Aart vun Entrée kréien, verëffentleche mir dësen Entrée un all Abonnente vun dësem Fanout.

Wéi funktionéiert Fan-Out?

Op Russesch iwwersetzt dëst als "Splitter". Mir hunn een Objet deen Abonnente registréiert déi e puer Updates kréien wëllen. A soubal en Update zu dësem Objet ukomm ass, verdeelt se dësen Update un all seng Abonnenten. Einfach genuch:

Mikhail Salosin. Golang Meetup. Benotzt Go am Backend vun der Look+ Applikatioun

Wéi et am Go ëmgesat gëtt:

Mikhail Salosin. Golang Meetup. Benotzt Go am Backend vun der Look+ Applikatioun

Et gëtt eng Struktur, et gëtt mat Mutexes synchroniséiert. Et huet e Feld dat den Zoustand vun der Fanout Verbindung mat der Datebank späichert, dh et lauschtert de Moment a kritt Updates, souwéi eng Lëscht vun all verfügbare Kanäl - Kaart, de Schlëssel vun deem ass de Kanal a Struktur a Form vun Wäerter (am Wesentlechen ass et net op iergendeng Manéier benotzt).

Zwee Methoden - Connected and Disconnected - erlaben eis Fanout ze soen datt mir eng Verbindung mat der Basis hunn, et ass erschéngt an datt d'Verbindung mat der Basis gebrach ass. Am zweete Fall musst Dir all Clienten trennen an hinnen soen datt se näischt méi nolauschtere kënnen an datt se erëm konnektéieren well d'Verbindung mat hinnen zou ass.

Et gëtt och eng Abonnementmethod déi de Kanal un d'"Nolauschterer" bäidréit:

Mikhail Salosin. Golang Meetup. Benotzt Go am Backend vun der Look+ Applikatioun

Et gëtt eng Unsubscribe Method, déi de Kanal vun den Nolauschterer läscht wann de Client trennt, souwéi eng Publish Method, déi Iech erlaabt e Message un all Abonnente ze schécken.

Froen: - Wat gëtt iwwer dëse Kanal iwwerdroen?

MS: - De Modell deen geännert huet oder de Ping gëtt iwwerdroen (am Fong just eng Zuel, ganz Zuel).

MS: - Dir kënnt alles schécken, all Struktur schécken, et publizéieren - et gëtt just an JSON an dat ass et.

MS: - Mir kréien eng Notifikatioun vu Postgres - et enthält den Dëschnumm an den Identifizéierer. Baséiert op den Dësch Numm an Identifizéierer, mir kréien de Rekord mir brauchen, an dann schécken mir dës Struktur fir Publikatioun.

Infrastruktur

Wéi gesäit dat aus enger Infrastrukturperspektiv aus? Mir hunn 7 Hardware Serveren: ee vun hinnen ass komplett der Datebank gewidmet, déi aner sechs lafen virtuell Maschinnen. Et gi 6 Exemplare vun der API: all virtuell Maschinn mat der API leeft op engem separaten Hardware Server - dëst ass fir Zouverlässegkeet.

Mikhail Salosin. Golang Meetup. Benotzt Go am Backend vun der Look+ Applikatioun

Mir hunn zwee Frontends mat Keepalved installéiert fir d'Accessibilitéit ze verbesseren, sou datt wann eppes geschitt, ee Frontend kann deen aneren ersetzen. Och - zwee Exemplare vum CMS.

Et gëtt och e Statistikimporter. Et gëtt en DB Sklave aus deem Backups periodesch gemaach ginn. Et gëtt Pigeon Pusher, eng Applikatioun déi Push Notifikatiounen u Clienten schéckt, souwéi Infrastruktur Saachen: Zabbix, Graylog2 a Chef.

Tatsächlech ass dës Infrastruktur redundant, well 100 Tausend kënne mat manner Server servéiert ginn. Awer et war Eisen - mir hunn et benotzt (mir krute gesot datt et méiglech wier - firwat net).

Virdeeler vum Go

Nodeems mir un dëser Applikatioun geschafft hunn, sinn esou offensichtlech Virdeeler vu Go entstanen.

  • Cool http Bibliothéik. Mat et kënnt Dir zimmlech vill aus der Këscht kreéieren.
  • Plus, Kanäl, déi eis erlaabt hunn ganz einfach e Mechanismus ze implementéieren fir Notifikatiounen u Clienten ze schécken.
  • Déi wonnerbar Saach Race Detector huet eis erlaabt e puer kritesch Bugs ze eliminéieren (Staging Infrastruktur). Alles wat op der Inszenéierung funktionnéiert gëtt lancéiert, zesummegesat mam Race Schlëssel; a mir kënnen deementspriechend d'Inszenéierungsinfrastruktur kucken fir ze kucken wat fir potenziell Problemer mir hunn.
  • Minimalismus an Einfachheet vun der Sprooch.

Mikhail Salosin. Golang Meetup. Benotzt Go am Backend vun der Look+ Applikatioun

Mir sichen fir Entwéckler! Wann iergendeen wëll, weg.

Är Froen

Fro vum Publikum (nodréiglech - B): - Et schéngt mir, datt Dir ee wichtege Punkt iwwer Fan-out verpasst hutt. Sinn ech richteg am Verständnis datt wann Dir eng Äntwert un e Client schéckt, Dir blockéiert wann de Client net wëllt liesen?

MS: - Nee, mir blockéieren net. Als éischt hu mir dat alles hannert nginx, dat ass, et gi keng Probleemer mat luesen Clienten. Zweetens, de Client huet e Kanal mat engem Puffer - tatsächlech kënne mir bis zu honnert Updates do setzen ... Wa mir net op de Kanal schreiwen, da läscht en en. Wa mir gesinn datt de Kanal blockéiert ass, da wäerte mir de Kanal einfach zoumaachen, an dat ass et - de Client wäert erëm konnektéieren wann e Problem entstinn. Dofir gëtt et am Prinzip keng Blockéierung hei.

IN: - Konnt et net méiglech sinn direkt e Rekord op Listen / Notify ze schécken, an net eng Identifizéierungstabell?

MS: - Lauschtert / Notifikatioun huet eng Limit vun 8 Tausend Bytes op der Preload déi se schéckt. Am Prinzip wier et méiglech ze schécken wa mir mat enger klenger Quantitéit un Daten ze dinn hunn, awer et schéngt mir datt dës Manéier [wéi mir et maachen] einfach méi zouverlässeg ass. D'Aschränkungen sinn am Postgres selwer.

IN: - Kréien Clienten Aktualiséierungen op Mätscher datt si net interesséiert sinn?

MS: - Am Allgemengen, jo. An der Regel ginn et 2-3 Matcher parallel, an och dann zimlech seelen. Wann e Client eppes kuckt, dann kuckt hien normalerweis de Match deen lass ass. Dann huet de Client eng lokal Datebank an där all dës Aktualiséierunge bäigefüügt ginn, an och ouni Internetverbindung kann de Client all vergaange Matcher kucken fir déi hien Updates huet. Wesentlech synchroniséiere mir eis Datebank um Server mat der lokaler Datebank vum Client fir datt hien offline ka schaffen.

IN: - Firwat hutt Dir Är eege ORM gemaach?

Alexey (ee vun den Entwéckler vu Look+): – Deemools (et war virun engem Joer) gouf et manner ORM wéi elo, wann et der relativ vill sinn. Meng Liiblings Saach iwwer déi meescht ORMs dobaussen ass datt déi meescht vun hinnen op eidel Interfaces lafen. Dat ass, d'Methoden an dësen ORMs si prett fir alles unzehuelen: eng Struktur, e Strukturpointer, eng Zuel, eppes komplett irrelevant ...

Eis ORM generéiert Strukturen op Basis vum Datemodell. Ech selwer. An dofir sinn all Methode konkret, benotzen keng Reflexioun, etc. Si akzeptéieren Strukturen an erwaarden déi Strukturen ze benotzen déi kommen.

IN: - Wéivill Leit hunn deelgeholl?

MS: – An der éischter Etapp hunn zwee Leit matgemaach. Mir hunn iergendwou am Juni ugefaang, an am August war den Haaptdeel fäerdeg (déi éischt Versioun). Et gouf eng Verëffentlechung am September.

IN: - Wou Dir SSE beschreift, benotzt Dir keng Timeout. Firwat?

MS: - Fir éierlech ze sinn, SSE ass nach ëmmer en html5 Protokoll: den SSE Standard ass entwéckelt fir mat Browser ze kommunizéieren, souwäit ech verstinn. Et huet zousätzlech Fonctiounen, sou datt d'Browser kënnen nei konnektéieren (a sou weider), awer mir brauchen se net, well mir Clienten haten, déi all Logik fir d'Verbindung an d'Informatioun ze kréien ëmsetzen. Mir hunn net SSE gemaach, awer éischter eppes ähnlech wéi SSE. Dëst ass net de Protokoll selwer.
Et war kee Besoin. Sou wäit wéi ech verstinn, hunn d'Clienten de Verbindungsmechanismus bal vun Null ëmgesat. Et war hinnen net wierklech egal.

IN: - Wéi eng zousätzlech Utilities hutt Dir benotzt?

MS: - Mir hunn am meeschte aktiv Govet a Golint benotzt fir de Stil vereenegt ze maachen, souwéi Gofmt. Näischt anescht gouf benotzt.

IN: - Wat hutt Dir benotzt fir ze Debuggen?

MS: - Debugging gouf gréisstendeels mat Tester duerchgefouert. Mir hunn keen Debugger oder GOP benotzt.

IN: - Kënnt Dir de Rutsch zréckginn wou d'Publish Funktioun implementéiert ass? Duercherneen eenzel-Bréif Variabel Nimm Iech?

MS: - Nee. Si hunn eng zimlech "schmuel" Visibilitéit. Si sinn net soss anzwousch benotzt ausser hei (ausser fir d'intern vun dëser Klass), an et ass ganz kompakt - et dauert just 7 Linnen.

IN: - Iergendwéi ass et nach ëmmer net intuitiv ...

MS: - Nee, nee, dëst ass e richtege Code! Et geet net ëm Stil. Et ass just sou eng utilitaristesch, ganz kleng Klass - nëmmen 3 Felder an der Klass ...

Mikhail Salosin. Golang Meetup. Benotzt Go am Backend vun der Look+ Applikatioun

MS: - Duerch a grouss, all d'Donnéeën, déi mat Clienten synchroniséiert sinn (Saison Mätscher, Spiller) änneren net. Grof geschwat, wa mir maachen aner Sport an deem musse mir de Match änneren, mir wäerten einfach alles Rechnung huelen an der neier Versioun vum Client, an déi al Versiounen vum Client wäert verbuede ginn.

IN: - Ginn et Drëtt Partei Ofhängegkeet Gestioun Packagen?

MS: - Mir benotzt go dep.

IN: - Et war eppes iwwer Video am Thema vum Bericht, awer et war näischt am Bericht iwwer Video.

MS: - Nee, ech hunn näischt am Thema iwwer de Video. Et gëtt "Look +" genannt - dat ass den Numm vun der Applikatioun.

IN: - Dir sot datt et u Cliente gestreamt gëtt? ..

MS: - Mir waren net am Streaming Video involvéiert. Dëst gouf ganz vum Megafon gemaach. Jo, ech hunn net gesot datt d'Applikatioun MegaFon war.

MS: - Go - fir all Donnéeën ze schécken - op de Score, op Matchevenementer, Statistiken ... Go ass de ganze Backend fir d'Applikatioun. De Client muss iergendwou wëssen, wéi ee Link fir de Spiller ze benotzen, fir datt de Benotzer de Match ka kucken. Mir hunn Linken op Videoen a Streamen déi virbereet goufen.

Puer Annoncen 🙂

Merci datt Dir bei eis bleift. Hutt Dir eis Artikelen gär? Wëllt Dir méi interessant Inhalt gesinn? Ënnerstëtzt eis andeems Dir eng Bestellung maacht oder Frënn empfeelt, Cloud VPS fir Entwéckler vun $ 4.99, en eenzegaartegen Analog vun Entry-Level Serveren, dee vun eis fir Iech erfonnt gouf: Déi ganz Wourecht iwwer VPS (KVM) E5-2697 v3 (6 Cores) 10GB DDR4 480GB SSD 1Gbps vun $19 oder wéi een e Server deelt? (verfügbar mat RAID1 an RAID10, bis zu 24 Kären a bis zu 40GB DDR4).

Dell R730xd 2 Mol méi bëlleg an Equinix Tier IV Daten Zentrum zu Amsterdam? Nëmmen hei 2 x Intel TetraDeca-Core Xeon 2x E5-2697v3 2.6GHz 14C 64GB DDR4 4x960GB SSD 1Gbps 100 TV vun $199 an Holland! Dell R420 - 2x E5-2430 2.2Ghz 6C 128GB DDR3 2x960GB SSD 1Gbps 100TB - vun $99! Liest iwwer Wéi bauen ech Infrastructure Corp. Klass mat der Benotzung vun Dell R730xd E5-2650 v4 Serveren Wäert 9000 Euro fir e Penny?

Source: will.com

Setzt e Commentaire