Mikhail Salosin. Golang vergadering. Gebruik Go in die agterkant van die Look+-toepassing

Mikhail Salosin (hierna - MS): - Hi almal! My naam is Michael. Ek werk as 'n back-end ontwikkelaar by MC2 Software, en ek sal praat oor die gebruik van Go in die agterkant van die Look+ mobiele toepassing.

Mikhail Salosin. Golang vergadering. Gebruik Go in die agterkant van die Look+-toepassing

Hou iemand hier van hokkie?

Mikhail Salosin. Golang vergadering. Gebruik Go in die agterkant van die Look+-toepassing

Dan is hierdie toepassing vir jou. Dit is vir Android en iOS, dit word gebruik om uitsendings van verskeie sportbyeenkomste aanlyn en op rekord te kyk. Die toepassing het ook verskeie statistieke, teksuitsendings, tabelle vir konferensies, toernooie en ander inligting wat nuttig is vir aanhangers.

Mikhail Salosin. Golang vergadering. Gebruik Go in die agterkant van die Look+-toepassing

Ook in die toepassing is daar iets soos video-oomblikke, dit wil sê jy kan die skerp oomblikke van wedstryde (doele, gevegte, skietgevegte, ens.) kyk. As jy nie lus is om die hele uitsending te kyk nie, kan jy net die interessantste kyk.

Wat is in ontwikkeling gebruik?

Die hoofgedeelte is in Go geskryf. Die API waarmee mobiele kliënte gekommunikeer het, is in Go geskryf. Daar is ook 'n diens in Go geskryf om stootkennisgewings na selfone te stuur. Ons moes ook ons ​​eie ORM skryf, waaroor ons dalk eendag kan praat. Wel, sommige klein dienste is in Go geskryf: verander die grootte en laai van beelde vir die redakteurskant ...

Ons het Postgres (PostgreSQL) as die databasis gebruik. Die koppelvlak vir die redakteurs is geskryf in Ruby on Rails met behulp van die ActiveAdmin-juweel. Ruby word ook gebruik om statistieke van 'n statistiekverskaffer in te voer.

Vir API-stelseltoetse het ons die Python-eenheidstoets gebruik. Memcached word gebruik vir API-betalingsbeperking, Chef vir konfigurasiebeheer, Zabbix vir die insameling en monitering van interne stelselstatistieke. Graylog2 is vir die versameling van logs, Slate is die API-dokumentasie vir kliënte.

Mikhail Salosin. Golang vergadering. Gebruik Go in die agterkant van die Look+-toepassing

Protokolkeuse

Die eerste probleem wat ons in die gesig gestaar het: ons moes die protokol kies vir die interaksie van die backend met mobiele kliënte, gebaseer op die volgende punte ...

  • Die belangrikste vereiste is dat die data op die kliënte intyds opgedateer moet word. Dit wil sê, almal wat tans na die uitsending kyk, behoort amper onmiddellik opdaterings te ontvang.
  • Om dit te vereenvoudig, het ons aangeneem dat die data wat met kliënte gesinchroniseer word, nie uitgevee word nie, maar met spesiale vlae versteek word.
  • Enige seldsame versoeke (soos statistieke, opstellings, spanstatistieke) word deur gereelde AOO-versoeke verkry.
  • Boonop moes die stelsel 100 XNUMX gebruikers op dieselfde tyd rustig weerstaan.

Op grond hiervan het ons twee protokolopsies gehad:

  1. Websockets. Maar ons het nie kanale van die kliënt na die bediener nodig gehad nie. Ons moes net opdaterings vanaf die bediener na die kliënt stuur, so websok is 'n oortollige opsie.
  2. Server-Sent Events (SSE) is net reg! Dit is redelik eenvoudig en voldoen in beginsel aan alles wat ons nodig het.

Bediener-gestuurde gebeurtenisse

'n Paar woorde oor hoe hierdie ding werk ...

Dit werk bo-op 'n http-verbinding. Die kliënt stuur 'n versoek, die bediener reageer met Content-Type: teks/gebeurtenisstroom en sluit nie die verbinding met die kliënt nie, maar gaan voort om data na die verbinding te skryf:

Mikhail Salosin. Golang vergadering. Gebruik Go in die agterkant van die Look+-toepassing

Data kan gestuur word in 'n formaat wat met kliënte ooreengekom is. In ons geval het ons dit in hierdie vorm gestuur: die naam van die veranderde struktuur (persoon, speler) is na die gebeurtenisveld gestuur, en JSON met nuwe, veranderde velde vir die speler is na die dataveld gestuur.

