29
NodeJS in Production

Nodejs in Production

Embed Size (px)

Citation preview

Page 1: Nodejs in Production

NodeJS in Production

Page 2: Nodejs in Production

William BrunoDesenvolvedor NodeJS

http://wbruno.com.br/ http://github.com/wbruno [email protected] @wbrunom

Page 3: Nodejs in Production

use istanbul use jshint

relatório de cobertura dos seus testes análise estática de código, check de sintaxe

Page 4: Nodejs in Production

seja rápidoSeja extremamente rápido, quanto menos tempo de NodeJS sua

aplicação tiver, mais ela irá escalar. Assíncrono

Single Thread V8 usa no máximo 1.6GB de RAM por processo

Consome pouca RAM e pouca CPU

Page 5: Nodejs in Production

use clusterif (cluster.isMaster) { for (let i = 0; i < numCPUs; i++) { let worker = cluster.fork(); worker.on('error', _onWorkerError); } } else { //… }

Page 6: Nodejs in Production

use Objetos Literaislet AccountController = { login: function doLogin(request, response, next) { //.. } };

module.exports = AccountController;

require() é síncrono, cacheado e singleton

Page 7: Nodejs in Production

use gzipapp.use(compression());

Page 8: Nodejs in Production

não use módulos desnecessárioshelmet

lodash/undescore

app.disable('etag'); app.disable('x-powered-by');

outros cabeçalhos no nginx

Page 9: Nodejs in Production

use programação funcional[].filter(); [].map(); [].some(); [].every(); [].find(); [].reduce(); Monads, clousures, currying, HOF, avoid side-effects, etc

Page 10: Nodejs in Production

use es6Nativa desde o NodeJS 4.0

Esqueça Babel

'use strict'; let express = require('express');

Page 11: Nodejs in Production

use mozilla/nunjucksÓtimo template engine

Mantido pela Fundação Mozilla

Page 12: Nodejs in Production

nomeie seus middlewaresapp.get('/', function getHome(request, response, next) { response.send('Home'); });

Page 13: Nodejs in Production

erros num único pontoTrate os erros num único lugar

app.use(function handleError(err, request, response, next) { response.status(err.status || 500);

//log if (request.xhr) { response.json({ err: err.message }); } else { response.render('error', { message: err.message }); } });

Page 14: Nodejs in Production

use debugNão deixe console.log() perdidos no código

Tudo o que vai para o std output escreve no log

Page 15: Nodejs in Production

escreva logwinston [splunk, graylog]

quem, quando, o quê

Page 16: Nodejs in Production

use newrelicSERVER

APMBROWSER

Page 17: Nodejs in Production

use a lib bluebirdMais rápida que a implementação nativa de Promise

Possui o método .promisifyAll()

Page 18: Nodejs in Production

use npm scripts{ "name": "app", "scripts": { "gulp": "gulp; ./scripts.sh akamai; gulp s3", "jshint": "jshint server/*", "karma": "./scripts.sh karma", "nodemon": "nodemon ./server/bin/www", "patch": "npm version patch -m \"release: version %s\" && git push --tags && git push", "start": "./scripts.sh start", "test": "./scripts.sh test" },

Page 19: Nodejs in Production

use npm scripts#!/bin/bash

BROWSER=${2:-"PhantomJS"}

case "$1" in start) echo 'Starting...' export DEBUG=blz:* bower install npm-run-all --parallel gulp-watch karma ;; test) echo 'Testing backend...' gulp eslint:nodejs export DEBUG=blz:* ./node_modules/istanbul/lib/cli.js cover ./node_modules/mocha/bin/_mocha test/nodejs/* ;; karma) echo 'Testing frontend...' gulp eslint:angular gulp eslint:jquery ./node_modules/karma/bin/karma start --browsers $BROWSER ./test/angular/karma.conf.js ;; akamai) echo 'Updating akamai...' export APPLICATION_VERSION=$(node -e "console.log(require('./package.json').version);") mkdir -p _akamai/$APPLICATION_VERSION cp -r dist/public/* _akamai/$APPLICATION_VERSION

chmod 400 akamai.key scp -i akamai.key -o StrictHostKeyChecking=no -rp _akamai/$APPLICATION_VERSION user@..…upload.akamai.com:/dir/ ;; *) echo "Usage: {start|akamai|test|karma}" exit 1 ;; esac

Page 20: Nodejs in Production

use forever para prod e nodemon para dev

Page 21: Nodejs in Production

use /etc/init.d/nodejs ou /etc/init/nodejs

Unix Service ou Ubuntu upstart

https://github.com/wbruno/examples/tree/gh-pages/nodejs-in-production

Page 22: Nodejs in Production

https://github.com/wbruno/examples/tree/gh-pages/nodejs-in-production

#!/bin/sh

### BEGIN INIT INFO # Provides: nodejs init script # Required-Start: forever node module # X-Interactive: true # Short-Description: application initscript # Description: Uses forever module to running the application ### END INIT INFO

NODE_ENV="{{ enviroment }}" PORT="3002" APP_DIR="/var/{{ application }}/dist/server" NODE_APP="bin/www" CONFIG_DIR="$APP_DIR/config" LOG_DIR="/var/log/{{ application }}" LOG_FILE="$LOG_DIR/app.log" NODE_EXEC="forever"

###############

USAGE="Usage: $0 {start|stop|restart|status}"

start_app() { mkdir -p "$LOG_DIR"

echo "Starting node app ..." PORT="$PORT" NODE_ENV="$NODE_ENV" NODE_CONFIG_DIR="$CONFIG_DIR" forever start "$APP_DIR/$NODE_APP" 1>"$LOG_FILE" 2>&1 & } stop_app() { forever stop "$APP_DIR/$NODE_APP" } status_app() { forever list } restart_app() { forever restart "$APP_DIR/$NODE_APP" }

case "$1" in start) start_app ;; stop) stop_app ;; restart) restart_app ;; status) status_app ;; *) echo $USAGE exit 1 ;; esac

Unix service

Page 23: Nodejs in Production

https://github.com/wbruno/examples/tree/gh-pages/nodejs-in-production

start on filesystem and started networking stop on shutdown

expect fork

setuid www-data env HOME="/var/{{ application }}"

env NODE_ENV="{{ enviroment }}" env MIN_UPTIME="5000" env SPIN_SLEEP_TIME="2000"

chdir /var/{{ application }}/dist/server env APP_EXEC="bin/www"

script exec forever -a -l $HOME/forever.log --minUptime=$MIN_UPTIME --spinSleepTime=$SPIN_SLEEP_TIME start $APP_EXEC end script

pre-stop script exec forever stopall end script

Ubuntu upstart

Page 24: Nodejs in Production

use o nginx-fullÓtimo web server

Ultra rápido Assíncrono, não bloqueante

Super configurável http2 (server push apenas no plus)

Page 25: Nodejs in Production

https://github.com/wbruno/examples/tree/gh-pages/nodejs-in-production

server { listen 80; server_name www.{{ domain }}; access_log /var/{{ application }}/www.{{ domain }}-access.log; error_log /var/{{ application }}/www.{{ domain }}-error.log;

proxy_cache one;

root /var/{{ application }}/dist/public/;

error_page 400 404 414 500 502 503 504 /50x.html;

location /50x.html { internal; }

location /api { proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $host; proxy_pass http://nodejs/api; }

location ~* \.(?:ico|css|html|json|js|gif|jpe?g|png|ttf|woff|woff2|svg|eot|txt)$ { access_log off; expires 14d; add_header Pragma public; add_header Cache-Control "public, mustrevalidate, proxy-revalidate"; root /var/{{ application }}/dist/public; }

}

location / { add_header X-Cache-Status $upstream_cache_status; add_header Strict-Transport-Security "max-age=1440; includeSubdomains";

expires 60s;

set $mobile ‘@desktop'; if ($http_user_agent ~* "...") { set $mobile "@tablet"; } if ($http_user_agent ~* "...") { set $mobile "@smartphone"; } proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $host;

proxy_ignore_headers Cache-Control;

proxy_pass http://nodejs;

proxy_cache_key "$mobile$scheme://$host$request_uri"; proxy_cache_bypass $cookie_nocache $arg_nocache;

proxy_cache_valid 1m; proxy_cache_min_uses 1; }

Page 26: Nodejs in Production

https://github.com/wbruno/examples/tree/gh-pages/nodejs-in-production

http { sendfile on;

tcp_nopush on; tcp_nodelay on;

keepalive_timeout 60; send_timeout 60;

client_body_timeout 60; client_header_timeout 60; client_body_buffer_size 10K; client_header_buffer_size 1k; client_max_body_size 8m;

large_client_header_buffers 4 32k; types_hash_max_size 2048;

server_tokens off; server_names_hash_bucket_size 64;

default_type application/octet-stream; log_format elb '$http_x_forwarded_for - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent"'; access_log /var/log/nginx/access.log; error_log /var/log/nginx/error.log;

proxy_cache_path /tmp/cache keys_zone=one:10m loader_threshold=100 loader_files=100 loader_sleep=30 inactive=30m max_size=2g;

charset utf-8;

gzip on; gzip_disable "msie6"; gzip_min_length 1; gzip_types *;

gzip_http_version 1.1; gzip_vary on; gzip_comp_level 6; gzip_proxied any; gzip_buffers 16 8k;

include /etc/nginx/mime.types; include /etc/nginx/conf.d/*.conf; include /etc/nginx/sites-enabled/*; include /etc/nginx/upstreams.d/nodejs; }

user www-data; worker_processes auto; pid /run/nginx.pid;

events { worker_connections 1024; multi_accept on; use epoll; }

Page 27: Nodejs in Production

Bibliografiahttps://promisesaplus.com https://blog.risingstack.com/node-js-best-practices/ https://www.sitepoint.com/10-tips-make-node-js-web-app-faster/ http://expressjs.com/en/advanced/best-practice-performance.html https://www.packtpub.com/books/content/fine-tune-nginx-configufine-tune-nginx-configurationfine-tune-nginx-configurationratio https://www.nginx.com/blog/nginx-caching-guide/

https://github.com/wbruno/examples/tree/gh-pages/nodejs-in-production

Page 28: Nodejs in Production

Obrigado

Page 29: Nodejs in Production