Node.js no Pagar.me

2.383 visualizações

Publicada em

Palestra explicando como o Pagar.me usa Node.js no meetup do NodeBR sobre APIs sediado na sede do Pagar.me :-)

Publicada em: Tecnologia
1 comentário
10 gostaram
Estatísticas
Notas
Sem downloads
Visualizações
Visualizações totais
2.383
No SlideShare
0
A partir de incorporações
0
Número de incorporações
22
Ações
Compartilhamentos
0
Downloads
61
Comentários
1
Gostaram
10
Incorporações 0
Nenhuma incorporação

Nenhuma nota no slide

Node.js no Pagar.me

  1. 1. PEDROFRANCESCHI @pedroh96 pedro@pagar.me github.com/pedrofranceschi Node.js no
  2. 2. Assuntos
  3. 3. • O problema Assuntos
  4. 4. • O problema • Por que Node.js? Assuntos
  5. 5. • O problema • Por que Node.js? • Problemas de Node.js Assuntos
  6. 6. • O problema • Por que Node.js? • Problemas de Node.js • Node.js“the right way” Assuntos
  7. 7. • O problema • Por que Node.js? • Problemas de Node.js • Node.js“the right way” • Repensando a infraestrutura (+ Microservices) Assuntos
  8. 8. • O problema • Por que Node.js? • Problemas de Node.js • Node.js“the right way” • Repensando a infraestrutura (+ Microservices) • Deployment (+ Continuous Integration) Assuntos
  9. 9. • O problema • Por que Node.js? • Problemas de Node.js • Node.js“the right way” • Repensando a infraestrutura (+ Microservices) • Deployment (+ Continuous Integration) • Conclusões… Assuntos
  10. 10. O problema
  11. 11. “Montar um gateway de pagamentos amigável para desenvolvedores e empreendedores”
  12. 12. “A forma mais simples de receber pagamentos online”
  13. 13. API RESTful Dashboard Angular.js Ruby Node.js Python Java .NET PHP C#
  14. 14. Premissas da API
  15. 15. • Simplicidade: RESTful + JSON Premissas da API
  16. 16. • Simplicidade: RESTful + JSON • Ambiente de testes isolado e decente Premissas da API
  17. 17. • Simplicidade: RESTful + JSON • Ambiente de testes isolado e decente • Segurança sem comprometer simplicidade (PCI) Premissas da API
  18. 18. • Simplicidade: RESTful + JSON • Ambiente de testes isolado e decente • Segurança sem comprometer simplicidade (PCI) • Uptime de 99,9% Premissas da API
  19. 19. • Simplicidade: RESTful + JSON • Ambiente de testes isolado e decente • Segurança sem comprometer simplicidade (PCI) • Uptime de 99,9% • Escalabilidade Premissas da API
  20. 20. Por que Node.js?
  21. 21. Por que Node.js? Request de transação API RESTful Sistema antifraude fraude legítimaAdquirente (Cielo, Rede, etc) sucesso/erro erro
  22. 22. Por que Node.js? Request de transação API RESTful Sistema antifraude fraude legítimaAdquirente (Cielo, Rede, etc) 10.000 ms 3.000 m s sucesso/erro erro
  23. 23. Por que Node.js? (no nosso caso)
  24. 24. Por que Node.js? (no nosso caso) • Requests externos demorados (>1.000ms)
  25. 25. Por que Node.js? (no nosso caso) • Requests externos demorados (>1.000ms) • I/O intenso em banco de dados
  26. 26. 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
  27. 27. 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 • Alta carga na aplicação
  28. 28. 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 • Alta carga na aplicação • Pouco processamento (sem blocking de CPU)
  29. 29. Por que Node.js? (no nosso caso) “Mas é só usar threads em qualquer linguagem!..”
  30. 30. Por que Node.js? (no nosso caso) “Mas é só usar threads em qualquer linguagem!..” Não.
  31. 31. 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
  32. 32. 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 …
  33. 33. 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
  34. 34. 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
  35. 35. Por que Node.js? (no nosso caso) Agora, em Node.js…
  36. 36. 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
  37. 37. 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 …
  38. 38. 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
  39. 39. 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.
  40. 40. 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
  41. 41. I/O síncrona Aplicação Sistema operacional
  42. 42. I/O síncrona Aplicação Sistema operacional I/O
  43. 43. I/O síncrona Aplicação Sistema operacional I/O
  44. 44. I/O síncrona Aplicação Sistema operacional I/O I/O bloqueante (aplicação travada)
  45. 45. I/O síncrona Aplicação Sistema operacional I/O I/O bloqueante (aplicação travada)
  46. 46. I/O síncrona Aplicação Sistema operacional I/O retorno I/O bloqueante (aplicação travada)
  47. 47. I/O síncrona Aplicação Sistema operacional I/O retorno I/O bloqueante (aplicação travada) I/O retorno I/O bloqueante (aplicação travada)
  48. 48. I/O síncrona Aplicação Sistema operacional I/O retorno I/O bloqueante (aplicação travada) I/O retorno I/O bloqueante (aplicação travada) I/O retorno I/O bloqueante (aplicação travada)
  49. 49. I/O“assíncrona”com threads Aplicação Sistema operacional
  50. 50. I/O“assíncrona”com threads Aplicação Sistema operacional I/O
  51. 51. I/O“assíncrona”com threads Aplicação Sistema operacional I/O
  52. 52. I/O“assíncrona”com threads Aplicação Sistema operacional I/O Thread
  53. 53. I/O“assíncrona”com threads Aplicação Sistema operacional I/O Thread
  54. 54. I/O“assíncrona”com threads Aplicação Sistema operacional I/O Thread I/O bloqueante (thread travada)
  55. 55. I/O“assíncrona”com threads Aplicação Sistema operacional I/O Thread I/O bloqueante (thread travada)
  56. 56. I/O“assíncrona”com threads Aplicação Sistema operacional I/O Thread I/O bloqueante (thread travada)
  57. 57. I/O“assíncrona”com threads Aplicação Sistema operacional I/O Thread callback I/O bloqueante (thread travada)
  58. 58. I/O“assíncrona”com threads Aplicação Sistema operacional I/O Thread callback I/O bloqueante (thread travada) I/O Thread callback I/O bloqueante (thread travada)
  59. 59. I/O“assíncrona”com threads Aplicação Sistema operacional I/O Thread callback I/O bloqueante (thread travada) I/O Thread callback I/O bloqueante (thread travada) I/O Thread callback I/O bloqueante (thread travada)
  60. 60. O segredo do Node.js JavaScript (event loop) V8 libuv Sistema operacional
  61. 61. O segredo do Node.js JavaScript (event loop) V8 libuv Sistema operacional I/O
  62. 62. O segredo do Node.js JavaScript (event loop) V8 libuv Sistema operacional I/O
  63. 63. O segredo do Node.js JavaScript (event loop) V8 libuv Sistema operacional I/O
  64. 64. O segredo do Node.js JavaScript (event loop) V8 libuv Sistema operacional I/O
  65. 65. O segredo do Node.js JavaScript (event loop) V8 libuv Sistema operacional …………………………………… I/O
  66. 66. O segredo do Node.js JavaScript (event loop) V8 libuv Sistema operacional …………………………………… operações assíncronas em nível de OS I/O
  67. 67. O segredo do Node.js JavaScript (event loop) V8 libuv Sistema operacional …………………………………… operações assíncronas em nível de OS I/O
  68. 68. O segredo do Node.js JavaScript (event loop) V8 libuv Sistema operacional …………………………………… operações assíncronas em nível de OS I/O
  69. 69. O segredo do Node.js JavaScript (event loop) V8 libuv Sistema operacional …………………………………… operações assíncronas em nível de OS I/O
  70. 70. O segredo do Node.js JavaScript (event loop) V8 libuv Sistema operacional …………………………………… operações assíncronas em nível de OS I/O callback
  71. 71. O segredo do Node.js JavaScript (event loop) V8 libuv Sistema operacional …………………………………… operações assíncronas em nível de OS I/O callback I/O
  72. 72. O segredo do Node.js JavaScript (event loop) V8 libuv Sistema operacional …………………………………… operações assíncronas em nível de OS …………………………………… I/O callback I/O
  73. 73. O segredo do Node.js JavaScript (event loop) V8 libuv Sistema operacional …………………………………… operações assíncronas em nível de OS …………………………………… I/O callback I/O I/O
  74. 74. O segredo do Node.js JavaScript (event loop) V8 libuv Sistema operacional …………………………………… operações assíncronas em nível de OS ………………………………………………………………………… I/O callback I/O I/O
  75. 75. O segredo do Node.js JavaScript (event loop) V8 libuv Sistema operacional …………………………………… operações assíncronas em nível de OS ………………………………………………………………………… I/O callback I/O I/O callback
  76. 76. O segredo do Node.js JavaScript (event loop) V8 libuv Sistema operacional …………………………………… operações assíncronas em nível de OS ………………………………………………………………………… I/O callback I/O I/O callback callback
  77. 77. Node.js escala em I/O bloqueante, não em utilização de CPU (threads são boas em processamento paralelo)
  78. 78. Problemas de Node.js
  79. 79. 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
  80. 80. 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
  81. 81. 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); Problemas de Node.js $ node test.js Tamanho do primeiro nome: 5 Tamanho do segundo nome: 10
  82. 82. 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); Problemas de Node.js $ 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
  83. 83. Problemas de Node.js
  84. 84. Problemas de Node.js • Single thread (escalar horizontalmente e verticalmente com múltiplas instâncias)
  85. 85. Problemas de Node.js • Single thread (escalar horizontalmente e verticalmente com múltiplas instâncias) • Leaks de memória difíceis de detectar (back-end em C++, variáveis globalizadas, closures, etc)
  86. 86. Problemas de Node.js • Single thread (escalar horizontalmente e verticalmente com múltiplas instâncias) • Leaks de memória difíceis de detectar (back-end em C++, variáveis globalizadas, closures, etc) • Programadores front-end mexendo em back-end (“é tudo Javascript!!”)
  87. 87. Problemas de Node.js • Single thread (escalar horizontalmente e verticalmente com múltiplas instâncias) • Leaks de memória difíceis de detectar (back-end em C++, variáveis globalizadas, closures, etc) • Programadores front-end mexendo em back-end (“é tudo Javascript!!”) • Existe a 6 anos, porém ainda é beta (v0.12.0) - e às vezes você precisa usar unstable em produção
  88. 88. Node.js“the right way”
  89. 89. Qualidade de vida vs. tempo usando Node
  90. 90. Qualidade de vida vs. tempo usando Node Node é muito legal!!!
  91. 91. Qualidade de vida vs. tempo usando Node Node é muito legal!!! Ops… Meu código está ficando uma zona…
  92. 92. Qualidade de vida vs. tempo usando Node Node é muito legal!!! Ops… Meu código está ficando uma zona… Queria ter feito em Rails…
  93. 93. Qualidade de vida vs. tempo usando Node Node é muito legal!!! Ops… Meu código está ficando uma zona… Queria ter feito em Rails… MVC de verdade + Promise + Bluebird <3
  94. 94. Modules Node.js “the right way” 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
  95. 95. Node.js “the right way” 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); }) }) }); Testes (JavaScript quebra) (https://github.com/visionmedia/mocha e https://github.com/visionmedia/should.js/)
  96. 96. Node.js “the right way” Models (Sequelize/Mongoose) var Transaction = Sequelize.define('Transaction', { amount: Sequelize.INTEGER, cost: Sequelize.FLOAT, status: { type: Sequelize.ENUM, values: ['paid', 'refused', 'refunded'], defaultValue: 'processing' } }, { instanceMethods: { calculateCost: function(status){ status = status || this.status; if(status == 'paid') { return 50 + (this.amount * 0.015); } }, }, classMethods: { }, hooks: { beforeUpdate: function(transaction) { return transaction.calculateCost() .then(function(cost) { transaction.cost = cost; }); } }, });
  97. 97. Node.js “the right way” Models (Sequelize/Mongoose) var Transaction = Sequelize.define('Transaction', { amount: Sequelize.INTEGER, cost: Sequelize.FLOAT, status: { type: Sequelize.ENUM, values: ['paid', 'refused', 'refunded'], defaultValue: 'processing' } }, { instanceMethods: { calculateCost: function(status){ status = status || this.status; if(status == 'paid') { return 50 + (this.amount * 0.015); } }, }, classMethods: { }, hooks: { beforeUpdate: function(transaction) { return transaction.calculateCost() .then(function(cost) { transaction.cost = cost; }); } }, });
  98. 98. Node.js “the right way” Models (Sequelize/Mongoose) var Transaction = Sequelize.define('Transaction', { amount: Sequelize.INTEGER, cost: Sequelize.FLOAT, status: { type: Sequelize.ENUM, values: ['paid', 'refused', 'refunded'], defaultValue: 'processing' } }, { instanceMethods: { calculateCost: function(status){ status = status || this.status; if(status == 'paid') { return 50 + (this.amount * 0.015); } }, }, classMethods: { }, hooks: { beforeUpdate: function(transaction) { return transaction.calculateCost() .then(function(cost) { transaction.cost = cost; }); } }, });
  99. 99. Node.js “the right way” Models (Sequelize/Mongoose) var Transaction = Sequelize.define('Transaction', { amount: Sequelize.INTEGER, cost: Sequelize.FLOAT, status: { type: Sequelize.ENUM, values: ['paid', 'refused', 'refunded'], defaultValue: 'processing' } }, { instanceMethods: { calculateCost: function(status){ status = status || this.status; if(status == 'paid') { return 50 + (this.amount * 0.015); } }, }, classMethods: { }, hooks: { beforeUpdate: function(transaction) { return transaction.calculateCost() .then(function(cost) { transaction.cost = cost; }); } }, });
  100. 100. Node.js “the right way” Models (Sequelize/Mongoose) var Transaction = Sequelize.define('Transaction', { amount: Sequelize.INTEGER, cost: Sequelize.FLOAT, status: { type: Sequelize.ENUM, values: ['paid', 'refused', 'refunded'], defaultValue: 'processing' } }, { instanceMethods: { calculateCost: function(status){ status = status || this.status; if(status == 'paid') { return 50 + (this.amount * 0.015); } }, }, classMethods: { }, hooks: { beforeUpdate: function(transaction) { return transaction.calculateCost() .then(function(cost) { transaction.cost = cost; }); } }, });
  101. 101. Node.js “the right way” Promises (Bluebird) fs.readFile("file.json", function(err, val) { if(err) { console.error("unable to read file"); } else { try { val = JSON.parse(val); console.log(val.success); } catch(e) { console.error("invalid json in file"); } } });
  102. 102. Node.js “the right way” Promises (Bluebird) fs.readFile("file.json", function(err, val) { if(err) { console.error("unable to read file"); } else { try { val = JSON.parse(val); console.log(val.success); } catch(e) { console.error("invalid json in file"); } } });
  103. 103. Node.js “the right way” Promises (Bluebird) fs.readFileAsync("file.json").then(JSON.parse).then(function(val) { console.log(val.success); }) .catch(SyntaxError, function(e) { console.error("invalid json in file"); }) .catch(function(e){ console.error("unable to read file") }); Assim é bem melhor :)
  104. 104. Node.js “the right way” Lodash var lines = [ ['name', 'type', 'cost'], ['iPhone', 'cellphone', '2000'], ['MacBook', 'computer', '10000'], ['iPad', 'tablet', '1500'] ]; var joinedLines = []; for(var i = 0; i < lines.length; i++) { joinedLines.push(lines[i].join(',')); } var csvContent = joinedLines.join('n'); name,type,cost iPhone,cellphone,2000 MacBook,computer,10000 iPad,tablet,1500 Output
  105. 105. Node.js “the right way” Lodash var lines = [ ['name', 'type', 'cost'], ['iPhone', 'cellphone', '2000'], ['MacBook', 'computer', '10000'], ['iPad', 'tablet', '1500'] ]; var joinedLines = []; for(var i = 0; i < lines.length; i++) { joinedLines.push(lines[i].join(',')); } var csvContent = joinedLines.join('n'); name,type,cost iPhone,cellphone,2000 MacBook,computer,10000 iPad,tablet,1500 Output
  106. 106. Node.js “the right way” Lodash var lines = [ ['name', 'type', 'cost'], ['iPhone', 'cellphone', '2000'], ['MacBook', 'computer', '10000'], ['iPad', 'tablet', '1500'] ]; var joinedLines = []; for(var i = 0; i < lines.length; i++) { joinedLines.push(lines[i].join(',')); } var csvContent = joinedLines.join('n'); name,type,cost iPhone,cellphone,2000 MacBook,computer,10000 iPad,tablet,1500 Output
  107. 107. Node.js “the right way” Assim é bem melhor :) Lodash var _ = require('lodash'); var lines = [ ['name', 'type', 'cost'], ['iPhone', 'cellphone', '2000'], ['MacBook', 'computer', '10000'], ['iPad', 'tablet', '1500'] ]; var csvContent = _.map(lines, function(line){ return line.join(','); }).join('n'); name,type,cost iPhone,cellphone,2000 MacBook,computer,10000 iPad,tablet,1500 Output
  108. 108. Node.js “the right way”
  109. 109. Node.js “the right way” • Seguir e manter um code style (dica: Google JavaScript Style Guide)
  110. 110. Node.js “the right way” • Seguir e manter um code style (dica: Google JavaScript Style Guide) • Tratamento de erros consistente via Promise (evitar que processos morram)
  111. 111. Node.js “the right way” • Seguir e manter um code style (dica: Google JavaScript Style Guide) • Tratamento de erros consistente via Promise (evitar que processos morram) • Manter consistência entre as bibliotecas de Promise (i.e. usar a mesma do wrapper do database)
  112. 112. Node.js “the right way” • Seguir e manter um code style (dica: Google JavaScript Style Guide) • Tratamento de erros consistente via Promise (evitar que processos morram) • Manter consistência entre as bibliotecas de Promise (i.e. usar a mesma do wrapper do database) • Sem for(var i = 0; i < object.length; i++) - #lodashFTW
  113. 113. Node.js “the right way” utils
  114. 114. Node.js “the right way” utils • Express.js: lightweight HTTP framework
  115. 115. Node.js “the right way” utils • Express.js: lightweight HTTP framework • Sequelize: ORM de MySQL, PostgreSQL, sqlite3, etc.
  116. 116. Node.js “the right way” utils • Express.js: lightweight HTTP framework • Sequelize: ORM de MySQL, PostgreSQL, sqlite3, etc. • Mongoose: ORM de MongoDB
  117. 117. 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
  118. 118. 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
  119. 119. Repensando a infraestrutura
  120. 120. Infraestrutura do Pagar.me Router api.pagar.me Servidor da API (Node.js) Ambiente de testes (sandbox dos clientes) Ambiente de produção Servidor da API (Node.js)
  121. 121. Infraestrutura do Pagar.me Router api.pagar.me Servidor da API (Node.js) ElasticSearchElasticSearch Ambiente de testes (sandbox dos clientes) Ambiente de produção Servidor da API (Node.js)
  122. 122. Infraestrutura do Pagar.me Router api.pagar.me Servidor da API (Node.js) ElasticSearchElasticSearch MySQL (transações e dados relacionais) MySQL (transações e dados relacionais) Ambiente de testes (sandbox dos clientes) Ambiente de produção Servidor da API (Node.js)
  123. 123. Infraestrutura do Pagar.me Router api.pagar.me Servidor da API (Node.js) ElasticSearchElasticSearch MySQL (transações e dados relacionais) MySQL (transações e dados relacionais) Ambiente de testes (sandbox dos clientes) Ambiente de produção Servidor da API (Node.js) Redis + Redis +
  124. 124. Infraestrutura do Pagar.me Router api.pagar.me Servidor da API (Node.js) ElasticSearchElasticSearch MySQL (transações e dados relacionais) MySQL (transações e dados relacionais) MongoDB (dados de clientes e não relacionais) Ambiente de testes (sandbox dos clientes) Ambiente de produção Servidor da API (Node.js) Redis + Redis +
  125. 125. Por que tantos bancos?
  126. 126. Por que tantos bancos? • Separar dados de teste (sandbox dos clientes) dos dados de produção
  127. 127. 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.)
  128. 128. 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.)
  129. 129. 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)
  130. 130. 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) • Redis: fila para notificações entre serviços
  131. 131. 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) • Redis: fila para notificações entre serviços • Não há porque se prender a uma tecnologia quando cada uma delas resolve uma parte do seu problema
  132. 132. Infraestrutura do Pagar.me Router api.pagar.me Servidor da API (Node.js) ElasticSearchElasticSearch MySQL (transações e dados relacionais) MySQL (transações e dados relacionais) MongoDB (dados de clientes e não relacionais) Ambiente de testes (sandbox dos clientes) Ambiente de produção Servidor da API (Node.js) Redis + Redis +
  133. 133. Infraestrutura do Pagar.me Router api.pagar.me Servidor da API (Node.js) ElasticSearchElasticSearch MySQL (transações e dados relacionais) MySQL (transações e dados relacionais) MongoDB (dados de clientes e não relacionais) Ambiente de testes (sandbox dos clientes) Ambiente de produção Servidor da API (Node.js) Redis + Redis +
  134. 134. Microservices
  135. 135. Cliente
  136. 136. Cliente node api.js -p 3000 node gateway.js -p 5000
  137. 137. Cliente node api.js -p 3000 node gateway.js -p 5000 API RESTful (pagar.me/docs)
  138. 138. Cliente node api.js -p 3000 node gateway.js -p 5000 API RESTful (pagar.me/docs) API RESTful (serviço interno)
  139. 139. Cliente node api.js -p 3000 node gateway.js -p 5000 API RESTful (pagar.me/docs) XML, SOAP, ISO 8583, X25, sinal de fumaça… :P API RESTful (serviço interno)
  140. 140. Cliente node api.js -p 3000 node gateway.js -p 5000 API RESTful (pagar.me/docs) XML, SOAP, ISO 8583, X25, sinal de fumaça… :P ~ 550 ms API RESTful (serviço interno)
  141. 141. Cliente node api.js -p 3000 node gateway.js -p 5000 API RESTful (pagar.me/docs)~ 500ms XML, SOAP, ISO 8583, X25, sinal de fumaça… :P ~ 550 ms API RESTful (serviço interno)
  142. 142. Cliente node api.js -p 3000 node gateway.js -p 5000 API RESTful (pagar.me/docs)~ 500ms XML, SOAP, ISO 8583, X25, sinal de fumaça… :P> 5000 ms ~ 550 ms API RESTful (serviço interno)
  143. 143. Cliente node api.js -p 3000 node gateway.js -p 5000 node hookshot.js API RESTful (pagar.me/docs)~ 500ms XML, SOAP, ISO 8583, X25, sinal de fumaça… :P> 5000 ms ~ 550 ms API RESTful (serviço interno)
  144. 144. Cliente node api.js -p 3000 node gateway.js -p 5000 node hookshot.js API RESTful (pagar.me/docs)~ 500ms Redis (queue) XML, SOAP, ISO 8583, X25, sinal de fumaça… :P> 5000 ms ~ 550 ms API RESTful (serviço interno)
  145. 145. Cliente node api.js -p 3000 node gateway.js -p 5000 node hookshot.js API RESTful (pagar.me/docs)~ 500ms Redis (queue) XML, SOAP, ISO 8583, X25, sinal de fumaça… :P> 5000 ms ~ 550 ms API RESTful (serviço interno) Request HTTP para o servidor do cliente
  146. 146. Cliente node api.js -p 3000 node gateway.js -p 5000 node hookshot.js API RESTful (pagar.me/docs)~ 500ms Redis (queue) XML, SOAP, ISO 8583, X25, sinal de fumaça… :P> 5000 ms ~ 550 ms API RESTful (serviço interno) ~ 100 ms Request HTTP para o servidor do cliente
  147. 147. Deployment
  148. 148. Nível 1 $ node server.js n00bz… Processo não roda em background
  149. 149. 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
  150. 150. Nível 3 $ git pull && npm install && nohup node server.js Nohup roda o processo mesmo depois do logout do SSH
  151. 151. 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
  152. 152. Nível 5 $ service node-server restart Agora o servidor de CI lida com o Git e as dependências Servidor de Continuous Integration (CI) +
  153. 153. pm2 (https://github.com/Unitech/pm2)
  154. 154. pm2 (https://github.com/Unitech/pm2) • Roda e gerencia os processos do Node.js (mantém processo rodando para sempre)
  155. 155. 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)
  156. 156. 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
  157. 157. 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
  158. 158. 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
  159. 159. Nível 6 $ pm2 reload all Strider é o servidor de CI e o pm2 reinicia o processo on-the-fly, sem perder nenhum request Strider (servidor de CI) +
  160. 160. Nível 7 (ChatOps) $ pm2 reload all Janky é o servidor de CI, Heaven é o servidor de deployment e o pm2 reinicia o processo on-the-fly, sem perder nenhum request Janky (Jenkins) + Heaven + Hubot +
  161. 161. ChatOps
  162. 162. ChatOps • Todos os commits são testados (via Janky + Jenkins)
  163. 163. ChatOps • Todos os commits são testados (via Janky + Jenkins) • Todas as branches têm um estado (green/no-green)
  164. 164. ChatOps • Todos os commits são testados (via Janky + Jenkins) • Todas as branches têm um estado (green/no-green) • Todas as branches green podem ser deployadas (sem regressão)
  165. 165. ChatOps • Todos os commits são testados (via Janky + Jenkins) • Todas as branches têm um estado (green/no-green) • Todas as branches green podem ser deployadas (sem regressão) • Tudo acontece integrado ao GitHub
  166. 166. ChatOps • Todos os commits são testados (via Janky + Jenkins) • Todas as branches têm um estado (green/no-green) • Todas as branches green podem ser deployadas (sem regressão) • Tudo acontece integrado ao GitHub • Deploy da branch X (via Heaven) para um servidor ou grupo de servidores
  167. 167. ChatOps • Todos os commits são testados (via Janky + Jenkins) • Todas as branches têm um estado (green/no-green) • Todas as branches green podem ser deployadas (sem regressão) • Tudo acontece integrado ao GitHub • Deploy da branch X (via Heaven) para um servidor ou grupo de servidores • Tudo acontece numa sala de bate papo com todas as pessoas relacionadas ao projeto.
  168. 168. $ hubot ci build pagarme-api/boleto_upgrade
  169. 169. $ hubot ci build pagarme-api/boleto_upgrade $ hubot deploy pagarme-api/boleto_upgrade to prod-test/api01
  170. 170. $ hubot ci build pagarme-api/boleto_upgrade $ hubot deploy pagarme-api/boleto_upgrade to prod-test/api01 $ alias sharon=hubot
  171. 171. $ alias sharon=hubot $ sharon deploy pagarme-api/boleto_upgrade to prod-test/api01 $ sharon ci build pagarme-api/boleto_upgrade
  172. 172. Conclusões…
  173. 173. PEDROFRANCESCHI @pedroh96 pedro@pagar.me github.com/pedrofranceschi Obrigado! :)
  174. 174. PEDROFRANCESCHI @pedroh96 pedro@pagar.me github.com/pedrofranceschi Node.js no

×