MICROSERVICES USING NODE.JS AND RABBITMQ
Case
Share your location with your friends
API Back-end
Key = DevOps
Microservices ↓ Microdeployments
Reasons
Team
Architecture
Best Practices
Code Review
Tests
Continuous Integration
Continuous Delivery
Continuous Monitoring
User Message Lorem Ipsum Dolor Sit Amet
Libraries
Results after 10 months
Startup 5 back-end developers 7 micro-services
Positives
New technologies
Minimum effort/impact
MySQL MySQL Postgre SQL Postgre SQL MySQL Postgre SQL Postgre SQL
Polyglot Persistence
Decoupled Code
Each service has a scope
Negatives
Shotgun effect
Granular Release
Unstable Interfaces
User Message
Integration Tests
Slow
Docker
New developers
User-service dependency
User Message Lorem Ipsum Dolor Sit Amet
Lorem Ipsum Dolor Amet
Microservices
Client Server
Server
1 const express = require('express'); 2 const bodyParser = require('body-parser'); 3 4 const app = express(); 5 app.use(bodyParser.json()); 6 7 app.listen(3000, () => { 8 console.log(' [x] Awaiting for requests'); 9 }); 10 11 app.get('/:id', (request, response) => { 12 const id = request.params.id; 13 14 console.log(` [.] ID ${id}`); 15 16 response.status(200).json({ 17 data: { 18 name: 'Ada Lovelace', 19 occupation: 'Programmer' 20 } 21 }); 22 });
1 app.listen(3000, () => { 2 console.log(' [x] Awaiting for requests'); 3 }); 4 5 app.get('/:id', (request, response) => { 6 const id = request.params.id; 7 8 console.log(` [.] ID ${id}`); 9 10 response.status(200).json({ 11 data: { 12 name: 'Ada Lovelace', 13 occupation: 'Programmer' 14 } 15 }); 16 });
Client
1 const express = require('express'); 2 const request = require('request-promise'); 3 4 const id = process.argv.slice(2); 5 6 const app = express(); 7 8 app.listen(3005, () => { 9 console.log(` [x] Requesting user ${id}`); 10 11 request(`http://localhost:3000/${id}`) 12 .then((res) => { 13 return console.log(` [.] Got ${res}`) 14 }); 15 });
1 const id = process.argv.slice(2); 2 3 app.listen(3005, () => { 4 console.log(` [x] Requesting user ${id}`); 5 6 request(`http://localhost:3000/${id}`) 7 .then((res) => { 8 return console.log(` [.] Got ${res}`) 9 }); 10 });
Result
Client
Fault resilience
Message Broker
AMPQ Advanced Message Queuing Protocol
Exchange asynchronous messages
Reliability
RPC Remote Procedure Call
Queueing
Client ServerRPC
Server
1 const amqp = require('amqplib/callback_api'); 2 3 amqp.connect('amqp://localhost', (err, conn) => { 4 conn.createChannel((err, ch) => { 5 const q = 'rpc_queue'; 6 7 ch.assertQueue(q, { durable: false }); 8 ch.prefetch(1); 9 10 console.log(' [x] Awaiting RPC requests'); 11 12 ch.consume(q, function reply(msg) { 13 const id = parseInt(msg.content.toString(), 10); 14 15 console.log(` [.] ID ${id}`); 16 17 ch.sendToQueue(msg.properties.replyTo, 18 new Buffer('name: Ada Lovelace, occupation: programmer'), 19 { correlationId: msg.properties.correlationId }); 20 21 ch.ack(msg); 22 }); 23 }); 24 });
rpc_queue Response Channel 3 amqp.connect('amqp://localhost', (err, conn) => { 4 conn.createChannel((err, ch) => { 5 const q = 'rpc_queue';
Retrieve message from rpc_queue 12 ch.consume(q, function reply(msg) { 13 const id = parseInt(msg.content.toString(), 10); 14 15 console.log(` [.] ID ${id}`);
Send response to callback queue 17 ch.sendToQueue(msg.properties.replyTo, 18 new Buffer('name: Ada Lovelace, occupation: programmer’), 19 { correlationId: msg.properties.correlationId });
Client
1 const amqp = require('amqplib/callback_api'); 2 const uuid = require('uuid'); 3 4 const id = process.argv.slice(2); 5 6 amqp.connect('amqp://localhost', (err, conn) => { 7 conn.createChannel((err, ch) => { 8 ch.assertQueue('', { exclusive: true }, (err, q) => { 9 10 const corr = uuid(); 11 console.log(` [x] Requesting user ${id}`); 12 13 ch.consume(q.queue, (msg) => { 14 if (msg.properties.correlationId === corr) { 15 console.log(` [.] Got ${msg.content.toString()}`); 16 setTimeout(function() { conn.close(); process.exit(0) }, 500); 17 } 18 }, {noAck: true}); 19 20 ch.sendToQueue('rpc_queue', 21 new Buffer(id.toString()), 22 { correlationId: corr, replyTo: q.queue }); 23 }); 24 }); 25 });
Callback Queue Request Channel 6 amqp.connect('amqp://localhost', (err, conn) => { 7 conn.createChannel((err, ch) => { 8 ch.assertQueue('', { exclusive: true }, (err, q) => {
Request to rpc_queue 10 const corr = uuid(); 20 ch.sendToQueue('rpc_queue', 21 new Buffer(id.toString()), 22 { correlationId: corr, replyTo: q.queue });
Retrieve response from callback queue 13 ch.consume(q.queue, (msg) => { 14 if (msg.properties.correlationId === corr) { 15 console.log(` [.] Got ${msg.content.toString()}`); 16 setTimeout(function() { conn.close(); process.exit(0) }, 500); 17 } 18 }, {noAck: true});
Result
Scalability
Round-Robin
Queues Performance
Conclusion
Any organization that designs a system (defined broadly) will produce a design whose structure is a copy of the organization's communication structure. Conway's Law
Engineering
Trade-Off
How to solve my team problems?
Shotgun effect Unstable interfaces Integration tests User-service dependency
Monolith
Partially
User Message Lorem Ipsum Dolor Sit Amet
User LoremIpsum
Shotgun effect Unstable interfaces Integration tests User-service dependency
Community
Let technology empower you!
Thanks!
https://github.com/carolpc https://twitter.com/CarolinaPascale carolina.pascale.c@gmail.com

Microservices using Node.js and RabbitMQ