📜 ⬆️ ⬇️

We write the first microservice on Node.js with communication through RabbitMQ

Over time, each project grows and it becomes more difficult, longer and more expensive for the business to implement the new functionality into the existing monolith.


One of the solutions to this problem is the use of microservice architecture. For beginners or for those who first encounter this architecture, it can be difficult to understand where to start, what to do and what not to do.


In this article, the simplest microservice will be written on Nodejs & RabbitMQ, and the process of monolith migration to microservices is also shown.


What is in microservice architecture?


  1. Gateway The main server that accepts requests and redirects them to the desired microservice. Most often, there is no business logic in gateway.
  2. Microservice. Microservice itself, which handles user requests with clearly defined business logic.
  3. Transport. This is the part through which Gateway & Microservice will communicate. HTTP, gRPC, RabbitMQ, etc. can act as a transport.

Why use RabbitMQ?


Of course, you can not use RabbitMQ, there are other options for communication between microservices. The easiest one is HTTP, there is gRPC from Google.


I use RabbitMQ, because I consider it simple enough to start writing microservices, reliable and convenient in the sense that sending a message to a queue, you can be sure that the message will reach the microservice (even if it is turned off at the moment and then turned on ). Thanks to these advantages, you can write reliable microservices and use seamless deploy.


Start


To begin with, we will implement a simple gateway that will accept HTTP requests while listening to a specific port.


We deploy RabbitMQ (through it our microservices and gateway will communicate):


$ docker run -d -p 5672:5672 rabbitmq 

Initialize the project and install the micromq NPM package:


 $ npm init -y $ npm i micromq -S 

We write gateway


 //   Gateway     micromq const Gateway = require('micromq/gateway'); //    Gateway const app = new Gateway({ //  ,      microservices: ['users'], //  rabbitmq rabbit: { //     rabbitmq (default: amqp://guest:guest@localhost:5672) url: process.env.RABBIT_URL, }, }); //    /friends & /status   GET app.get(['/friends', '/status'], async (req, res) => { //     users await res.delegate('users'); }); //    app.listen(process.env.PORT); 

How it will work:


  1. The server starts, it starts listening to the port and receiving requests
  2. User sends a request to https://mysite.com/friends
  3. Gateway, according to the logic we described, delegates the request:
    3.1. The message is being sent (request parameters, headers, connection information, etc.) to the RabbitMQ queue
    3.2. Microservice listens to this queue, processes a new request.
    3.3. Microservice sends a response to the queue
    3.4. Gateway listens to the response queue, receives a response from microservice
    3.5. Gateway sends a response to the client.
  4. User gets answer

We write microservice


 //   MicroService     micromq const MicroMQ = require('micromq'); //    MicroService const app = new MicroMQ({ //   (    ,    Gateway) name: 'users', //  rabbitmq rabbit: { //     rabbitmq (default: amqp://guest:guest@localhost:5672) url: process.env.RABBIT_URL, }, }); //   /friends   GET app.get('/friends', (req, res) => { //  json  res.json([ { id: 1, name: 'Mikhail Semin', }, { id: 2, name: 'Ivan Ivanov', }, ]); }); //   /status   GET app.get('/status', (req, res) => { //  json  res.json({ text: 'Thinking...', }); }); //     app.start(); 

How it will work:


  1. The microservice starts, starts listening to the queue of requests that Gateway will write to
  2. Microservice receives a request, processes it, driving it through all available middlewares
  3. Microservice sends a response to Gateway
    3.1. Sending message (headers, HTTP code response body) to RabbitMQ queue
    3.2. Gateway listens to this queue, receives a message, finds a client to whom to send a response
    3.3 Gateway sends response to client

Monolith Migration to Microservice Architecture


Suppose that we already have an application on express, and we want to start transferring it to microservices.


It looks like this:


 const express = require('express'); const app = express(); app.get('/balance', (req, res) => { res.json({ amount: 500, }); }); app.get('/friends', (req, res) => { res.json([ { id: 1, name: 'Mikhail Semin', }, { id: 2, name: 'Ivan Ivanov', }, ]); }); app.get('/status', (req, res) => { res.json({ text: 'Thinking...', }); }); app.listen(process.env.PORT); 

We want to take out from it 2 endpoints: / friends and / status. What do we need to do for this?


  1. Take business logic to microservice
  2. Implement the delegation of requests for these two endpoints to microservice
  3. Get a response from microservice
  4. Send response to customer

In the example above, when we created microservice users, we implemented two methods / friends and / status, which do the same thing that our monolith does.


In order to proxy requests to microservice from gateway, we will use the same package, connecting the middleware to our express application:


 const express = require('express'); //   Gateway     micromq const Gateway = require('micromq/gateway'); const app = express(); //    Gateway const gateway = new Gateway({ //   (    ,    Gateway) name: 'users', //  rabbitmq rabbit: { //     rabbitmq (default: amqp://guest:guest@localhost:5672) url: process.env.RABBIT_URL, }, }); //  middleware  ,      app.use(gateway.middleware()); //    ,          app.get('/balance', (req, res) => { res.json({ amount: 500, }); }); //    /friends & /status   GET app.get(['/friends', '/status'], async (req, res) => { //     users //  res.delegate   middleware,     await res.delegate('users'); }); //   app.listen(process.env.PORT); 

This works in the same way as in the example above, where we wrote the pure Gateway. In this example, the only difference is that the requests are received not by the Gateway, but by a monolith written in express.


What's next


  1. RPC (remote action call) from microservice to monolith / gateway (for example, for authorization)
  2. Communicate between microservices through the RabbitMQ queues for more information, because each microservice has its own database

I already told you this in the article “Learning to communicate between microservices on Node.js via RabbitMQ” .



')

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


All Articles