Socket.io -sovelluksen lisääminen monisäikeiseen Node.js-tiedostoon

Kuva Vidar Nordli-Mathisen on Unsplash

Yksi solmun haitoista on, että se on yksisäikeinen. Tietysti on olemassa tapa sen ympärille - nimittäin klusteriksi kutsuttu moduuli. Klusterin avulla voimme levittää sovelluksemme useille säikeille.

Nyt kuitenkin esiintyy uusi ongelma. Katso, useilla tapauksilla ajetulla koodillamme on todella merkittäviä haittapuolia. Yhdellä heistä ei ole globaaleja valtioita.

Tavallisesti yksisäikeisissä tapauksissa tämä ei ole paljon huolestuttavaa. Meille se muuttaa nyt kaiken.

Katsotaanpa miksi.

Joten mikä on ongelma?

Sovelluksemme on yksinkertainen verkkokeskustelu, joka toimii neljällä ketjulla. Tämä mahdollistaa käyttäjän kirjautumisen samanaikaisesti puhelimeen ja tietokoneeseen.

Kuvittele, että pistorasiat on asennettu täsmälleen samalla tavalla kuin olisimme asettaneet ne yhdelle kierteelle. Toisin sanoen meillä on nyt yksi iso globaali valtio, jossa on pistorasiat.

Kun käyttäjä kirjautuu sisään tietokoneellaan, verkkosivusto avaa yhteyden palvelimemme Socket.io-ilmentymään. Pistorasia on tallennettu kierteen # 3 tilaan.

Kuvittele nyt, että käyttäjä menee keittiöön napata välipalaa ja ottaa puhelimen mukanaan - haluaa luonnollisesti pitää tekstiviestejä ystäviensä kanssa verkossa.

Heidän puhelin muodostaa yhteyden ketjuun 4, ja pistorasia tallennetaan langan tilassa.

Viestin lähettäminen puhelimesta ei tee käyttäjälle mitään hyötyä. Vain viestiketjujen nro 3 ihmiset näkevät viestin. Tämä johtuu siitä, että säieeseen # 3 tallennetut pistorasiat eivät jotenkin ole maagisesti tallennettuina myös ketjuihin # 1, # 2 ja # 4.

Hauska, edes käyttäjä itse ei näe viestejään tietokoneellaan, kun he tulevat takaisin keittiöstä.

Tietenkin, kun he päivittävät verkkosivuston, voisimme lähettää GET-pyynnön ja hakea viimeiset 50 viestiä, mutta emme voi oikeasti sanoa, että se on ”dynaaminen” tapa, voimmeko?

Miksi tämä tapahtuu?

Palvelimemme levittäminen useille ketjuille on jollain tapaa samanarvoista, että meillä on useita erillisiä palvelimia. He eivät tiedä toistensa olemassaolosta eivätkä varmasti jaa mitään muistia. Tämä tarkoittaa, että yhtä instanssia koskevaa objektia ei ole toisessa.

Lankaan 3 tallennetut pistorasiat eivät välttämättä ole kaikkia käyttäjän tällä hetkellä käyttämiä pistorasioita. Jos käyttäjän ystävät ovat eri säieissä, he eivät näe käyttäjän viestejä, elleivät he päivitä verkkosivustoa.

Ihannetapauksessa haluaisimme ilmoittaa muille tapauksille tapahtumasta käyttäjälle. Tällä tavoin voimme olla varmoja, että jokainen kytketty laite vastaanottaa päivityksiä.

Ratkaisu

Voimme ilmoittaa muille ketjuille käyttämällä Redisin julkaisu- / tilaustiedotusmalli (pubsub).

Redis on avoimen lähdekoodin (BSD-lisensoitu) muistin sisäinen tietorakennevarasto. Sitä voidaan käyttää tietokannana, välimuistina ja viestinvälittäjänä.

Tämä tarkoittaa, että voimme käyttää Redis-sovellusta tapahtumien jakamiseen instanssiemme välillä.

Huomaa, että yleensä varastoimme koko rakenteemme Redisin sisälle. Koska rakennetta ei kuitenkaan voida sarjoittaa ja se on pidettävä "elossa" muistin sisällä, tallennamme osan siitä jokaisessa esiintymässä.

Virtaus

Ajattellaan nyt vaiheita, joissa aiomme käsitellä saapuvaa tapahtumaa.

  1. Viestinä kutsuttu tapahtuma tulee yhteen pistorasioistamme - tällä tavalla meidän ei tarvitse kuunnella kaikkia mahdollisia tapahtumia.
  2. Objektin sisällä, joka on siirretty argumentiksi tämän tapahtuman käsittelijälle, löydämme tapahtuman nimen. Esimerkiksi sendMessage - .on ('viesti', ({tapahtuma}) => {}).
  3. Jos tälle nimelle on käsittelijä, suoritamme sen.
  4. Käsittelijä voi suorittaa lähettämisen vastauksella.
  5. Lähetys lähettää vastaustapahtuman Redis-pubiin. Sieltä se pääsee jokaiseen tapaukseemme.
  6. Jokainen ilmentymä lähettää sen socketsState-tilaansa varmistaen, että jokainen kytketty asiakas vastaanottaa tapahtuman.

