Slide 1

Slide 1 text

Building Microservices using Hydra A hands-on workshop @cjus (twitter / github) https://goo.gl/GzJ1JP

Slide 2

Slide 2 text

Prereqs • Your favorite text editor or: https://atom.io/ • Your favorite terminal app or: iTerm2 / Hyper.js • NodeJS: https://nodejs.org
 * Requires Node 6.2.1 or greater • Lastly, if you’re cruising along - help the person sitting next to you!

Slide 3

Slide 3 text

Code examples at: https://goo.gl/AVW0lG

Slide 4

Slide 4 text

Microservices • Microservice: a process which is dedicated to doing a kind of thing really well • A distributed computing application - works across a network • Commonly implemented using ExpressJS and other lesser known frameworks

Slide 5

Slide 5 text

Monolithic vs Microservice

Slide 6

Slide 6 text

Monolithic Microservice “mono” - meaning one “micro” - meaning small

Slide 7

Slide 7 text

Monolithic • Pros: • easier to deploy • easier to test • Cons: • can become too large for anyone on the team to fully understand • can be fragile due to the fact that a single error can take down the entire system • can be difficult to modify as modules are tightly coupled • can be difficult to build using remote teams • often requires the same tech stack

Slide 8

Slide 8 text

Microservice • Pros: • collection of loosely connected services • easier / safer to modify • can be easy to deploy • can be easy to test since you’re focused on a particular set of functionality • can be built using different tech stacks • Cons: • can be difficult to test due to its distributed nature • routing endpoints can require more consideration • services may need to discover one another

Slide 9

Slide 9 text

Who builds microservices? • Amazon, Comcast, eBay, IBM, Google, Groupon, Microsoft, Netflix, Paypal, SoundCloud, Uber • … and lots of other companies

Slide 10

Slide 10 text

1 2 3 4 5 6 7 8 9 10 *

Slide 11

Slide 11 text

$ mkdir express-test $ cd express-test $ npm init { name app: index } $ npm install express ——save

Slide 12

Slide 12 text

$ vi index.js var express = require('express') var app = express() app.get('/', function (req, res) { res.send('Hello World!') }) app.listen(3000, function () { console.log('Example app listening on port 3000!') }) Cut & paste from: express-hello.js https://goo.gl/AVW0lG

Slide 13

Slide 13 text

$ node index.js View in web browser: http://localhost:3000/

Slide 14

Slide 14 text

What’s Hydra? • An NPM package that facilitates building distributed applications - such as microservices • It addresses distributed computing concerns so you won’t have to • Open Source project - released by Flywheel Sports • Related projects: hydra-express, hydra-router

Slide 15

Slide 15 text

Hydra features • Automated health and presence • Automated service discovery • Inter-service (P2P) communication with support for socket messaging and RESTful interfaces • Built-in load balancing and routing • Self registration with near zero configuration • Built-in job queues • Built on Node using native ES6 • Great with Docker

Slide 16

Slide 16 text

The hydra project consist of: hydra-core, hydra-express and hydra-router In this workshop we’ll focus on Hydra Express

Slide 17

Slide 17 text

No content

Slide 18

Slide 18 text

Hydra has a single infrastructure dependency

Slide 19

Slide 19 text

See our intro to Redis at: https://goo.gl/S11jdo

Slide 20

Slide 20 text

Let’s upgrade our basic express app using hydra-express $ npm install fwsp-hydra-express ——save

Slide 21

Slide 21 text

$ vi index.js var hydraExpress = require('fwsp-hydra-express'); var config = require('./config.json'); function onRegisterRoutes() { var express = hydraExpress.getExpress(); var api = express.Router(); api.get('/', function(req, res) { res.send('Hello World!'); }); hydraExpress.registerRoutes({ '': api }); } hydraExpress.init(config, onRegisterRoutes); Cut & paste hydra-express-hello.js from: https://goo.gl/AVW0lG

Slide 22

Slide 22 text

$ vi config.json { "hydra": { "serviceName": "hello", "serviceIP": "", "servicePort": 3000, "serviceType": "", "serviceDescription": "", "redis": { "url": "172.16.0.2", "port": 6379, "db": 15 } } } Cut & paste config.json from: https://goo.gl/AVW0lG

