Microservices with SenecaJS (part 2)

Post on 19-Jan-2017

326 views 3 download

transcript

9/30/16 1

CLICK TO EDIT MASTER TITLE STYLE

Security Classification: Internal

MICROSERVICES WITH SENECAJSTrung Dang Session 2

9/30/16 2

CLICK TO EDIT MASTER TITLE STYLE

Security Classification: InternalSecurity Classification: Internal

Agenda – Session 2▪Docker▪AMQP / RabbitMQ: What is it?▪SenecaJS transportation with AMQP▪Multiple service instances: PM2 or Docker?▪Consul - Service health checker & Configuration▪JWT for Auth▪Introducing servicebase package▪Q/A

9/30/16 3

CLICK TO EDIT MASTER TITLE STYLE

Security Classification: InternalSecurity Classification: Internal

Sample source code is available at https://github.com/immanuel192/seneca-with-rabbitmq-seminar

9/30/16 4

CLICK TO EDIT MASTER TITLE STYLE

Security Classification: Internal

Review Session 1

9/30/16 5

CLICK TO EDIT MASTER TITLE STYLE

Security Classification: InternalSecurity Classification: Internal

Monolithic Application Model

1. How to scale this application to serve more customer requests?

2. The Payments Module is taking very long time to process the requests. Is there any solution with cheap cost?

9/30/16 6

CLICK TO EDIT MASTER TITLE STYLE

Security Classification: InternalSecurity Classification: Internal

9/30/16 7

CLICK TO EDIT MASTER TITLE STYLE

Security Classification: InternalSecurity Classification: Internal

Microservices with Seneca, RabbitMQ, Consul, and FeathersJS

servicebase

Database Models

Service Logic

Service B

NGI

NX

– Lo

ad B

alan

cer

Gate

way

API

1Ga

tew

ay A

PI 2

Rabb

itMQ

Configuration Storage & Health Checker

Docker

servicebase

Database Models

Service Logic

Service A

Redis

9/30/16 8

CLICK TO EDIT MASTER TITLE STYLE

Security Classification: InternalSecurity Classification: Internal

Docker - https://www.docker.com/

9/30/16 9

CLICK TO EDIT MASTER TITLE STYLE

Security Classification: InternalSecurity Classification: Internal

AMQP & RabbitMQ. What is it?

• RabbitMQ is a messaging broker - an intermediary for messaging.

9/30/16 10

CLICK TO EDIT MASTER TITLE STYLE

Security Classification: InternalSecurity Classification: Internal

Service 1

RabbitMQ - How it works

Service 2

Queue

Queue

Exchange

client

Service 1

9/30/16 11

CLICK TO EDIT MASTER TITLE STYLE

Security Classification: InternalSecurity Classification: Internal

docker run -d \

--hostname rabbitmq-server \

-p 5672:5672 -p 15672:15672 \

--name rabbitmq-server \

-e RABBITMQ_DEFAULT_USER=username -e

RABBITMQ_DEFAULT_PASS=password \

rabbitmq:management

Docker – Start RabbitMQ

9/30/16 12

CLICK TO EDIT MASTER TITLE STYLE

Security Classification: InternalSecurity Classification: Internal

SenecaJS Philosophy

• Pattern Matching: instead of fragile service discovery, you just let the world know what sort of messages you are about.

• Transport Independence: you can send messages between services in many ways, all hidden from your business logic.

9/30/16 13

CLICK TO EDIT MASTER TITLE STYLE

Security Classification: InternalSecurity Classification: Internal

SenecaJS – Your first microservicelet seneca = require('seneca')()

seneca.add('service:math,cmd:sum', (msg, reply) => { reply(null, { answer: (msg.left + msg.right) }) })

seneca.act({ service: 'math', cmd: 'sum', left: 1, right: 2 }, (err, result) => {

if (err) return console.error(err) console.log(result) })

9/30/16 14

CLICK TO EDIT MASTER TITLE STYLE

Security Classification: InternalSecurity Classification: Internal

SenecaJS – Pattern Matchingseneca.add('service:math,cmd:sum', (msg, reply) => { reply(null, { answer: (msg.left + msg.right) }) })