Nou oor hoe die interaksie self werk.

  • Eerstens, die kliënt bepaal wanneer die laaste keer dat sinchronisasie met die diens uitgevoer is: dit kyk na sy plaaslike databasis en bepaal die datum van die laaste verandering wat deur dit aangeteken is.
  • Dit stuur 'n versoek met daardie datum.
  • In reaksie stuur ons vir hom al die opdaterings wat sedert daardie datum plaasgevind het.
  • Daarna koppel dit aan die regstreekse kanaal en sluit nie totdat dit hierdie opdaterings benodig nie:

Mikhail Salosin. Golang vergadering. Gebruik Go in die agterkant van die Look+-toepassing

Ons stuur vir hom 'n lys van veranderinge: as iemand 'n doel aanteken - ons verander die telling van die wedstryd, word beseer - dit word ook intyds gestuur. Dus, in die wedstrydgebeurtenisvoer, ontvang kliënte onmiddellik opgedateerde data. Van tyd tot tyd, sodat die kliënt verstaan ​​dat die bediener nie dood is nie, dat niks daaraan gebeur het nie, stuur ons een keer elke 15 sekondes 'n tydstempel - sodat dit weet dat alles in orde is en dat dit nie nodig is om weer te koppel nie.

Hoe word 'n regstreekse verbinding gediens?

  • Eerstens skep ons 'n kanaal wat opdaterings met 'n buffer sal ontvang.
  • Daarna teken ons op hierdie kanaal in om opdaterings te ontvang.
  • Ons stel die korrekte kopskrif sodat die kliënt weet dat alles in orde is.
  • Ons stuur die eerste ping. Ons skryf net die huidige tydstempel van die verbinding neer.
  • Daarna lees ons vanaf die kanaal in 'n lus totdat die opdateringskanaal gesluit is. Die kanaal ontvang van tyd tot tyd óf die huidige tydstempel óf veranderinge wat ons reeds skryf om verbindings oop te maak.

Mikhail Salosin. Golang vergadering. Gebruik Go in die agterkant van die Look+-toepassing

Die eerste probleem wat ons in die gesig gestaar het, was die volgende: vir elke verbinding wat met die kliënt oopgemaak is, het ons 'n timer geskep wat elke 15 sekondes gemerk het - dit blyk dat ons 6 duisend verbindings oop gehad het met een masjien (met een API-bediener), 6 duisend timers geskep is. Dit het daartoe gelei dat die masjien nie die vereiste vrag gehou het nie. Die probleem was nie vir ons so duidelik nie, maar ons het 'n bietjie hulp gekry en ons het dit reggemaak.

Gevolglik het ons nou ping wat van dieselfde kanaal af kom waarvandaan die opdatering kom.

Gevolglik is daar net een tydhouer wat elke 15 sekondes tik.

Daar is verskeie hulpfunksies hier - die stuur van die kopskrif, ping en die struktuur self. Dit wil sê, die naam van die tabel (persoon, wedstryd, seisoen) en die inligting oor hierdie rekord self word hier oorgedra:

Mikhail Salosin. Golang vergadering. Gebruik Go in die agterkant van die Look+-toepassing

Meganisme vir die stuur van opdaterings

Nou 'n bietjie oor waar die veranderinge vandaan kom. Ons het verskeie mense, redakteurs, wat die uitsending intyds kyk. Hulle skep al die gebeure: iemand is afgestuur, iemand is beseer, 'n soort plaasvervanger ...

Met die hulp van CMS kom die data in die databasis. Daarna gebruik die databasis die Luister/kennisgewing-meganisme om die API-bedieners hieroor in kennis te stel. API-bedieners stuur reeds hierdie inligting aan kliënte. Ons het dus in werklikheid net 'n paar bedieners wat aan die databasis gekoppel is en daar is geen spesiale las op die databasis nie, omdat die kliënt op geen manier direk met die databasis interaksie het nie:

Mikhail Salosin. Golang vergadering. Gebruik Go in die agterkant van die Look+-toepassing

PostgreSQL: Luister / Stel in kennis

Die Luister / Kennisgewing-meganisme in Postgres laat jou toe om gebeurtenis-intekenare in kennis te stel dat een of ander gebeurtenis verander het - een of ander rekord is in die databasis geskep. Om dit te doen, het ons 'n eenvoudige sneller en funksie geskryf:

Mikhail Salosin. Golang vergadering. Gebruik Go in die agterkant van die Look+-toepassing

