SlideShare a Scribd company logo
1 of 71
Download to read offline
Node.js: serious business
PEDROFRANCESCHI
@pedroh96
pedro@pagar.me
github.com/pedrofranceschi
Assuntos
•

O problema

•

Por que e quando usar Node.js?

•

Problemas de Node.js

•

Node.js “the right way”

•

Repensando a infraestrutura

•

Deployment (Continuous Integration) e monitoramento

•

Conclusões…
O problema
“Montar um gateway de pagamentos
amigável para desenvolvedores e
empreendedores”
“A forma mais simples de receber
pagamentos online”
API RESTful

Node.js
C#

Ruby
Python

Dashboard
Angular.js

.NET
Java
PHP
Premissas da API
•

Simplicidade: RESTful + JSON

•

Ambiente de testes isolado e decente

•

Segurança sem comprometer simplicidade

•

Uptime de 99,9%

•

Escalabilidade
Por que Node.js?
Antes...
Node.js: serious business
Por que Node.js?
(Cielo, RedeCard, etc)

legítima

Sistema antifraude

ro

er
o/
ss
ce
su

m
s

10.000 ms

3.
00
0

Adquirente

fraude
erro

API RESTful

Request de transação
Por que Node.js?
(no nosso caso)

•

Requests externos demorados (>1.000ms)

•

I/O intenso em banco de dados

•

Totalmente assíncrono, single thread e event-based

•

Pouco processamento (sem blocking de CPU)
Por que Node.js?
(no nosso caso)

“Mas é só usar threads em qualquer
linguagem!..”

Não.
Por que Node.js?
(no nosso caso)

1.000 requests por segundo com conexão a uma API
externa + I/O no DB = 1.000 threads por segundo
… se cada request leva em média 10 segundos …
Em 9 segundos, teremos 9.000 threads
Isso escala? :P :P :P
Por que Node.js?
(no nosso caso)

Agora, em Node.js…
Por que Node.js?
(no nosso caso)

1.000 requests por segundo com conexão a uma API
externa + I/O no DB = 1 thread
… se cada request leva em média 10 segundos …
Em 9 segundos, teremos 1 thread
Isso escala? Sim.
#eventloopFTW
I/O síncrona
I/O
retorno

I/O
retorno

I/O
retorno

Aplicação

I/O bloqueante
(aplicação travada)

I/O bloqueante
(aplicação travada)

Sistema operacional

I/O bloqueante
(aplicação travada)
I/O “assíncrona” com threads
I/O
callback

I/O
callback

I/O
callback

Aplicação
Thread

Thread

Thread

I/O bloqueante
(thread travada)

I/O bloqueante
(thread travada)

I/O bloqueante
(thread travada)

Sistema operacional
O segredo do Node.js
I/O

I/O

callback
callback
callback

I/O

JavaScript (event loop)
V8
libuv
Sistema operacional
……………………………………
……………………………………
……………………………………
operações assíncronas em nível de OS
Node.js escala em I/O bloqueante, não
em utilização de CPU
(threads são boas em processamento paralelo)
Se I/O bloqueante não for um problema,
Node.js não tem tantas vantagens.
Node.js: serious business
Problemas de Node.js
Problemas de Node.js
Código assíncrono (race conditions, callback hell,
testes assíncronos, etc)
db.query("SELECT a FROM users WHERE ...;", function (err, result1) {
db.query("SELECT b FROM users WHERE ...;", function (err, result2) {
db.query("SELECT c FROM users WHERE ...;", function (err, result3) {
db.query("SELECT d FROM users WHERE ...;", function (err, result4) {
db.query("SELECT e FROM users WHERE ...;", function (err, result5) {
console.log("Finished.");
});
});
});
});
});
Um ótimo exemplo do que não fazer: callback hell.
Problemas de Node.js
Problemas de Javascript: bizarrices e facilidade em não
seguir padrões e orientação a objetos.
> 0.1+0.2
0.30000000000000004

!

> typeof NaN
'number'

!

> NaN === NaN
false

Cortesia do wtfjs.com
Problemas de Node.js
Exceptions não tratadas matam o processo.
var name = “Pedro Franceschi";

!

console.log("Tamanho do primeiro nome: " + name.split(" ")[0].length);
console.log("Tamanho do segundo nome: " + name.split(" ")[1].length);

$ node test.js
Tamanho do primeiro nome: 5
Tamanho do segundo nome: 10
Problemas de Node.js
Exceptions não tratadas matam o processo.
var name = “Pedro";

!

console.log("Tamanho do primeiro nome: " + name.split(" ")[0].length);
console.log("Tamanho do segundo nome: " + name.split(" ")[1].length);

$ node test.js
Tamanho do primeiro nome: 5

!

/private/tmp/test.js:4
console.log("Tamanho do segundo nome: " + name.split(" ")[1].length);
^
TypeError: Cannot read property 'length' of undefined
at Object.<anonymous> (/private/tmp/test.js:4:61)
at Module._compile (module.js:456:26)
at Object.Module._extensions..js (module.js:474:10)
at Module.load (module.js:356:32)
at Function.Module._load (module.js:312:12)
at Function.Module.runMain (module.js:497:10)
at startup (node.js:119:16)
at node.js:901:3
Problemas de Node.js
•

Single thread (escalar horizontalmente e
verticalmente com múltiplas instâncias)

•

Leaks de memória difíceis de detectar devido a
código mal feito (variáveis globalizadas, closures, etc)

•

Programadores front-end mexendo em back-end
(“é tudo Javascript!!”)

•

Existe a 4 anos, porém ainda é beta (v0.10.22)
Node.js “the right way”
Node.js “the right way”
Modules

var PI = Math.PI;

!

exports.area = function (r) {
return PI * r * r;
};

!

exports.circumference = function (r) {
return 2 * PI * r;
};

circle.js

var circle = require('./circle.js');

!

console.log( 'The area of a circle of radius 4 is ' + circle.area(4));