Can this service return the result as an integer only whenever I need?

9/30/16 15

CLICK TO EDIT MASTER TITLE STYLE

Security Classification: InternalSecurity Classification: Internal

SenecaJS – Pattern Matching - 2

seneca.add(‘service:math,cmd:sum’, function (msg, reply) { if (msg.integer === true){ reply(null, { answer: (parseInt(msg.left) + parseInt(msg.right)) }) } else{ reply(null, { answer: (msg.left + msg.right) }) }})

9/30/16 16

CLICK TO EDIT MASTER TITLE STYLE

Security Classification: InternalSecurity Classification: Internal

SenecaJS – Pattern Matching - 3seneca.add('service:math,cmd:sum', (msg, reply) => { reply(null, { answer: (msg.left + msg.right) }) })

seneca.add('service:math,cmd:sum,integer:true', (msg, reply) => { reply(null, {

answer: ( parseInt(msg.left) + parseInt(msg.right)

) })

})

9/30/16 17

CLICK TO EDIT MASTER TITLE STYLE

Security Classification: InternalSecurity Classification: Internal

SenecaJS – Pattern Matching - Recap• Matches against top level properties of JSON message• Patterns are unique• Specialised patterns win over generic patterns• Competing patterns win based on value

9/30/16 18

CLICK TO EDIT MASTER TITLE STYLE

Security Classification: InternalSecurity Classification: Internal

SenecaJS – Transport

• Seneca can work with multiple transports

• Available transports: RabbitMQ, Kafka, Redis, BeansTalk, mqp, Mesh, SQS, NSQ, ZeroMQ, NATS, Azure Service Bus, NServiceBus, Aliyun-MNS, Google Cloud PubSub

• HTTP/TCP is supported by default

9/30/16 19

CLICK TO EDIT MASTER TITLE STYLE

Security Classification: InternalSecurity Classification: Internal

SenecaJS with AMQP Transport

• seneca-amqp-transporthttps://github.com/seneca-contrib/seneca-amqp-transport• It is a plugin to allow seneca listeners and clients to communicate

over AMQP• Currently support AMQP 0.9.1• For AMQP 1.0, please use seneca-servicebus-transport

9/30/16 20

CLICK TO EDIT MASTER TITLE STYLE

Security Classification: InternalSecurity Classification: Internal

SenecaJS with AMQP Transport – Serverlet seneca = require('seneca')() .use('seneca-amqp-transport') .add('service:myService,cmd:create', function (args, done) { console.log(`From client ${args.clientId}: ${args.i}`); done(null, { i: args.i }) }) .listen({ type: 'amqp', pin: 'service:myService', url: 'amqp://username:password@rabbitmq-server:5672' })

9/30/16 21

CLICK TO EDIT MASTER TITLE STYLE

Security Classification: InternalSecurity Classification: Internal

SenecaJS with AMQP Transport – Clientlet clientId = 1let args = process.argv.slice(2)if (args.length > 0) {

clientId = args[0]}

let client = require('seneca')().use('seneca-amqp-transport').client({type: 'amqp',pin: 'service:myService',url: 'amqp://username:password@rabbitmq-server:5672'

})let i = 0setInterval(function() {

client.act(`service:myService,cmd:create,clientId:${clientId},i:${i}`,function(err, ret) {

console.log('Client: received i = ' + ret.i);});

i++;}, 100)

9/30/16 22

CLICK TO EDIT MASTER TITLE STYLE

Security Classification: InternalSecurity Classification: Internal

SenecaJS with AMQP Transport – How it works Consumer Queue

Queue

myServiceclient

Requestreply_to = my_client_id

correlation_id = abc

Reply

correlation_id = abcQueue

Client Queue

Routingpin = service:myService

Routingpin = my_client_id

9/30/16 23

CLICK TO EDIT MASTER TITLE STYLE

Security Classification: Internal

DEMO

9/30/16 24

CLICK TO EDIT MASTER TITLE STYLE

Security Classification: Internal

TEA-BREAK

9/30/16 25

CLICK TO EDIT MASTER TITLE STYLE

Security Classification: InternalSecurity Classification: Internal

PM2

• Advanced process manager for production Node.js applications. Load balancer, logs facility, startup script, micro service management, at a glance.

