Building Microservices using Hydra

Building Microservices using Hydra

A hands-on workshop for building Hydra based Node microservices. First presented at the NYC JavaScript @ FlatIron meetup. https://www.meetup.com/NYC-JavaScript-Flatiron/events/235932229/

E2e942d05d5ea93ad2eddd3394ffcd96?s=128

Carlos Justiniano

December 14, 2016
Tweet

Transcript

  1. Building Microservices using Hydra A hands-on workshop @cjus (twitter /

    github) https://goo.gl/GzJ1JP
  2. 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!
  3. Code examples at: https://goo.gl/AVW0lG

  4. 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
  5. Monolithic vs Microservice

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

  7. 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
  8. 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
  9. Who builds microservices? • Amazon, Comcast, eBay, IBM, Google, Groupon,

    Microsoft, Netflix, Paypal, SoundCloud, Uber • … and lots of other companies
  10. 1 2 3 4 5 6 7 8 9 10

    *
  11. $ mkdir express-test $ cd express-test $ npm init {

    name app: index } $ npm install express ——save
  12. $ 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
  13. $ node index.js View in web browser: http://localhost:3000/

  14. 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
  15. 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
  16. The hydra project consist of: hydra-core, hydra-express and hydra-router In

    this workshop we’ll focus on Hydra Express
  17. None
  18. Hydra has a single infrastructure dependency

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

  20. Let’s upgrade our basic express app using hydra-express $ npm

    install fwsp-hydra-express ——save
  21. $ 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
  22. $ 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
  23. $ node index.js View in web browser: http://localhost:3000/

  24. None
  25. $ sudo npm install -g hydra-cli $ hydra-cli config redisUrl:

    172.16.0.2 redisPort: 6379 redisDb: 15
  26. $ 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
  27. $ hydra-cli nodes $ hydra-cli routes $ hydra-cli health hello

  28. $ hydra-cli rest hello:[get]/

  29. $ 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
  30. $ 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
  31. $ hydra-cli rest hello:[get]/ $ hydra-cli rest hello:[get]/ $ hydra-cli

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

    rest hello:[get]/ { Load balanced! }
  33. $ hydra-cli nodes $ hydra-cli rest 45dc1730a9ec92fea6c9c0e0e7d52681@hello:[get]/

  34. 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
  35. Improved routes

  36. $ 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
  37. $ node index.js $ hydra-cli nodes $ hydra-cli rest hello:[get]/v1/hello

  38. Building more complex services

  39. $ sudo npm install -g yo generator-fwsp-hydra $ yo fwsp-hydra

    { name it “hello” }
  40. $ 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
  41. $ 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 } } }
  42. $ vi config/config.json "redis": {
 "url": "127.0.0.1",
 "port": 6379,
 "db":

    15
 } Update to 172.16.0.2
  43. // In routes/hello-v1-routes.js // … res.sendOk({ msg: `hello from ${hydra.getServiceName()}

    - ${hydra.getInstanceID()}` });
  44. $ cd hello-service $ npm install $ node hello-service or

    $ npm start
  45. $ npm start > hello-service@0.0.1 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 }
  46. $ hydra-cli nodes $ hydra-cli routes $ hydra-cli rest hello:[get]/v1/hello

  47. Inter-service Communication

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

    }
  49. $ 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
  50. 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' } }
  51. Recap

  52. ExpressJS apps are fairly easy to build

  53. Hydra-Express adds just a bit more code!

  54. And we get a great deal for that extra code

  55. We saw that even a basic hydraExpress app emits health

    and presence information
  56. We saw that our routes are discoverable

  57. And automatically load-balanced!

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

  59. The hydra generator tool allowed us to quickly build microservice

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

  61. 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