Slide 23

Slide 23 text

$ node index.js View in web browser: http://localhost:3000/

Slide 24

Slide 24 text

No content

Slide 25

Slide 25 text

$ sudo npm install -g hydra-cli $ hydra-cli config redisUrl: 172.16.0.2 redisPort: 6379 redisDb: 15

Slide 26

Slide 26 text

$ hydra-cli hydra-cli version 0.3.5 Usage: hydra-cli command [parameters] See docs at: https://github.com/flywheelsports/hydra-cli A command line interface for Hydra services Commands: help - this help list config - configure connection to redis config list - display current configuration health [serviceName] - display service health healthlog serviceName - display service health log message create - create a message object message send message.json - send a message nodes [serviceName] - display service instance nodes rest path [payload.json] - make an HTTP RESTful call to a service routes [serviceName] - display service API routes services [serviceName] - display list of services

Slide 27

Slide 27 text

$ hydra-cli nodes $ hydra-cli routes $ hydra-cli health hello

Slide 28

Slide 28 text

$ hydra-cli rest hello:[get]/

Slide 29

Slide 29 text

$ vi config.json { "hydra": { "serviceName": "hello", "serviceIP": "", "servicePort": 0, "serviceType": "", "serviceDescription": "", "redis": { "url": "172.16.0.2", "port": 6379, "db": 15 } } } Cut & paste config.json from: https://goo.gl/AVW0lG Change from 3000 to 0

Slide 30

Slide 30 text

$ vi index.js var hydraExpress = require('fwsp-hydra-express'); var hydra = hydraExpress.getHydra(); var config = require('./config.json'); function onRegisterRoutes() { var express = hydraExpress.getExpress(); var api = express.Router(); api.get('/', function(req, res) { res.send({ msg: `hello from ${hydra.getServiceName()} - ${hydra.getInstanceID()}` }); }); hydraExpress.registerRoutes({ '': api }); } hydraExpress.init(config, onRegisterRoutes); Cut & paste
 hydra-express-hello-id.js from: https://goo.gl/AVW0lG

Slide 31

Slide 31 text

$ hydra-cli rest hello:[get]/ $ hydra-cli rest hello:[get]/ $ hydra-cli nodes

Slide 32

Slide 32 text

$ hydra-cli rest hello:[get]/ $ hydra-cli rest hello:[get]/ $ hydra-cli rest hello:[get]/ { Load balanced! }

Slide 33

Slide 33 text

$ hydra-cli nodes $ hydra-cli rest 45dc1730a9ec92fea6c9c0e0e7d52681@hello:[get]/

Slide 34

Slide 34 text

var hydraExpress = require('fwsp-hydra-express'); var config = require('./config.json'); function onRegisterRoutes() { var express = hydraExpress.getExpress(); var api = express.Router(); api.get('/', function(req, res) { res.send('Hello World!'); }); hydraExpress.registerRoutes({ '': api }); } hydraExpress.init(config, onRegisterRoutes); var express = require('express') var app = express() app.get('/', function (req, res) { res.send('Hello World!') }) app.listen(3000, function () { console.log('Example app listening on port 3000!') }) Side by side comparison

Slide 35

Slide 35 text

Improved routes

Slide 36

Slide 36 text

$ vi index.js var hydraExpress = require('fwsp-hydra-express'); var hydra = hydraExpress.getHydra(); var config = require('./config.json'); function onRegisterRoutes() { var express = hydraExpress.getExpress(); var api = express.Router(); api.get('/hello', function(req, res) { res.send({ msg: `hello from ${hydra.getServiceName()} - ${hydra.getInstanceID()}` }); }); hydraExpress.registerRoutes({ '/v1': api }); } hydraExpress.init(config, onRegisterRoutes); Cut & paste
 hydra-express-hello-route.js from: https://goo.gl/AVW0lG

Slide 37

Slide 37 text

$ node index.js $ hydra-cli nodes $ hydra-cli rest hello:[get]/v1/hello

Slide 38

Slide 38 text

Building more complex services

Slide 39

Slide 39 text

$ sudo npm install -g yo generator-fwsp-hydra $ yo fwsp-hydra { name it “hello” }

Slide 40

Slide 40 text

