Download - Nodejs in Production
NodeJS in Production
William BrunoDesenvolvedor NodeJS
http://wbruno.com.br/ http://github.com/wbruno [email protected] @wbrunom
use istanbul use jshint
relatório de cobertura dos seus testes análise estática de código, check de sintaxe
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
use clusterif (cluster.isMaster) { for (let i = 0; i < numCPUs; i++) { let worker = cluster.fork(); worker.on('error', _onWorkerError); } } else { //… }
use Objetos Literaislet AccountController = { login: function doLogin(request, response, next) { //.. } };
module.exports = AccountController;
require() é síncrono, cacheado e singleton
use gzipapp.use(compression());
não use módulos desnecessárioshelmet
lodash/undescore
app.disable('etag'); app.disable('x-powered-by');
outros cabeçalhos no nginx
use programação funcional[].filter(); [].map(); [].some(); [].every(); [].find(); [].reduce(); Monads, clousures, currying, HOF, avoid side-effects, etc
use es6Nativa desde o NodeJS 4.0
Esqueça Babel
'use strict'; let express = require('express');
use mozilla/nunjucksÓtimo template engine
Mantido pela Fundação Mozilla
nomeie seus middlewaresapp.get('/', function getHome(request, response, next) { response.send('Home'); });
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 }); } });
use debugNão deixe console.log() perdidos no código
Tudo o que vai para o std output escreve no log
escreva logwinston [splunk, graylog]
quem, quando, o quê
use newrelicSERVER
APMBROWSER
use a lib bluebirdMais rápida que a implementação nativa de Promise
Possui o método .promisifyAll()
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" },
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
use forever para prod e nodemon para dev
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
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
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
use o nginx-fullÓtimo web server
Ultra rápido Assíncrono, não bloqueante
Super configurável http2 (server push apenas no plus)
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; }
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; }
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
Obrigado