Lernen, über RabbitMQ zwischen Microservices auf Node.js zu kommunizieren

Dies ist eine Fortsetzung des Artikels " Wir schreiben den ersten Microservice auf Node.js mit Kommunikation über RabbitMQ ", der von den Benutzern des Habr gut aufgenommen wurde.


In diesem Artikel werde ich darüber sprechen, wie man richtig zwischen Mikrodiensten kommuniziert, damit Mikrodienste isoliert bleiben.


Wie man es nicht macht


Warum müssen Sie zwischen Microservices kommunizieren? Verwenden Sie eine Datenbank, lesen Sie von dort aus, was Sie wollen - etwas unternehmen!


Nein, das kannst du nicht. Das Konzept von Microservices ist, dass sie voneinander isoliert sind, niemand (praktisch) etwas über jemanden weiß. Höchstwahrscheinlich möchten Sie in Zukunft, wenn das System zu wachsen beginnt, die Funktionalität erweitern und zwischen Microservices kommunizieren: Beispielsweise hat ein Benutzer ein Produkt gekauft, sodass Sie dem Verkäufer eine Benachrichtigung über den Verkauf senden müssen.


Isolationsvorteile


Zuverlässigkeit


Angenommen, es gibt eine monolithische Anwendung, in der es mehrere Controller gibt:


  1. Produkte
  2. Rabatte
  3. Der Blog
  4. Benutzer

Eines schönen Tages sinkt unsere Datenbank: Jetzt können wir keine Produkte, keine Rabatte, keine Blog-Beiträge, keine Benutzer mehr erhalten. Die Website ist nicht verfügbar, Kunden können sich nicht anmelden, das Geschäft verliert Gewinne.


Was wird in der Microservice-Architektur passieren?


In einem anderen Universum wird die Benutzer-Microservice-Datenbank am selben Tag nicht mehr zugänglich: Benutzer können sich nicht abmelden, registrieren und anmelden. Es scheint, dass alles schlecht ist und das Geschäft auch Gewinn verliert, aber nein: Potenzielle Käufer können sich die verfügbaren Waren ansehen, den Blog des Unternehmens lesen und Rabatte finden.


Aufgrund der Tatsache, dass jeder Microservice eine eigene Datenbank hat, werden die Nebenwirkungen viel geringer.


Dies wird als allmähliche Verschlechterung bezeichnet .


Abstraktion


In einer großen Anwendung ist es sehr schwierig, sich auf eine Aufgabe zu konzentrieren, da das Ändern einer kleinen Middleware eine Art Controller beschädigen kann. Möchten Sie den neuen Client für Redis verwenden? Nein, der Controller, den wir vor drei Jahren geschrieben haben, verwendet die Version 0.1.0. Möchten Sie endlich die neuen Funktionen von Node.js 10 nutzen? Oder vielleicht 12? Entschuldigung, aber der Monolith verwendet Version 6.


Wie kommuniziere ich?


Da wir über das Beispiel "Ein Benutzer hat ein Produkt gekauft, senden wir eine Verkaufsbenachrichtigung an den Verkäufer" gesprochen haben, werden wir es implementieren.


Das Schema ist wie folgt:


  1. Der Benutzer sendet eine Anfrage an den Microservice-Markt, um Dinge unter dem Link / market / buy /: id zu kaufen
  2. Das Flag wird in die Datenbank geschrieben, dass das Produkt verkauft wird
  3. Vom Microservice-Markt wird eine Anfrage an die Microservice-Benachrichtigungen gesendet, mit denen Clients über WebSocket verbunden sind
  4. Microservice-Benachrichtigungen senden eine Nachricht an den Verkäufer über den Verkauf von Dingen

Installieren Sie MicroMQ


$ npm i micromq@1 -S 

Ein Gateway schreiben


 const Gateway = require('micromq/gateway'); //   const gateway = new Gateway({ microservices: ['market'], rabbit: { url: process.env.RABBIT_URL, }, }); //        market gateway.post('/market/buy/:id', (req, res) => res.delegate('market')); //      gateway.listen(process.env.PORT); 

