Real World Lessons on the Pain Points of Node.JS Application

Preview:

Citation preview

Real World Lessons on the Pain Points of Node.js Applications

@Ben_HallBen@BenHall.me.ukOcelotUproar.com / Katacoda.com

@Ben_Hall / Blog.BenHall.me.ukOcelot Uproar

WH

O AM

I?

Learn via Interactive Browser-Based LabsKatacoda.com

Agenda

• Creating strong foundation– Node v6/v7, NPM, Security

• Error Handling• Async / Promises• Deploying / Scaling• Performance• Debugging

Provide an overview of our node.js experiences

and the tasks we wish we did earlier!

Strong Foundations

Upgrading from Node v0.10.38 to v6.1.0

#nodestats for March: Node 6.x hits 48% share, Node 7.x breaks 15%, 0.10 and 0.12 drop below 10% share for the first time:

https://mobile.twitter.com/i/web/status/838922927735132160

Previous Node Versioning

• Even === Stable– 0.10, 0.12, 4, 6

• Odd === Beta– 0.9, 0.11, 5

Node Release Stages

• CURRENT: new features (and bug fixes and security patches)

• ACTIVE LTS: bug fixes (and security patches)• MAINTENANCE: only security patches

Docker to test deployment

• Didn’t need to install anything on host

> docker run -it -v $(pwd):/src -p 3000 node:6 root@container:> npm install root@container:> npm start

Default to Underscore.js ?

Fixing NPM

Lock down NPM dependencies because no-one respects SemVer