Wanneer 'n rekord ingevoeg of verander word, roep ons die kennisgewing-funksie op die data_updates-kanaal deur die naam van die tabel en die ID van die rekord wat daar verander of ingevoeg is, deur te gee.

Vir alle tabelle wat met die kliënt gesinchroniseer moet word, definieer ons 'n sneller wat, na die verandering / opdatering van 'n rekord, die funksie wat op die skyfie hieronder aangedui word, oproep.
Hoe onderskryf die API hierdie veranderinge?

'n Fanout-meganisme word geskep - dit stuur boodskappe aan die kliënt. Dit versamel alle klantekanale en versprei die opdaterings wat dit ontvang het deur hierdie kanale:

Mikhail Salosin. Golang vergadering. Gebruik Go in die agterkant van die Look+-toepassing

Hier is die pq-standaardbiblioteek, wat aan die databasis koppel en sê dat dit na die kanaal wil luister (data_updates), kyk of die verbinding oop is en alles in orde is. Ek laat foutkontrolering weg om spasie te bespaar (nie kontrolering is riskant).

Vervolgens stel ons asinchronies 'n Tikker in wat elke 15 sekondes 'n ping sal stuur en begin luister na die kanaal waarop ons ingeteken het. As ons 'n ping kry, publiseer ons hierdie ping. As ons een of ander rekord ontvang het, publiseer ons hierdie rekord aan alle intekenare van hierdie Fanout'a.

Hoe werk fan-out?

In Russies word dit vertaal as "splitter". Ons het een voorwerp wat intekenare registreer wat een of ander soort opdaterings wil ontvang. En sodra 'n opdatering van hierdie voorwerp aankom, versprei dit hierdie opdatering aan al sy intekenare. Eenvoudig genoeg:

Mikhail Salosin. Golang vergadering. Gebruik Go in die agterkant van die Look+-toepassing

Hoe dit in Go geïmplementeer word:

Mikhail Salosin. Golang vergadering. Gebruik Go in die agterkant van die Look+-toepassing

Daar is 'n struktuur, dit word gesinchroniseer met die hulp van Mutex'ov. Dit het 'n veld wat die toestand van Fanout se verbinding met die databasis stoor, dit wil sê op die oomblik dat dit luister en opdaterings sal ontvang, sowel as 'n lys van alle beskikbare kanale - kaart, waarvan die sleutel die kanaal en struktuur as waardes is (in werklikheid word dit op geen manier gebruik nie).

Twee metodes - Gekoppel en Ontkoppel - laat jou toe om vir Fanout te vertel dat ons 'n verbinding met die basis het, dit het verskyn en dat die verbinding met die basis verbreek is. In die tweede geval moet jy alle kliënte ontkoppel en vir hulle sê dat hulle na niks meer kan luister nie en dat hulle weer koppel omdat die verbinding met hulle gesluit is.

Daar is ook 'n intekenmetode wat die kanaal by die "luisteraars" voeg:

Mikhail Salosin. Golang vergadering. Gebruik Go in die agterkant van die Look+-toepassing

Daar is die Unsubscribe-metode, wat die kanaal van die luisteraars verwyder as die kliënt ontkoppel word, sowel as die Publiseer-metode, wat jou toelaat om 'n boodskap aan alle intekenare te stuur.

Vraag: Wat word op hierdie kanaal uitgesaai?

