Upload
ben-hall
View
96
Download
7
Embed Size (px)
Citation preview
Real World Lessons on the Pain Points of Node.js Applications
@[email protected] / 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)
NPM Credentials Leaks
• https://github.com/ChALkeR/notes/blob/master/Do-not-underestimate-credentials-leaks.md
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