main.js
Node.js “the right way”
Evitar callback hells com async
(https://github.com/caolan/async)

db.query("SELECT a FROM users WHERE ...;", function (err, result1) {
db.query("SELECT b FROM users WHERE ...;", function (err, result2) {
db.query("SELECT c FROM users WHERE ...;", function (err, result3) {
db.query("SELECT d FROM users WHERE ...;", function (err, result4) {
db.query("SELECT e FROM users WHERE ...;", function (err, result5) {
console.log("Finished.");
});
});
});
});
});

Não tente fazer isso em casa
Node.js “the right way”
Evitar callback hells com async
(https://github.com/caolan/async)
async.parallel({
result1: function(callback) {
db.query("SELECT a FROM users WHERE ...;", function(err, result1){
callback(err, result1);
});
},
result2: function(callback) {
db.query("SELECT b FROM users WHERE ...;", function(err, result2){
callback(err, result2);
});
},
result3: function(callback) {
db.query("SELECT c FROM users WHERE ...;", function(err, result3){
callback(err, result3);
});
}
}, function(err, results){
console.log("Finished.");
})

Assim é bem melhor :)
Node.js “the right way”
Testes (JavaScript quebra)
(https://github.com/visionmedia/mocha e https://github.com/visionmedia/should.js/)

describe('Array', function(){
describe('#indexOf()', function(){
it('should return -1 when the value is not present', function(){
[1,2,3].indexOf(5).should.equal(-1);
})
})

!

!

describe(‘#indexOf() after one second', function(){
before(function(done){
setTimeout(function(){
done();
}, 1000);
});
it('should return -1 when the value is not present', function(){
[1,2,3].indexOf(5).should.equal(-1);
})
})

});
Node.js “the right way”

•

Seguir e manter um code style (dica: Google
JavaScript Style Guide)

•

Tratamento de erros consistente (processos morrem)
Node.js “the right way”
utils

•

Express.js: lightweight HTTP framework

•

Sequelize: ORM de MySQL, PostgreSQL, sqlite3, etc.

•

Mongoose: ORM de MongoDB

•

Commander: wrapper de command line

•

Vim: melhor editor de texto :P
“Inovação” em padrões de código
não é inovação.
(99,9% das vezes)
“Follow the patterns”
Repensando a infraestrutura
Use o melhor de cada banco de dados.
Infraestrutura do Pagar.me
MySQL

MongoDB

MySQL

(transações e dados relacionais)

(dados de clientes e não relacionais)

(transações e dados relacionais)

ElasticSearch

ElasticSearch

Servidor da API

Servidor da API

(Node.js)

(Node.js)

Router
Ambiente de produção

Ambiente de testes
(sandbox dos clientes)

api.pagar.me
Por que tantos bancos?
•

Separar dados de teste (sandbox dos clientes) dos dados
de produção

•

MySQL: dados relacionais (transações, assinaturas,
planos, cartões, etc.)

•

MongoDB: dados não-relacionais (informações do
cliente, usuários de uma conta, etc.)

•

ElasticSearch: indexação/buscas ultra-rápidas (expondo
uma engine de buscas poderosa para os clientes)

•

Não há porque se prender a uma tecnologia quando
cada uma delas resolve uma parte do seu problema
Um parênteses...
ElasticSearch
•

“Open Source Distributed Real Time Search & Analytics”

•

Construído em Java em cima do Apache Lucene (engine
robusta de busca e indexação em Java)

•

API RESTful (POST para inserir (indexar) dados num
“model”, GET para buscá-los)

•

Just works and scales (sem instalação, basta iniciar o
servidor; suporte a clusters out of the box)

•

Nosso uso: indexar/buscar responses (incluindo
metadata e nested objects) de models do MySQL
ElasticSearch
Transaction

Customer

amount

name

payment_method

email

card_last_digits document_number
customer_id

document_type

address_id

Address

{
"object": "transaction",
"status": "paid",
"date_created": "2013-11-21T02:27:10.000Z",
"amount": 1000,
"installments": 1,
"id": 35,
"card_holder_name": "PEDRO FRANCESCHI",
"card_last_digits": "5592",
"card_brand": "visa",
"payment_method": "credit_card",
"antifraud_score": null,
"subscription_id": null,
"customer": {
"object": "customer",
"document_number": "12388451908",
"document_type": "cpf",
"name": "Pedro Franceschi",
"email": null,
"born_at": null,
"date_created": "2013-11-11T05:24:52.000Z",
"id": 1
},
"address": {
"object": "address",
"street": "Av. Brigadeiro Faria Lima 2941",
"street_number": "2941",
"neighborhood": “Itaim Bibi",
"city": "São Paulo",
"state": "SP",
"zipcode": "01452000",
"country": "Brasil",
"id": 1
},
"phone": {
"object": "phone",
"ddi": "55",
"ddd": "21",
"number": "88888888",
"id": 1
},
"metadata": null

Phone

customer_id customer_id
street

ddd

neighborhood

number

id

id

id

phone_id

3 joins para montar o objeto de resposta

}
ElasticSearch
Transaction

Customer

amount

name

payment_method

email

card_last_digits document_number
customer_id

document_type

address_id

Address

Phone

customer_id customer_id
street

ddd

neighborhood

number

id

id

id

phone_id

ElasticSearch indexa o JSON já montado pelo
seu id em um índice (model) específico.

$ curl -X POST http://0.0.0.0:9200/pagarme/transactions/35
-d ‘
{
"object": "transaction",
"status": "paid",
"date_created": "2013-11-21T02:27:10.000Z",
"amount": 1000,
"installments": 1,
"id": 35,
"card_holder_name": "PEDRO FRANCESCHI",
"card_last_digits": "5592",
"card_brand": "visa",
"payment_method": "credit_card",
"antifraud_score": null,
"subscription_id": null,
"customer": {
"object": "customer",
"document_number": "12388451908",
"document_type": "cpf",
"name": "Pedro Franceschi",
"email": null,
"born_at": null,
"date_created": "2013-11-11T05:24:52.000Z",
"id": 1
},
"address": {
"object": "address",
"street": "Av. Brigadeiro Faria Lima 2941",
"street_number": "2941",
"neighborhood": “Itaim Bibi",
"city": "São Paulo",
"state": "SP",
"zipcode": "01452000",
"country": "Brasil",
"id": 1
},
"phone": {
"object": "phone",
"ddi": "55",
"ddd": "21",
"number": "88888888",
"id": 1
},
"metadata": null
}’
ElasticSearch
Transaction

Customer

amount

name

payment_method

email

card_last_digits document_number
customer_id

document_type

address_id

Address

Phone

customer_id customer_id
street

ddd

neighborhood

number

id

id

id

phone_id

Para retornar o objeto, basta realizar um GET pelo
seu id (o objeto é retornado dentro de “_source”)

$ curl -X GET http://0.0.0.0:9200/pagarme/transactions/
35
{
"_index": "pagarme",
"_type": "transaction",
"_id": "35",
"_version": 2,
"exists": true,
"_source": {
"object": "transaction",
"status": "paid",
"date_created": "2013-11-21T02:27:10.000Z",
"amount": 1000,
"installments": 1,
"id": 35,
"card_holder_name": “PEDRO FRANCESCHI",
"card_last_digits": "5592",
"card_brand": "visa",
"payment_method": "credit_card",
"antifraud_score": null,
"subscription_id": null,
"customer": {
"object": "customer",
"document_number": "12388451908",
"document_type": "cpf",
"name": "Pedro Franceschi",
"email": null,
"born_at": null,
"date_created": "2013-11-11T05:24:52.000Z",
"id": 1
},
"address": {
"object": "address",
"street": "Av. Brigadeiro Faria Lima 2941",
"street_number": "2941",
"neighborhood": “Itaim Bibi",
"city": "São Paulo",
"state": "SP",
"zipcode": "01452000",
"country": "Brasil",
"id": 1
},
"phone": {
"object": "phone",
"ddi": "55",
"ddd": "21",
"number": "88888888",
"id": 1
},
"metadata": null,
}
}
ElasticSearch
(buscando…)
$ curl -X GET ‘http://localhost:9200/pagarme/transaction/_search’ -d '
{
"query": {
"bool": {
"must": [
{
"text": {
"payment_method": "credit_card"
}
},
{
"text": {
"address.zipcode": "01452000"
}
},
{
"range": {
"amount": {
"gt": 1000
}
}
}
]
}
}
}'
ElasticSearch
• NÃO é um banco de dados. É um indexador.
• Evita I/O no DB (salva JSONs construídos a partir das
queries no DB)

• Permite buscas em cima dos próprios objetos que são
retornados para os clientes (padroniza o que é exposto
nos responses independente da estrutura do DB)

• Dashboard em tempo real a partir das indexações
• Dica: crie um script para indexar seu DB (indexar em
tempo real funciona mas pode quebrar)
Deployment
Nível 1

$ node server.js

n00bz… Processo não roda em background
Nível 2

$ git pull && npm install && node server.js &

Opa… Agora tem Git, update das dependências pelo NPM e o
processo roda em background
Nível 3

$ git pull && npm install && nohup node server.js

Nohup roda o processo mesmo depois do logout do SSH
Nível 4

$ git pull && npm install && service node-server restart

Um serviço é responsável por rodar e reiniciar o processo e
salvar os logs do processo
Nível 5
Servidor de Continuous Integration (CI)

+
$ service node-server restart

Agora o servidor de CI lida com o Git e as dependências
Nível 6
Strider (servidor de CI)

+
$ pm2 reload all

Strider é o servidor de CI e o pm2 reinicia o processo on-the-fly,
sem perder nenhum request
pm2
(https://github.com/Unitech/pm2)

•

Roda e gerencia os processos do Node.js (mantém
processo rodando para sempre)

•

Reload no código on-the-fly (zero downtime)

•

Multi-thread e clusterização sem alterar uma linha de
código

•

Monitoramento e gerenciamento dos logs

•

API RESTful + interface web
Strider
(https://github.com/Strider-CD/strider)

•

Servidor de CI 100% em Node.js

•

Integração com Github

•

Monitoramento dos testes em tempo real pelo
browser (com Socket.io)

•

Envio de emails com erros nos testes

•

Suporte a testes de regressão, custom scripts de
deployment, etc.
Monitoramento
Saber de problemas antes dos
clientes e ser transparente
quando eles acontecerem.
Para saber dos problemas…
!

Pingdom + PagerDuty
Para ser transparente sobre os problemas…
!

Status Page + Twitter de status
Para monitorar possíveis problemas…
!

Librato
Node.js: serious business
Conclusões…
Node.js: serious business
… mas …
Node.js: serious business
JavaScript
Overall…
Obrigado! :)
PEDROFRANCESCHI
@pedroh96
pedro@pagar.me
github.com/pedrofranceschi
Node.js: serious business
PEDROFRANCESCHI
@pedroh96
pedro@pagar.me
github.com/pedrofranceschi

More Related Content

What's hot

Turbinando o desenvolvimento Android com Kotlin
Turbinando o desenvolvimento Android com KotlinTurbinando o desenvolvimento Android com Kotlin
Turbinando o desenvolvimento Android com KotlinNelson Glauber Leal
 
Curso mongo db com php
Curso mongo db com phpCurso mongo db com php
Curso mongo db com phpSuissa
 
Hibernate efetivo (COALTI-2014 / ALJUG)
Hibernate efetivo (COALTI-2014 / ALJUG)Hibernate efetivo (COALTI-2014 / ALJUG)
Hibernate efetivo (COALTI-2014 / ALJUG)Rafael Ponte
 
Hibernate efetivo (IA-2014 / Disturbing the Mind)
Hibernate efetivo (IA-2014 / Disturbing the Mind)Hibernate efetivo (IA-2014 / Disturbing the Mind)
Hibernate efetivo (IA-2014 / Disturbing the Mind)Rafael Ponte
 
Zabbix Conference LatAm 2016 - Jorge Pretel - Low Level Discovery for ODBC an...
Zabbix Conference LatAm 2016 - Jorge Pretel - Low Level Discovery for ODBC an...Zabbix Conference LatAm 2016 - Jorge Pretel - Low Level Discovery for ODBC an...
Zabbix Conference LatAm 2016 - Jorge Pretel - Low Level Discovery for ODBC an...Zabbix
 
ZEO/RelStorage/PostgreSQL
ZEO/RelStorage/PostgreSQLZEO/RelStorage/PostgreSQL
ZEO/RelStorage/PostgreSQLgsroma
 
Persistência de Dados no SQLite com Room
Persistência de Dados no SQLite com RoomPersistência de Dados no SQLite com Room
Persistência de Dados no SQLite com RoomNelson Glauber Leal
 
Coisas que aprendi e quero passar adiante - RubyConf Brasil 2010
Coisas que aprendi e quero passar adiante - RubyConf Brasil 2010Coisas que aprendi e quero passar adiante - RubyConf Brasil 2010
Coisas que aprendi e quero passar adiante - RubyConf Brasil 2010lucashungaro
 
Ecossistema Ruby e Rails (Serpro BH)
Ecossistema Ruby e Rails (Serpro BH)Ecossistema Ruby e Rails (Serpro BH)
Ecossistema Ruby e Rails (Serpro BH)Daniel Lopes
 
Javascript no SAPO e libsapojs
Javascript no SAPO e libsapojsJavascript no SAPO e libsapojs
Javascript no SAPO e libsapojscodebits
 
Desenvolvimento de aplicações PHP com MongoDB
Desenvolvimento de aplicações PHP com MongoDBDesenvolvimento de aplicações PHP com MongoDB
Desenvolvimento de aplicações PHP com MongoDBAri Stopassola Junior
 
JavaScript e JQuery para Webdesigners
JavaScript e JQuery para WebdesignersJavaScript e JQuery para Webdesigners
JavaScript e JQuery para WebdesignersHarlley Oliveira
 
Desenvolvendo para iOS com Cocoa-Touch
Desenvolvendo para iOS com Cocoa-TouchDesenvolvendo para iOS com Cocoa-Touch
Desenvolvendo para iOS com Cocoa-TouchCampus Party Brasil
 
Minicurso sobre AndroidAnnotations, GreenDAO, EventBus e Crouton
Minicurso sobre AndroidAnnotations, GreenDAO, EventBus e CroutonMinicurso sobre AndroidAnnotations, GreenDAO, EventBus e Crouton
Minicurso sobre AndroidAnnotations, GreenDAO, EventBus e CroutonRicardo Longa
 
Autenticacao em APIs com SSL
Autenticacao em APIs com SSLAutenticacao em APIs com SSL
Autenticacao em APIs com SSLMarcelo Milhomem
 
Projeto Octopus - Database Sharding para ActiveRecord
Projeto Octopus - Database Sharding para ActiveRecordProjeto Octopus - Database Sharding para ActiveRecord
Projeto Octopus - Database Sharding para ActiveRecordtchandy
 

What's hot (20)

Turbinando o desenvolvimento Android com Kotlin
Turbinando o desenvolvimento Android com KotlinTurbinando o desenvolvimento Android com Kotlin
Turbinando o desenvolvimento Android com Kotlin
 
Curso mongo db com php
Curso mongo db com phpCurso mongo db com php
Curso mongo db com php
 
Hibernate efetivo (COALTI-2014 / ALJUG)
Hibernate efetivo (COALTI-2014 / ALJUG)Hibernate efetivo (COALTI-2014 / ALJUG)
Hibernate efetivo (COALTI-2014 / ALJUG)
 
Mongo + php
Mongo + phpMongo + php
Mongo + php
 
Hibernate efetivo (IA-2014 / Disturbing the Mind)
Hibernate efetivo (IA-2014 / Disturbing the Mind)Hibernate efetivo (IA-2014 / Disturbing the Mind)
Hibernate efetivo (IA-2014 / Disturbing the Mind)
 
Zabbix Conference LatAm 2016 - Jorge Pretel - Low Level Discovery for ODBC an...
Zabbix Conference LatAm 2016 - Jorge Pretel - Low Level Discovery for ODBC an...Zabbix Conference LatAm 2016 - Jorge Pretel - Low Level Discovery for ODBC an...
Zabbix Conference LatAm 2016 - Jorge Pretel - Low Level Discovery for ODBC an...
 
ZEO/RelStorage/PostgreSQL
ZEO/RelStorage/PostgreSQLZEO/RelStorage/PostgreSQL
ZEO/RelStorage/PostgreSQL
 
Modern PHP
Modern PHPModern PHP
Modern PHP
 
Persistência de Dados no SQLite com Room
Persistência de Dados no SQLite com RoomPersistência de Dados no SQLite com Room
Persistência de Dados no SQLite com Room
 
Coisas que aprendi e quero passar adiante - RubyConf Brasil 2010
Coisas que aprendi e quero passar adiante - RubyConf Brasil 2010Coisas que aprendi e quero passar adiante - RubyConf Brasil 2010
Coisas que aprendi e quero passar adiante - RubyConf Brasil 2010
 
Ecossistema Ruby e Rails (Serpro BH)
Ecossistema Ruby e Rails (Serpro BH)Ecossistema Ruby e Rails (Serpro BH)
Ecossistema Ruby e Rails (Serpro BH)
 
Javascript no SAPO e libsapojs
Javascript no SAPO e libsapojsJavascript no SAPO e libsapojs
Javascript no SAPO e libsapojs
 
Desenvolvimento de aplicações PHP com MongoDB
Desenvolvimento de aplicações PHP com MongoDBDesenvolvimento de aplicações PHP com MongoDB
Desenvolvimento de aplicações PHP com MongoDB
 
JavaScript e JQuery para Webdesigners
JavaScript e JQuery para WebdesignersJavaScript e JQuery para Webdesigners
JavaScript e JQuery para Webdesigners
 
Desenvolvendo para iOS com Cocoa-Touch
Desenvolvendo para iOS com Cocoa-TouchDesenvolvendo para iOS com Cocoa-Touch
Desenvolvendo para iOS com Cocoa-Touch
 
Doctrine for Dummies
Doctrine for DummiesDoctrine for Dummies
Doctrine for Dummies
 
Minicurso sobre AndroidAnnotations, GreenDAO, EventBus e Crouton
Minicurso sobre AndroidAnnotations, GreenDAO, EventBus e CroutonMinicurso sobre AndroidAnnotations, GreenDAO, EventBus e Crouton
Minicurso sobre AndroidAnnotations, GreenDAO, EventBus e Crouton
 
Java 9, 10 e ... 11
Java 9, 10 e ... 11Java 9, 10 e ... 11
Java 9, 10 e ... 11
 
Autenticacao em APIs com SSL
Autenticacao em APIs com SSLAutenticacao em APIs com SSL
Autenticacao em APIs com SSL
 
Projeto Octopus - Database Sharding para ActiveRecord
Projeto Octopus - Database Sharding para ActiveRecordProjeto Octopus - Database Sharding para ActiveRecord
Projeto Octopus - Database Sharding para ActiveRecord
 

Viewers also liked

Porque você deve aprender VIm hoje.
Porque você deve aprender VIm hoje.Porque você deve aprender VIm hoje.
Porque você deve aprender VIm hoje.Pedro Franceschi
 
Fazendo mágica com ElasticSearch
Fazendo mágica com ElasticSearchFazendo mágica com ElasticSearch
Fazendo mágica com ElasticSearchPedro Franceschi
 
Micro serviços com node.js
Micro serviços com node.jsMicro serviços com node.js
Micro serviços com node.jsBruno Trecenti
 
7Masters jQuery - Eventos em jQuery, com Felquis Gimenes
7Masters jQuery - Eventos em jQuery, com Felquis Gimenes7Masters jQuery - Eventos em jQuery, com Felquis Gimenes
7Masters jQuery - Eventos em jQuery, com Felquis GimenesiMasters
 
Fizzics presentation
Fizzics presentationFizzics presentation
Fizzics presentationmicroventures
 

Viewers also liked (6)

Porque você deve aprender VIm hoje.
Porque você deve aprender VIm hoje.Porque você deve aprender VIm hoje.
Porque você deve aprender VIm hoje.
 
Fazendo mágica com ElasticSearch
Fazendo mágica com ElasticSearchFazendo mágica com ElasticSearch
Fazendo mágica com ElasticSearch
 
Yes we can!
Yes we can!Yes we can!
Yes we can!
 
Micro serviços com node.js
Micro serviços com node.jsMicro serviços com node.js
Micro serviços com node.js
 
7Masters jQuery - Eventos em jQuery, com Felquis Gimenes
7Masters jQuery - Eventos em jQuery, com Felquis Gimenes7Masters jQuery - Eventos em jQuery, com Felquis Gimenes
7Masters jQuery - Eventos em jQuery, com Felquis Gimenes
 
Fizzics presentation
Fizzics presentationFizzics presentation
Fizzics presentation
 

Similar to Node.js: serious business

Workshop Node.js + MongoDB + Mongoose
Workshop Node.js + MongoDB + MongooseWorkshop Node.js + MongoDB + Mongoose
Workshop Node.js + MongoDB + MongooseLuiz Duarte
 
Tornando as coisas mais simples com Azure Functions e Node.JS
Tornando as coisas mais simples com Azure Functions e Node.JSTornando as coisas mais simples com Azure Functions e Node.JS
Tornando as coisas mais simples com Azure Functions e Node.JSMatheus Donizete
 
Monitoramento em tempo real (DEVDAY2015)
Monitoramento em tempo real (DEVDAY2015)Monitoramento em tempo real (DEVDAY2015)
Monitoramento em tempo real (DEVDAY2015)Marcus Lacerda
 
Precisamos falar sobre MERN stack
Precisamos falar sobre MERN stackPrecisamos falar sobre MERN stack
Precisamos falar sobre MERN stackSidney Roberto
 
Node.js: 5 razões para começar a utilizar
Node.js: 5 razões para começar a utilizarNode.js: 5 razões para começar a utilizar
Node.js: 5 razões para começar a utilizarFilipe Falcão
 
Redu walled garden
Redu walled gardenRedu walled garden
Redu walled gardenGuilherme
 
Linguagem de Programação Java para Iniciantes
Linguagem de Programação Java para IniciantesLinguagem de Programação Java para Iniciantes
Linguagem de Programação Java para IniciantesOziel Moreira Neto
 
Rails - EXATEC2009
Rails - EXATEC2009Rails - EXATEC2009
Rails - EXATEC2009Caue Guerra
 
WebSocket com Node.js ( socketstream && coffeescript ) X RoR ( Juggernaut )
WebSocket com Node.js ( socketstream && coffeescript ) X RoR ( Juggernaut )WebSocket com Node.js ( socketstream && coffeescript ) X RoR ( Juggernaut )
WebSocket com Node.js ( socketstream && coffeescript ) X RoR ( Juggernaut )João Moura
 
Backbone.js + Rails - Front-end e back-end conectados
Backbone.js + Rails - Front-end e back-end conectadosBackbone.js + Rails - Front-end e back-end conectados
Backbone.js + Rails - Front-end e back-end conectadosHenrique Gogó
 
Mini-Curso de MongoDB
Mini-Curso de MongoDBMini-Curso de MongoDB
Mini-Curso de MongoDBBrunno Gomes
 
LambdaDay: Backbone.js
LambdaDay: Backbone.jsLambdaDay: Backbone.js
LambdaDay: Backbone.jsGiovanni Bassi
 
Comparação de desempenho entre SQL e NoSQL
Comparação de desempenho entre SQL e NoSQLComparação de desempenho entre SQL e NoSQL
Comparação de desempenho entre SQL e NoSQLpichiliani
 
Apresentação sobre MVVMC
Apresentação sobre MVVMCApresentação sobre MVVMC
Apresentação sobre MVVMCAlisson Agiani
 

Similar to Node.js: serious business (20)

Workshop Node.js + MongoDB + Mongoose
Workshop Node.js + MongoDB + MongooseWorkshop Node.js + MongoDB + Mongoose
Workshop Node.js + MongoDB + Mongoose
 
Tornando as coisas mais simples com Azure Functions e Node.JS
Tornando as coisas mais simples com Azure Functions e Node.JSTornando as coisas mais simples com Azure Functions e Node.JS
Tornando as coisas mais simples com Azure Functions e Node.JS
 
Monitoramento em tempo real (DEVDAY2015)
Monitoramento em tempo real (DEVDAY2015)Monitoramento em tempo real (DEVDAY2015)
Monitoramento em tempo real (DEVDAY2015)
 
Boas práticas de API Design
Boas práticas de API DesignBoas práticas de API Design
Boas práticas de API Design
 
Precisamos falar sobre MERN stack
Precisamos falar sobre MERN stackPrecisamos falar sobre MERN stack
Precisamos falar sobre MERN stack
 
Node.js: 5 razões para começar a utilizar
Node.js: 5 razões para começar a utilizarNode.js: 5 razões para começar a utilizar
Node.js: 5 razões para começar a utilizar
 
Redu walled garden
Redu walled gardenRedu walled garden
Redu walled garden
 
Linguagem de Programação Java para Iniciantes
Linguagem de Programação Java para IniciantesLinguagem de Programação Java para Iniciantes
Linguagem de Programação Java para Iniciantes
 
Rails - EXATEC2009
Rails - EXATEC2009Rails - EXATEC2009
Rails - EXATEC2009
 
Hibernate-consultas
Hibernate-consultasHibernate-consultas
Hibernate-consultas
 
WebSocket com Node.js ( socketstream && coffeescript ) X RoR ( Juggernaut )
WebSocket com Node.js ( socketstream && coffeescript ) X RoR ( Juggernaut )WebSocket com Node.js ( socketstream && coffeescript ) X RoR ( Juggernaut )
WebSocket com Node.js ( socketstream && coffeescript ) X RoR ( Juggernaut )
 
Backbone.js + Rails - Front-end e back-end conectados
Backbone.js + Rails - Front-end e back-end conectadosBackbone.js + Rails - Front-end e back-end conectados
Backbone.js + Rails - Front-end e back-end conectados
 
Mini-Curso de MongoDB
Mini-Curso de MongoDBMini-Curso de MongoDB
Mini-Curso de MongoDB
 
introdução a ajax
introdução a ajaxintrodução a ajax
introdução a ajax
 
Mongodb workshop cinlug
Mongodb workshop cinlugMongodb workshop cinlug
Mongodb workshop cinlug
 
LambdaDay: Backbone.js
LambdaDay: Backbone.jsLambdaDay: Backbone.js
LambdaDay: Backbone.js
 
DDD > Experiências
DDD > ExperiênciasDDD > Experiências
DDD > Experiências
 
Comparação de desempenho entre SQL e NoSQL
Comparação de desempenho entre SQL e NoSQLComparação de desempenho entre SQL e NoSQL
Comparação de desempenho entre SQL e NoSQL
 
Implementação de
Implementação de Implementação de
Implementação de
 
Apresentação sobre MVVMC
Apresentação sobre MVVMCApresentação sobre MVVMC
Apresentação sobre MVVMC
 

Node.js: serious business

  • 2. Assuntos • O problema • Por que e quando usar Node.js? • Problemas de Node.js • Node.js “the right way” • Repensando a infraestrutura • Deployment (Continuous Integration) e monitoramento • Conclusões…
  • 4. “Montar um gateway de pagamentos amigável para desenvolvedores e empreendedores”
  • 5. “A forma mais simples de receber pagamentos online”
  • 7. Premissas da API • Simplicidade: RESTful + JSON • Ambiente de testes isolado e decente • Segurança sem comprometer simplicidade • Uptime de 99,9% • Escalabilidade
  • 11. Por que Node.js? (Cielo, RedeCard, etc) legítima Sistema antifraude ro er o/ ss ce su m s 10.000 ms 3. 00 0 Adquirente fraude erro API RESTful Request de transação
  • 12. Por que Node.js? (no nosso caso) • Requests externos demorados (>1.000ms) • I/O intenso em banco de dados • Totalmente assíncrono, single thread e event-based • Pouco processamento (sem blocking de CPU)
  • 13. Por que Node.js? (no nosso caso) “Mas é só usar threads em qualquer linguagem!..” Não.
  • 14. Por que Node.js? (no nosso caso) 1.000 requests por segundo com conexão a uma API externa + I/O no DB = 1.000 threads por segundo … se cada request leva em média 10 segundos … Em 9 segundos, teremos 9.000 threads Isso escala? :P :P :P
  • 15. Por que Node.js? (no nosso caso) Agora, em Node.js…
  • 16. Por que Node.js? (no nosso caso) 1.000 requests por segundo com conexão a uma API externa + I/O no DB = 1 thread … se cada request leva em média 10 segundos … Em 9 segundos, teremos 1 thread Isso escala? Sim. #eventloopFTW
  • 17. I/O síncrona I/O retorno I/O retorno I/O retorno Aplicação I/O bloqueante (aplicação travada) I/O bloqueante (aplicação travada) Sistema operacional I/O bloqueante (aplicação travada)
  • 18. I/O “assíncrona” com threads I/O callback I/O callback I/O callback Aplicação Thread Thread Thread I/O bloqueante (thread travada) I/O bloqueante (thread travada) I/O bloqueante (thread travada) Sistema operacional
  • 19. O segredo do Node.js I/O I/O callback callback callback I/O JavaScript (event loop) V8 libuv Sistema operacional …………………………………… …………………………………… …………………………………… operações assíncronas em nível de OS
  • 20. Node.js escala em I/O bloqueante, não em utilização de CPU (threads são boas em processamento paralelo)
  • 21. Se I/O bloqueante não for um problema, Node.js não tem tantas vantagens.
  • 24. Problemas de Node.js Código assíncrono (race conditions, callback hell, testes assíncronos, etc) db.query("SELECT a FROM users WHERE ...;", function (err, result1) { db.query("SELECT b FROM users WHERE ...;", function (err, result2) { db.query("SELECT c FROM users WHERE ...;", function (err, result3) { db.query("SELECT d FROM users WHERE ...;", function (err, result4) { db.query("SELECT e FROM users WHERE ...;", function (err, result5) { console.log("Finished."); }); }); }); }); }); Um ótimo exemplo do que não fazer: callback hell.
  • 25. Problemas de Node.js Problemas de Javascript: bizarrices e facilidade em não seguir padrões e orientação a objetos. > 0.1+0.2 0.30000000000000004 ! > typeof NaN 'number' ! > NaN === NaN false Cortesia do wtfjs.com
  • 26. Problemas de Node.js Exceptions não tratadas matam o processo. var name = “Pedro Franceschi"; ! console.log("Tamanho do primeiro nome: " + name.split(" ")[0].length); console.log("Tamanho do segundo nome: " + name.split(" ")[1].length); $ node test.js Tamanho do primeiro nome: 5 Tamanho do segundo nome: 10
  • 27. Problemas de Node.js Exceptions não tratadas matam o processo. var name = “Pedro"; ! console.log("Tamanho do primeiro nome: " + name.split(" ")[0].length); console.log("Tamanho do segundo nome: " + name.split(" ")[1].length); $ node test.js Tamanho do primeiro nome: 5 ! /private/tmp/test.js:4 console.log("Tamanho do segundo nome: " + name.split(" ")[1].length); ^ TypeError: Cannot read property 'length' of undefined at Object.<anonymous> (/private/tmp/test.js:4:61) at Module._compile (module.js:456:26) at Object.Module._extensions..js (module.js:474:10) at Module.load (module.js:356:32) at Function.Module._load (module.js:312:12) at Function.Module.runMain (module.js:497:10) at startup (node.js:119:16) at node.js:901:3
  • 28. Problemas de Node.js • Single thread (escalar horizontalmente e verticalmente com múltiplas instâncias) • Leaks de memória difíceis de detectar devido a código mal feito (variáveis globalizadas, closures, etc) • Programadores front-end mexendo em back-end (“é tudo Javascript!!”) • Existe a 4 anos, porém ainda é beta (v0.10.22)
  • 30. Node.js “the right way” Modules var PI = Math.PI; ! exports.area = function (r) { return PI * r * r; }; ! exports.circumference = function (r) { return 2 * PI * r; }; circle.js var circle = require('./circle.js'); ! console.log( 'The area of a circle of radius 4 is ' + circle.area(4)); main.js
  • 31. Node.js “the right way” Evitar callback hells com async (https://github.com/caolan/async) db.query("SELECT a FROM users WHERE ...;", function (err, result1) { db.query("SELECT b FROM users WHERE ...;", function (err, result2) { db.query("SELECT c FROM users WHERE ...;", function (err, result3) { db.query("SELECT d FROM users WHERE ...;", function (err, result4) { db.query("SELECT e FROM users WHERE ...;", function (err, result5) { console.log("Finished."); }); }); }); }); }); Não tente fazer isso em casa
  • 32. Node.js “the right way” Evitar callback hells com async (https://github.com/caolan/async) async.parallel({ result1: function(callback) { db.query("SELECT a FROM users WHERE ...;", function(err, result1){ callback(err, result1); }); }, result2: function(callback) { db.query("SELECT b FROM users WHERE ...;", function(err, result2){ callback(err, result2); }); }, result3: function(callback) { db.query("SELECT c FROM users WHERE ...;", function(err, result3){ callback(err, result3); }); } }, function(err, results){ console.log("Finished."); }) Assim é bem melhor :)
  • 33. Node.js “the right way” Testes (JavaScript quebra) (https://github.com/visionmedia/mocha e https://github.com/visionmedia/should.js/) describe('Array', function(){ describe('#indexOf()', function(){ it('should return -1 when the value is not present', function(){ [1,2,3].indexOf(5).should.equal(-1); }) }) ! ! describe(‘#indexOf() after one second', function(){ before(function(done){ setTimeout(function(){ done(); }, 1000); }); it('should return -1 when the value is not present', function(){ [1,2,3].indexOf(5).should.equal(-1); }) }) });
  • 34. Node.js “the right way” • Seguir e manter um code style (dica: Google JavaScript Style Guide) • Tratamento de erros consistente (processos morrem)
  • 35. Node.js “the right way” utils • Express.js: lightweight HTTP framework • Sequelize: ORM de MySQL, PostgreSQL, sqlite3, etc. • Mongoose: ORM de MongoDB • Commander: wrapper de command line • Vim: melhor editor de texto :P
  • 36. “Inovação” em padrões de código não é inovação. (99,9% das vezes)
  • 39. Use o melhor de cada banco de dados.
  • 40. Infraestrutura do Pagar.me MySQL MongoDB MySQL (transações e dados relacionais) (dados de clientes e não relacionais) (transações e dados relacionais) ElasticSearch ElasticSearch Servidor da API Servidor da API (Node.js) (Node.js) Router Ambiente de produção Ambiente de testes (sandbox dos clientes) api.pagar.me
  • 41. Por que tantos bancos? • Separar dados de teste (sandbox dos clientes) dos dados de produção • MySQL: dados relacionais (transações, assinaturas, planos, cartões, etc.) • MongoDB: dados não-relacionais (informações do cliente, usuários de uma conta, etc.) • ElasticSearch: indexação/buscas ultra-rápidas (expondo uma engine de buscas poderosa para os clientes) • Não há porque se prender a uma tecnologia quando cada uma delas resolve uma parte do seu problema
  • 43. ElasticSearch • “Open Source Distributed Real Time Search & Analytics” • Construído em Java em cima do Apache Lucene (engine robusta de busca e indexação em Java) • API RESTful (POST para inserir (indexar) dados num “model”, GET para buscá-los) • Just works and scales (sem instalação, basta iniciar o servidor; suporte a clusters out of the box) • Nosso uso: indexar/buscar responses (incluindo metadata e nested objects) de models do MySQL
  • 44. ElasticSearch Transaction Customer amount name payment_method email card_last_digits document_number customer_id document_type address_id Address { "object": "transaction", "status": "paid", "date_created": "2013-11-21T02:27:10.000Z", "amount": 1000, "installments": 1, "id": 35, "card_holder_name": "PEDRO FRANCESCHI", "card_last_digits": "5592", "card_brand": "visa", "payment_method": "credit_card", "antifraud_score": null, "subscription_id": null, "customer": { "object": "customer", "document_number": "12388451908", "document_type": "cpf", "name": "Pedro Franceschi", "email": null, "born_at": null, "date_created": "2013-11-11T05:24:52.000Z", "id": 1 }, "address": { "object": "address", "street": "Av. Brigadeiro Faria Lima 2941", "street_number": "2941", "neighborhood": “Itaim Bibi", "city": "São Paulo", "state": "SP", "zipcode": "01452000", "country": "Brasil", "id": 1 }, "phone": { "object": "phone", "ddi": "55", "ddd": "21", "number": "88888888", "id": 1 }, "metadata": null Phone customer_id customer_id street ddd neighborhood number id id id phone_id 3 joins para montar o objeto de resposta }
  • 45. ElasticSearch Transaction Customer amount name payment_method email card_last_digits document_number customer_id document_type address_id Address Phone customer_id customer_id street ddd neighborhood number id id id phone_id ElasticSearch indexa o JSON já montado pelo seu id em um índice (model) específico. $ curl -X POST http://0.0.0.0:9200/pagarme/transactions/35 -d ‘ { "object": "transaction", "status": "paid", "date_created": "2013-11-21T02:27:10.000Z", "amount": 1000, "installments": 1, "id": 35, "card_holder_name": "PEDRO FRANCESCHI", "card_last_digits": "5592", "card_brand": "visa", "payment_method": "credit_card", "antifraud_score": null, "subscription_id": null, "customer": { "object": "customer", "document_number": "12388451908", "document_type": "cpf", "name": "Pedro Franceschi", "email": null, "born_at": null, "date_created": "2013-11-11T05:24:52.000Z", "id": 1 }, "address": { "object": "address", "street": "Av. Brigadeiro Faria Lima 2941", "street_number": "2941", "neighborhood": “Itaim Bibi", "city": "São Paulo", "state": "SP", "zipcode": "01452000", "country": "Brasil", "id": 1 }, "phone": { "object": "phone", "ddi": "55", "ddd": "21", "number": "88888888", "id": 1 }, "metadata": null }’
  • 46. ElasticSearch Transaction Customer amount name payment_method email card_last_digits document_number customer_id document_type address_id Address Phone customer_id customer_id street ddd neighborhood number id id id phone_id Para retornar o objeto, basta realizar um GET pelo seu id (o objeto é retornado dentro de “_source”) $ curl -X GET http://0.0.0.0:9200/pagarme/transactions/ 35 { "_index": "pagarme", "_type": "transaction", "_id": "35", "_version": 2, "exists": true, "_source": { "object": "transaction", "status": "paid", "date_created": "2013-11-21T02:27:10.000Z", "amount": 1000, "installments": 1, "id": 35, "card_holder_name": “PEDRO FRANCESCHI", "card_last_digits": "5592", "card_brand": "visa", "payment_method": "credit_card", "antifraud_score": null, "subscription_id": null, "customer": { "object": "customer", "document_number": "12388451908", "document_type": "cpf", "name": "Pedro Franceschi", "email": null, "born_at": null, "date_created": "2013-11-11T05:24:52.000Z", "id": 1 }, "address": { "object": "address", "street": "Av. Brigadeiro Faria Lima 2941", "street_number": "2941", "neighborhood": “Itaim Bibi", "city": "São Paulo", "state": "SP", "zipcode": "01452000", "country": "Brasil", "id": 1 }, "phone": { "object": "phone", "ddi": "55", "ddd": "21", "number": "88888888", "id": 1 }, "metadata": null, } }
  • 47. ElasticSearch (buscando…) $ curl -X GET ‘http://localhost:9200/pagarme/transaction/_search’ -d ' { "query": { "bool": { "must": [ { "text": { "payment_method": "credit_card" } }, { "text": { "address.zipcode": "01452000" } }, { "range": { "amount": { "gt": 1000 } } } ] } } }'
  • 48. ElasticSearch • NÃO é um banco de dados. É um indexador. • Evita I/O no DB (salva JSONs construídos a partir das queries no DB) • Permite buscas em cima dos próprios objetos que são retornados para os clientes (padroniza o que é exposto nos responses independente da estrutura do DB) • Dashboard em tempo real a partir das indexações • Dica: crie um script para indexar seu DB (indexar em tempo real funciona mas pode quebrar)
  • 50. Nível 1 $ node server.js n00bz… Processo não roda em background
  • 51. Nível 2 $ git pull && npm install && node server.js & Opa… Agora tem Git, update das dependências pelo NPM e o processo roda em background
  • 52. Nível 3 $ git pull && npm install && nohup node server.js Nohup roda o processo mesmo depois do logout do SSH
  • 53. Nível 4 $ git pull && npm install && service node-server restart Um serviço é responsável por rodar e reiniciar o processo e salvar os logs do processo
  • 54. Nível 5 Servidor de Continuous Integration (CI) + $ service node-server restart Agora o servidor de CI lida com o Git e as dependências
  • 55. Nível 6 Strider (servidor de CI) + $ pm2 reload all Strider é o servidor de CI e o pm2 reinicia o processo on-the-fly, sem perder nenhum request
  • 56. pm2 (https://github.com/Unitech/pm2) • Roda e gerencia os processos do Node.js (mantém processo rodando para sempre) • Reload no código on-the-fly (zero downtime) • Multi-thread e clusterização sem alterar uma linha de código • Monitoramento e gerenciamento dos logs • API RESTful + interface web
  • 57. Strider (https://github.com/Strider-CD/strider) • Servidor de CI 100% em Node.js • Integração com Github • Monitoramento dos testes em tempo real pelo browser (com Socket.io) • Envio de emails com erros nos testes • Suporte a testes de regressão, custom scripts de deployment, etc.
  • 59. Saber de problemas antes dos clientes e ser transparente quando eles acontecerem.
  • 60. Para saber dos problemas… ! Pingdom + PagerDuty
  • 61. Para ser transparente sobre os problemas… ! Status Page + Twitter de status
  • 62. Para monitorar possíveis problemas… ! Librato