MS: - Die model wat verander het of ping word oorgedra (in wese net 'n getal, heelgetal).

MS: - Jy kan enigiets, enige struktuur stuur, dit publiseer - dit verander net in JSON en dit is dit.

MS: - Ons ontvang 'n kennisgewing van Postgres - dit bevat die naam van die tabel en die identifiseerder. By die naam van die tabel kry ons en die identifiseerder kry ons die rekord wat ons benodig, en ons stuur hierdie struktuur vir publikasie.

Infrastruktuur

Hoe lyk dit in terme van infrastruktuur? Ons het 7 ysterbedieners: een van hulle is heeltemal toegewy aan die basis, die ander ses gebruik virtuele masjiene. Daar is 6 kopieë van die API: elke virtuele masjien met die API loop op 'n aparte ysterbediener - dit is vir betroubaarheid.

Mikhail Salosin. Golang vergadering. Gebruik Go in die agterkant van die Look+-toepassing

Ons het twee frontends wat Keepalived geïnstalleer het om toeganklikheid te verbeter sodat een frontend die ander kan vervang as iets verkeerd loop. Ook - twee kopieë van die CMS.

Daar is ook 'n statistiek-invoerder. Daar is 'n DB Slaaf waaruit rugsteun periodiek gemaak word. Daar is Pigeon Pusher - die toepassing wat stoot na kliënte stuur, sowel as infrastruktuurdinge: Zabbix, Graylog2 en Chef.

Trouens, hierdie infrastruktuur is oorbodig, want 100 duisend kan met minder bedieners bedien word. Maar daar was yster - ons het dit gebruik (ons is meegedeel dat dit moontlik is - hoekom nie).

Voordele van Go

Nadat ons aan hierdie toepassing gewerk het, het sulke ooglopende voordele van Go aan die lig gekom.

  • Cool http-biblioteek. Daarmee kan jy reeds "buite die boks" heelwat skep.
  • Plus, kanale wat ons in staat gestel het om baie maklik 'n meganisme te implementeer om kennisgewings aan kliënte te stuur.
  • Die wonderlike Race-detektor-funksie het ons in staat gestel om verskeie kritieke foute (vervoer-infrastruktuur) uit te skakel. Alles wat op verhoogwerk werk, is aan die gang, saamgestel met die Race-sleutel; en ons kan dus op die verhooginfrastruktuur sien watter potensiële probleme ons het.
  • Minimalisme en eenvoud van die taal.

Mikhail Salosin. Golang vergadering. Gebruik Go in die agterkant van die Look+-toepassing

Ons is op soek na ontwikkelaars! As iemand wil - asseblief.

vrae

Vraag van die gehoor (hierna - V): - Ek dink jy het een belangrike punt oor Fan-out gemis. Verstaan ​​ek reg dat wanneer jy 'n antwoord aan 'n kliënt stuur, jy blokkeer as die kliënt nie wil lees nie?

MS: Nee, ons blokkeer nie. Eerstens, ons het dit alles agter nginx, dit wil sê, daar is geen probleme met stadige kliënte nie. Tweedens het die kliënt 'n kanaal met 'n buffer - om die waarheid te sê, ons kan tot honderd opdaterings daar plaas ... As ons nie na die kanaal kan skryf nie, dan verwyder dit dit. As ons sien dat die kanaal geblokkeer is, dan sluit ons eenvoudig die kanaal, en dit is dit - die kliënt sal weer koppel as daar enige probleem is. Daarom vind blokkering in beginsel nie hier plaas nie.

IN: - Kon dit nie dadelik gestuur word na Luister / Stel 'n rekord in kennis, en nie 'n identifiseerdertabel nie?

MS: - Luister/kennisgewing het 'n limiet van 8k grepe op die vooraflading wat dit stuur. In beginsel sou dit moontlik wees om te stuur as ons met 'n klein hoeveelheid data te doen het, maar dit lyk vir my of hierdie manier [soos ons doen] eenvoudig meer betroubaar is. Die beperkings is in Postgres self.

IN: – Ontvang klante opdaterings oor wedstryde waarin hulle nie belangstel nie?

MS: – Oor die algemeen, ja. As 'n reël is daar 2-3 wedstryde parallel, en dan redelik selde. As 'n kliënt iets kyk, dan kyk hy gewoonlik na die wedstryd wat aan die gang is. Dan, op die kliënt, is daar 'n plaaslike databasis waarin al hierdie opdaterings bygevoeg word, en selfs sonder 'n internetverbinding kan die kliënt alle vorige wedstryde kyk waarvoor hy opdaterings het. Trouens, ons sinchroniseer ons databasis op die bediener met die kliënt se plaaslike databasis sodat dit vanlyn kan werk.

IN: – Hoekom het jy jou ORM gemaak?

Alexey (een van die ontwikkelaars van "Look +"): - Destyds (dit was 'n jaar gelede) was daar minder ORM's as nou, toe daar nogal baie van hulle is. Van die meeste ORM's daar buite, wat ek die meeste hou, is dat die meeste van hulle op leë koppelvlakke werk. Dit wil sê, die metodes wat in hierdie ORM's gereed is om enigiets aan te neem: 'n struktuur, 'n struktuurwyser, 'n getal, iets heeltemal irrelevant ...

Ons ORM genereer strukture gebaseer op die datamodel. Ekself. En dus is alle metodes konkreet, gebruik nie refleksie nie, ens. Hulle aanvaar strukture en verwag om enige strukture te gebruik.

IN: – Hoeveel mense het deelgeneem?

MS: - Aan die beginstadium het twee mense deelgeneem. Iewers in Junie het ons begin, in Augustus was die hoofgedeelte gereed (die eerste weergawe). Daar was 'n vrylating in September.

IN: - Waar jy SSE beskryf, gebruik jy nie time-out nie. Hoekom is dit?

MS: - Om eerlik te wees, is SSE steeds 'n html5-protokol: die SSE-standaard is ontwerp om met blaaiers te kommunikeer, sover ek verstaan. Dit het bykomende kenmerke sodat blaaiers weer kan koppel (ensovoorts), maar ons het dit nie nodig nie, want ons het kliënte gehad wat enige logika kon implementeer om inligting te koppel en te ontvang. Ons het nie eerder SSE gedoen nie, maar iets soortgelyk aan SSE. Dit is nie die protokol self nie.
Daar was geen behoefte nie. Sover ek verstaan, het kliënte die verbindingsmeganisme amper van nuuts af geïmplementeer. Hulle het basies nie omgegee nie.

IN: – Watter bykomende nutsprogramme het jy gebruik?

MS: – Ons het govet en golint die aktiefste gebruik om die styl konsekwent te hou, sowel as gofmt. Niks anders is gebruik nie.

IN: - Wat het jy gebruik om dit reg te maak?

MS: - Ontfouting het oor die algemeen gegaan met behulp van toetse. Ons het geen ontfouter gebruik nie, GOP.

IN: - Kan jy die skyfie terugstuur waar die Publiseer-funksie geïmplementeer is? Pla enkelletterveranderlike name jou?

MS: - Geen. Hulle het 'n redelik "nou" omvang. Hulle word nêrens gebruik nie, behalwe hier (behalwe vir die interne van hierdie klas), en dit is baie kompak - dit neem net 7 reëls.

IN: Op een of ander manier is dit steeds nie intuïtief nie ...

MS: - Nee, nee, dit is 'n regte kode! Dit gaan nie oor styl nie. Dit is net so 'n utilitaristiese, baie klein klas - net 3 velde binne die klas ...

Mikhail Salosin. Golang vergadering. Gebruik Go in die agterkant van die Look+-toepassing

MS: – Oor die algemeen verander al die data wat met kliënte gesinchroniseer word (seisoenale wedstryde, spelers) nie. Rofweg gesproke, as ons 'n ander soort sport maak waarin ons die wedstryd moet verander, sal ons eenvoudig alles in ag neem in die nuwe weergawe van die kliënt, en die ou weergawes van die kliënt sal verban word.

IN: – Is daar enige derdeparty-pakkette vir die bestuur van afhanklikhede?

MS: Ons het go dep gebruik.

IN: - In die onderwerp van die verslag was daar iets oor video, maar daar was geen video in die verslag nie.

MS: – Nee, ek het niks in die onderwerp oor die video nie. Dit word "Kyk+" genoem - dit is wat die toepassing genoem word.

IN: – Jy het gesê dat jy vir kliënte stroom?

MS: - Ons het nie te doen gehad met streaming video nie. Dit is heeltemal deur Megafon gedoen. Ja, ek het nie gesê dat die toepassing megafoon is nie.

MS: - Gaan - vir die stuur van alle data - volgens telling, volgens wedstrydgebeurtenisse, statistieke ... Gaan is die hele agterkant vir die toepassing. Die kliënt moet van iewers af weet watter skakel om vir die speler te gebruik sodat die gebruiker die wedstryd kan kyk. Ons het skakels na video's en strome wat voorberei is.

Sommige advertensies 🙂

Dankie dat jy by ons gebly het. Hou jy van ons artikels? Wil jy meer interessante inhoud sien? Ondersteun ons deur 'n bestelling te plaas of by vriende aan te beveel, wolk VPS vir ontwikkelaars vanaf $4.99, 'n unieke analoog van intreevlakbedieners, wat deur ons vir jou uitgevind is: Die hele waarheid oor VPS (KVM) E5-2697 v3 (6 Cores) 10GB DDR4 480GB SSD 1Gbps vanaf $19 of hoe om 'n bediener te deel? (beskikbaar met RAID1 en RAID10, tot 24 kerne en tot 40 GB DDR4).

Dell R730xd 2x goedkoper in Equinix Tier IV-datasentrum in Amsterdam? Net hier 2 x Intel TetraDeca-Core Xeon 2x E5-2697v3 2.6GHz 14C 64GB DDR4 4x960GB SSD 1Gbps 100 TV vanaf $199 in Nederland! Dell R420 - 2x E5-2430 2.2Ghz 6C 128GB DDR3 2x960GB SSD 1Gbps 100TB - vanaf $99! Lees van Hoe om infrastruktuur korp. klas met die gebruik van Dell R730xd E5-2650 v4-bedieners ter waarde van 9000 XNUMX euro vir 'n sent?

Bron: will.com

Voeg 'n opmerking