AngularJs 1.2 => 1.3"dependencies": { "angular": "^1.2.16”}

Angular 1.2 => 1.3> angular.element(document)[#document]

> angular.element(document)TypeError: undefined is not a function

Lock Down Dependencies

Randomly breaking builds and deployments will occur otherwise

$ npm shrinkwrap

Lock down dependencies to what’s running locally

Hard code versions in package.json

"dependencies": { "angular": “1.2.23”}

$ npm outdated

.npmrc

• https://docs.npmjs.com/misc/config

> cat .npmrcsave=truesave-exact=true

npm install -g

Replaced Glup, Grunt with Make

templates:handlebars views/templates/*.hbs -f

public/js/templates.js

> make templates

Security

Child Process Execchild_process.exec(req.query.url, function (err, data) { console.log(data);});

https://localhost:49155/api/openUrlInDefaultBrowser?url=c:/windows/system32/calc.exe

Thanks TrendMicro Antivirus on Windows!

https://code.google.com/p/google-security-research/issues/detail?id=693

Cross-Site Request Forgeryvar csrf = require('csurf');

var csrfProtection = csrf({ cookie: true }); var parseForm = bodyParser.urlencoded({ extended: false });

app.get('/form', csrfProtection, function(req, res) { res.render('send', { csrfToken: req.csrfToken() });});

app.post('/process', parseForm, csrfProtection, function(req, res) { res.send('data is being processed');});

https://blog.risingstack.com/node-js-security-checklist/

Rate Limitingvar ratelimit = require('koa-ratelimit');

var ipBasedRatelimit = ratelimit({ db: redis.createClient(), duration: 60000, max: 10, id: function (context) { return context.ip; }});

app.post('/login', ipBasedRatelimit, handleLogin);

https://blog.risingstack.com/node-js-security-checklist/

Security Audit NPM Packages> npm install nsp> nsp check(+) 18 vulnerabilities found

https://nodesecurity.io/

• Root Path Disclosure (2x)• Regular Expression Denial of Service (10x)• Incorrect Handling of Non-Boolean

Comparisons During Minification• Denial-of-Service Extended Event Loop Blocking• Denial-of-Service Memory Exhaustion• Symlink Arbitrary File Overwrite• Remote Memory Disclosure (2x)

https://blog.acolyer.org/2017/03/07/thou-shalt-not-depend-on-me-analysing-the-use-of-outdated-javascript-libraries-on-the-web/

Create Strong Foundations

Error Handling

Wasn’t great from the start

Try {} Catch {}

Try {} Catch {}

Domains haven’t really worked

https://raw.githubusercontent.com/strongloop/zone/master/showcase/curl/curl-zone.js

Zones? No. Not really

Returning String as Error

Strongly typed errors

Async Flow Control

Promises

Promises… Promises… Never break your promises.

Personally, I never make promises.

http://domenic.me/2012/10/14/youre-missing-the-point-of-promises/

Callbacks

So good it’s got it’s own website callbackhell.com

“The goal isn’t about removing levels of indentation but rather writing modular code that

is easy to reason about”

Strongloop Blog

http://strongloop.com/strongblog/node-js-callback-hell-promises-generators/

Loops + Async Callbacks

Loops + Async Callbacks

“You can't get into callback hell if you don't go there.”

Isaac Schlueter

Node 7 – Async Awaitclass Demo { async greeting() { const h = await this.world(); return h; } world() { return Promise.resolve('hello world'); }}

const retval = await demo.greeting();

Node 7 – Async Await Errorsasync getPersonFullNameWithTryCatch() { try { let response = await fetch('./data/person2.json'); } catch(e) { console.log('there was an error'); console.log(e); }}

DEPLOY!

Single Threaded

CPU Intensive?

Array Filtering / Sorting / Processing

Maybe not use Node?

Golang has a great community

Where Node was a few years ago?

Have more threads

Solved Problem?

var cluster = require('cluster');var http = require('http');var numCPUs = require('os').cpus().length;

if (cluster.isMaster) { // Fork workers. for (var i = 0; i < numCPUs; i++) { cluster.fork(); }

cluster.on('exit', function(worker, code, signal) { console.log('worker ' + worker.process.pid + ' died'); });} else { // Workers can share any TCP connection // In this case it is an HTTP server http.createServer(function(req, res) { res.writeHead(200); res.end("hello world\n"); }).listen(8000);}

> NODE_DEBUG=cluster node server.js23521,Master Worker 23524 online23521,Master Worker 23526 online23521,Master Worker 23523 online23521,Master Worker 23528 online

Deploying with Docker

Container

https://www.docker.com/whatisdocker/

Container

Deploying Node App via Docker> cat DockerfileFROM node:6-onbuildEXPOSE 3000

> docker build –t my-node-app .> docker run –p 3000:3000 my-node-app

59,040 environments/day/server

112,320 environments/day/server

> docker run -d \ -p 80:80 \ -v /var/run/docker.sock:/tmp/docker.sock:ro \ jwilder/nginx-proxy

> docker run --name web \ -e VIRTUAL_HOST=www.katacoda.com my-node-app

Load Balancer

Nginx Proxy

Node Node

Node Node

Node Node

Nginx Proxy

Node Node

Node Node

Node Node

Nginx Proxy

Node Node

Node Node

Node Node

Health Endpointsrouter.get('/_specialfunctions/_check', function(req, res) { async.parallel([ check_docker, check_starter, check_redis, check_pg ], function(err, results) { if(err) { console.log("Health check failed", err); res.status(500); return res.json({healthy: false, details: err}); }

res.json({healthy: true}); })});

var check_docker = function(cb) { docker.ping(function(err) { handle_error('docker', err, cb);});};

var check_redis = function(cb) { redis.status(function(err, connected) { if(err === null && connected === "ready") { cb(); } else { handle_error('redis', {msg: 'Not Connected', err: err}, cb); } })};

var check_pg = function(cb) { pg.status(function(err) { handle_error('postgres', err, cb);});};

Careful!

socket.io and global state

Sticky Sessions

Compiled Nginx + OSS Modules

Global State as a Service

Microservices FTW!!

Code Performance Still Matters

Performance

> npm install v8-profiler const profiler = require('v8-profiler')const fs = require('fs')var profilerRunning = false

function toggleProfiling () { if (profilerRunning) { const profile = profiler.stopProfiling() console.log('stopped profiling') profile.export() .pipe(fs.createWriteStream('./myapp-'+Date.now()+'.cpuprofile')) .once('error', profiler.deleteAllProfiles) .once('finish', profiler.deleteAllProfiles) profilerRunning = false return } profiler.startProfiling() profilerRunning = true console.log('started profiling')}

process.on('SIGUSR2', toggleProfiling)

> kill -SIGUSR2 <pid>

JetBrains WebStorm

OpenTracing - Zipkin

Prometheus + Grafana

Debugging

require(‘debug’);

Webstorm

VS Code

Profiling Node Applications

March 10, 2017 @ 09:00 Fontaine E

Real-Time Monitoring with Grafana, StatsD and InfluxDB

March 10, 2017 @ 15:00

Testing?!

Summary

• Upgrade to Node.js v6• Start looking at ES6 / Node 7• Security• Manage your errors• Forgot making promises• Scale using Docker

Thank you!@Ben_Hall

Ben@BenHall.me.ukwww.Katacoda.com

Recommended