Unser Gateway besteht nur aus einem Endpunkt, aber das reicht zum Beispiel und für die Schulung.


Schreiben einer Microservice-Benachrichtigung


 const MicroMQ = require('micromq'); const WebSocket = require('ws'); //   const app = new MicroMQ({ name: 'notifications', rabbit: { url: process.env.RABBIT_URL, }, }); //        const ws = new WebSocket.Server({ port: process.env.PORT, }); //     const clients = new Map(); //    ws.on('connection', (connection) => { //     connection.on('message', (message) => { //  ,       . //      try/catch,    json! const { event, data } = JSON.parse(message); //   'authorize'         if (event === 'authorize' && data.userId) { //         clients.set(data.userId, connection); } }); }); //       , //    ! ws.on('close', ...); //   notify,      app.action('notify', (meta) => { //      ,    400 if (!meta.userId || !meta.text) { return [400, { error: 'Bad data' }]; } //     const connection = clients.get(meta.userId); //     ,    404 if (!connection) { return [404, { error: 'User not found' }]; } //    connection.send(meta.text); //  200   return { ok: true }; }); //   app.start(); 

Hier erhöhen wir gleichzeitig den Web-Socket-Server und den Microservice, um Anforderungen sowohl für den Web-Socket als auch für RabbitMQ zu erhalten.


Das Schema ist wie folgt:


  1. Ein Benutzer stellt eine Verbindung zu unserem Web-Socket-Server her
  2. Der Benutzer wird autorisiert, indem er ein authorize mit seiner Benutzer-ID sendet
  3. Wir behalten die Verbindung des Benutzers bei, damit Sie ihm später Benachrichtigungen senden können
  4. Auf RabbitMQ kommt ein Ereignis an, dass Sie eine Benachrichtigung an den Benutzer senden müssen
  5. Überprüfung der Gültigkeit eingehender Daten
  6. Benutzerverbindung abrufen
  7. Benachrichtigung senden

Schreiben eines Microservice-Marktes


 const MicroMQ = require('micromq'); const { Items } = require('./api/mongodb'); //   const app = new MicroMQ({ name: 'market', rabbit: { url: process.env.RABBIT_URL, }, }); //      app.post('/market/buy/:id', async (req, res) => { const { id } = req.params; //      const item = await Items.findOne({ id, isSold: false }); //   ,  404 if (!item) { res.status(404).json({ error: 'Item not found', }); return; } //  ,    ,    await Items.updateOne({ id, }, { $set: { isSold: true, }, }); //     ,    req.app.ask('notifications', { server: { action: 'notify', meta: { userId: item.sellerId, text: JSON.stringify({ event: 'notification', data: { text: `Item #${id} was sold!`, }, }), }, }, }) //  ,      .catch(err => console.log('Cannot send message via notifications microservice', err)); //    ,     res.json({ ok: true, }); }); //   app.start(); 

Das Schema ist wie folgt:


  1. Wir erhalten eine Benutzeranfrage für den Kauf eines Artikels
  2. Wir suchen den Artikel mit der richtigen ID und stellen sicher, dass er noch nicht verkauft ist
  3. Artikel als verkauft markieren
  4. Wir senden dem Verkäufer eine Benachrichtigung über den Verkauf im Hintergrund
  5. Wir antworten dem Kunden

Überprüfen Sie


  1. Wir starten 3 Prozesse
  2. Wir senden POST / market / buy / 1
  3. Wir erhalten die Antwort { ok: true }
  4. Verkäufer erhält Benachrichtigung

 $ PORT=9000 node ./src/gateway.js $ PORT=9001 node ./src/notifications.js $ MONGODB_URL=mongodb://localhost:27017/my-super-microservice node ./src/market.js 


Source: https://habr.com/ru/post/de447250/


All Articles