• We can use pm2 to start our services with scalepm2 start config-file.jsonpm2 start your-app.jspm2 scale app-name instance-number

9/30/16 26

CLICK TO EDIT MASTER TITLE STYLE

Security Classification: InternalSecurity Classification: Internal

PM2 - Sample JSON configuration

File start-service.json{

apps: [{

name: "myService",script: "index.js",watch: false,env: {

"NODE_ENV": "development"},instances: 1

}]

}

9/30/16 27

CLICK TO EDIT MASTER TITLE STYLE

Security Classification: InternalSecurity Classification: Internal

Docker – Run your service in multiple containerexport pwd=`pwd`docker run -d --link=rabbitmq-server -v "$pwd":/app \ mhart/alpine-node:latest node /app/server.js

docker run -d --link=rabbitmq-server -v "$pwd":/app \ mhart/alpine-node:latest node /app/client.js 1

docker run -d --link=rabbitmq-server -v "$pwd":/app \ mhart/alpine-node:latest node /app/client.js 2

9/30/16 28

CLICK TO EDIT MASTER TITLE STYLE

Security Classification: InternalSecurity Classification: Internal

Configuring your service

• How can we protect our configuration for production ENV?• How can we monitor our services’s heath?

References:• Health - Consul

https://www.consul.io/docs/agent/http/health.html

• Key / Value store - Consulhttps://www.consul.io/docs/agent/http/kv.html

9/30/16 29

CLICK TO EDIT MASTER TITLE STYLE

Security Classification: InternalSecurity Classification: Internal

JWT for Authentication

• JWT stands for Json Web Token• No more cookies.• JWT has 3 parts: header.body.signature

Example: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzY290Y2guaW8iLCJleHAiOjEzMDA4MTkzODAsIm5hbWUiOiJDaHJpcyBTZXZpbGxlamEiLCJhZG1pbiI6dHJ1ZX0.03f329983b86f7d9a9f5fef85305880101d5e302afafa20154d094b229f75

• JWT helps to verify the sender, authorize the request, prevent man in middle and good with CORS.

9/30/16 30

CLICK TO EDIT MASTER TITLE STYLE

Security Classification: InternalSecurity Classification: Internal

Introducing servicebase package

https://www.npmjs.com/package/servicebase

Features :• Listener / Client mode, with AMQP Transport or HTTP Transport• Promisify all functions• Use Consul as Configuration Storage & Service Health Checker• Support multiple database adapters. Postgresql & Sqlite are build-in supported adapters• Use Loggly as logs monitoring service• Support Authorization when consuming the service’s action• Error handler: no more terminating your service because of TIMEOUT or fatal$ error• Including test helper• Including typed-definitions file

9/30/16 31

CLICK TO EDIT MASTER TITLE STYLE

Security Classification: Internal

DEMO

9/30/16 32

CLICK TO EDIT MASTER TITLE STYLE

Security Classification: InternalSecurity Classification: Internal

Testing your services

• Use sqlite in-memory for integration test• For unit-test: test your logic-class instead of test the function you

registered with seneca• For integration-test with other services: use pm2 & rabbitmq

9/30/16 33

CLICK TO EDIT MASTER TITLE STYLE

Security Classification: InternalSecurity Classification: Internal

Microservices are the kind of SOA. Microservices must be independently deployable, whereas SOA services are often implemented in deployment monoliths. Classic SOA is more platform driven, so microservices offer more choices in all dimensions.

Torsten Winterberg (Oracle ACE Director)

Microservices vs SOA

9/30/16 34

CLICK TO EDIT MASTER TITLE STYLE

Security Classification: Internal

Q&AThank you very much

9/30/16 35

CLICK TO EDIT MASTER TITLE STYLE

Security Classification: InternalSecurity Classification: Internal

Stateful / Stateless & Authorization

• Stateful means that there is memory of the past. Previous transactions are remembered and may affect the current transaction.

• Stateless means there is no memory of the past. Every transaction is performed as if it were being done for the very first time.

• In Stateless service, we use JWT (Json Web Token) for Authentication. No more Cookies.

• Authorization will be done by each service regarding to the authenticated user.