Tuntuu monimutkaiselta, tiedän, mutta kestää kanssani.

Toteutus

Tässä on arkisto, jonka ympäristö on valmis, joten meidän ei tarvitse asentaa ja asettaa kaikkea itse.

Ensinnäkin aiomme perustaa palvelin Expressin kanssa.

Luomme Express-sovelluksen, HTTP-palvelimen ja init-pistorasiat.

Nyt voimme keskittyä pistorasioiden lisäämiseen.

Välitämme Socket.ion palvelin-ilmentymän toiminnollemme, johon asetamme keskitason.

onAuth

OnAuth-toiminto yksinkertaisesti jäljittelee valheellista valtuutusta. Meidän tapauksessamme se on merkkiperusteinen.

Henkilökohtaisesti korvaan sen todennäköisesti tulevaisuudessa JWT: llä, mutta sitä ei panna millään tavalla täytäntöön.

Siirrytään nyt onConnection-väliohjelmaan.

onConnection

Täällä näemme, että haemme käyttäjän tunnuksen, joka oli asetettu edellisessä väliohjelmassa, ja tallennamme sen socketsState-sovellukseen avaimen ollessa tunnus ja arvo on joukko pistorasioita.

Seuraavaksi kuuntelemme viestitapahtumaa. Koko logiikkamme perustuu siihen - jokaiselle etumatkan meille lähettämälle tapahtumalle annetaan nimi: viesti.

Tapahtuman nimi lähetetään argumenttiobjektin sisään - kuten yllä todettiin.

käsittelijät

Kuten voit nähdä onConnectionissa, erityisesti viestitapahtuman kuuntelijassa, etsimme käsittelijää tapahtuman nimen perusteella.

Käsittelijämme ovat yksinkertaisesti esine, jossa avain on tapahtuman nimi ja arvo on funktio. Käytämme sitä kuunnella tapahtumia ja reagoida vastaavasti.

Lisäksi myöhemmin aiomme lisätä lähetystoiminnon ja käyttää sitä tapahtuman lähettämiseen esiintymien yli.

SocketsState

Tiedämme valtiomme rajapinnan, mutta sitä ei ole vielä toteutettu.

Lisäämme menetelmiä pistorasian lisäämiseksi ja poistamiseksi sekä tapahtuman lähettämiseksi.

Lisää-toiminto tarkistaa, onko tilillä ominaisuus, joka on yhtä suuri kuin käyttäjän tunnus. Jos näin on, lisäämme sen yksinkertaisesti jo olemassa olevaan taulukkoomme. Muussa tapauksessa luomme ensin uuden taulukon.

Poista-toiminto tarkistaa myös, onko valtion ominaisuuksissa käyttäjän tunnus. Jos ei - se ei tee mitään. Muutoin se suodattaa taulukon kannen poistamiseksi taulukosta. Sitten, jos taulukko on tyhjä, se poistaa sen tilasta asettamalla ominaisuuden määrittelemättömäksi.

Redisin pubi

Pubsub-sivustomme luomiseen aiomme käyttää pakettia nimeltä node-redis-pubsub.

Lähetyksen lisääminen

Ok, nyt on jäljellä vain lähettämistoiminto ...

… Ja lisää kuuntelija lähtevälle_socket_viestille. Tällä tavalla jokainen ilmentymä vastaanottaa tapahtuman ja lähettää sen käyttäjän pistorasioihin.

Tehdään kaikesta monisäikeinen

Lisää lopuksi koodi, jota tarvitaan palvelimemme monisäikeiseksi tekemiseen.

Huomaa: Meidän täytyy tappaa satama, koska lopetettuamme Nodemon-prosessimme Ctrl + c: llä, se vain roikkuu siinä.

Pienellä säätämisellä meillä on nyt toimivia pistorasioita kaikissa tapauksissa. Seurauksena: paljon tehokkaampi palvelin.

Kiitos paljon lukemisesta!

Arvostan sitä, että kaikki saattaa tuntua aluksi ylivoimaiselta ja raskaalta ottaa se kaikki kerralla. Kannustan tätä mielestäni lukemaan koodi uudelleen kokonaisuudessaan ja pohtimaan sitä kokonaisuutena.

Jos sinulla on kysyttävää tai kommentteja, lisää ne alla olevaan kommenttiosaan tai lähetä minulle viesti.

Tutustu sosiaaliseen mediaani!

Liity uutiskirjeeni!

Alun perin julkaistu osoitteessa www.mcieslar.com 10. syyskuuta 2018.