$ tree hello-service hello-service !"" README.md !"" config # !"" config.json # $"" sample-config.json !"" package.json !"" hello-service.js !"" routes # $"" hello-v1-routes.js !"" scripts # $"" docker.js $"" specs !"" helpers # $"" chai.js $"" test.js 5 directories, 9 files

Slide 41

Slide 41 text

$ cd hello-service $ vi config/config.json { "appServiceName": "hello-service", "environment": "development", "hydra": { "serviceName": "hello-service", "serviceIP": "", "servicePort": 0, "serviceType": "hello", "serviceDescription": "", "redis": { "url": "127.0.0.1", "port": 6379, "db": 15 } } }

Slide 42

Slide 42 text

$ vi config/config.json "redis": {
 "url": "127.0.0.1",
 "port": 6379,
 "db": 15
 } Update to 172.16.0.2

Slide 43

Slide 43 text

// In routes/hello-v1-routes.js // … res.sendOk({ msg: `hello from ${hydra.getServiceName()} - ${hydra.getInstanceID()}` });

Slide 44

Slide 44 text

$ cd hello-service $ npm install $ node hello-service or $ npm start

Slide 45

Slide 45 text

$ npm start > [email protected] start /Users/cjustiniano/dev/hello-service > node hello-service.js INFO { event: 'info', message: 'Successfully reconnected to redis server' } INFO { event: 'start', message: 'hello-service (v.0.0.1) server listening on port 13664' } INFO { event: 'info', message: 'Using environment: development' } serviceInfo { serviceName: 'hello-service', serviceIP: '172.16.0.12', servicePort: 13664 }

Slide 46

Slide 46 text

$ hydra-cli nodes $ hydra-cli routes $ hydra-cli rest hello:[get]/v1/hello

Slide 47

Slide 47 text

Inter-service Communication

Slide 48

Slide 48 text

$ yo fwsp-hydra { Create a “blue” or “red” service }

Slide 49

Slide 49 text

$ vi {red/blue}-service.js hydraExpress.init(config.getObject(), version, () => { hydraExpress.registerRoutes({ '/v1/red': require('./routes/red-v1-routes') }); }) .then((serviceInfo) => { console.log('serviceInfo', serviceInfo); let hydra = hydraExpress.getHydra(); let message = hydra.createUMFMessage({ to: 'blue-service:[get]/v1/blue/', from: 'red-service:/', body: {} }); hydra.makeAPIRequest(message) .then((response) => { console.log('response', response); }); return 0; }) Cut & paste
 red-blue-service.js from: https://goo.gl/AVW0lG Edit “red” or “blue” words accordingly

Slide 50

Slide 50 text

INFO { event: 'info', message: 'Successfully reconnected to redis server' } INFO { event: 'start', message: 'red-service (v.0.0.1) server listening on port 13185' } INFO { event: 'info', message: 'Using environment: development' } serviceInfo { serviceName: 'red-service', serviceIP: '172.16.0.12', servicePort: 13185 } response { statusCode: 200, statusMessage: 'OK', statusDescription: 'Request succeeded without error', result: { msg: 'hello from blue-service - 088c270d30d36fdda37564de2cc68773' } }

Slide 51

Slide 51 text

Recap

Slide 52

Slide 52 text

ExpressJS apps are fairly easy to build

Slide 53

Slide 53 text

Hydra-Express adds just a bit more code!

Slide 54

Slide 54 text

And we get a great deal for that extra code

Slide 55

Slide 55 text

We saw that even a basic hydraExpress app emits health and presence information

Slide 56

Slide 56 text

We saw that our routes are discoverable

Slide 57

Slide 57 text

And automatically load-balanced!

Slide 58

Slide 58 text

Hydra-cli made it easy to communicate and test our services

Slide 59

Slide 59 text

The hydra generator tool allowed us to quickly build microservice projects

Slide 60

Slide 60 text

We saw inter-service communication using UMF messages and the hydra.makeAPIRequest

Slide 61

Slide 61 text

Resources! • Hydra project: https://github.com/flywheelsports • Hydra Intro: https://goo.gl/Ikcx4q • Getting Redis: https://goo.gl/S11jdo • Code used in this workshop: https://goo.gl/AVW0lG