Arquitetura Java: Escalando Alem do Hype - #BSBDevFestival

Arquitetura Java: Escalando Alem do Hype - #BSBDevFestival

(Palestra ministrada no evento #BSBDevFestival em JUN-2018)

É muito comum evangelizarem que hoje em dia uma aplicação somente escala se utilizarmos micro-serviços, containers, cloud computing e muitos outras tecnologias e práticas da moda, o tal do HYPE.

Mas será mesmo? Já se perguntou como as aplicações escalavam ANTES desse hype todo? Que tipos de práticas e tecnologias eram utilizadas? Alias, será mesmo que meu sistema web precisa escalar para centenas ou milhares de usuários?

Nessa palestra vamos entender como podemos escalar nosso sistema web SEM se levar pelo hype, partindo de práticas mais simples e baratas até as mais rebuscadas e que precisam de um maior investimento. Se você entende pouco ou quase nada sobre como escalar uma aplicação web, então essa palestra é para você!

F853760c988228c4a153333407e64f09?s=128

Rafael Ponte

June 09, 2018
Tweet

Transcript

  1. None
  2. ahh o hype…

  3. Hype-Driven Development

  4. None
  5. None
  6. None
  7. None
  8. None
  9. None
  10. None
  11. None
  12. None
  13. podemos escalar SEM o hype…

  14. Rafael Ponte @rponte

  15. None
  16. Fortaleza - Terra do Sol

  17. ARQUITETURA JAVA escalando sua aplicação além do hype

  18. Como escalar minha app para MILHARES de usuários?

  19. Loja Virtual

  20. None
  21. Revisitando a Web…

  22. servidor

  23. servidor

  24. navegador servidor

  25. navegador servidor requisição

  26. navegador servidor db requisição

  27. navegador servidor db requisição resposta

  28. navegador servidor db requisição resposta

  29. 2 conceitos importantes

  30. Performance 
 X 
 Escalabilidade

  31. tempo de resposta (response time)

  32. navegador servidor db requisição resposta

  33. navegador servidor db requisição resposta tempo resposta

  34. navegador servidor db requisição resposta tempo resposta: 100ms

  35. operações / unidade_tempo (throughput)

  36. usuários / minuto (throughput)

  37. usuários / segundo (throughput)

  38. usuários / segundo (throughput)

  39. requisições / segundo (throughput)

  40. navegador servidor db requisição resposta

  41. navegador servidor db requisição resposta tempo resposta: 100ms

  42. servidor db requisição resposta tempo resposta: 100ms

  43. servidor db requisição resposta tempo resposta: 100ms

  44. servidor db requisição resposta tempo resposta: 1s

  45. servidor db requisição resposta tempo resposta: 7s

  46. servidor db requisição resposta tempo resposta: 24s

  47. servidor db requisição resposta tempo resposta: 0

  48. nossa aplicação não escala mais do que: 80 req/s

  49. navegador servidor db requisição resposta throughput: 80 req/s

  50. navegador servidor db requisição resposta throughput: 250 req/s

  51. navegador servidor db requisição resposta throughput: 1000 req/s

  52. PASSOS 5 RESUMINDO EM

  53. Passo 1
 (TUNANDO A APLICAÇÃO)

  54. navegador servidor db requisição resposta

  55. navegador servidor db requisição resposta

  56. None
  57. None
  58. None
  59. None
  60. None
  61. None
  62. JVM

  63. None
  64. 2Gb

  65. 2Gb ???

  66. 2Gb 256Mb

  67. 2Gb ??Mb

  68. 2Gb 2Gb

  69. 2Gb 2Gb =

  70. 2Gb 2Gb = X

  71. 2Gb 1Gb

  72. 2Gb 1Gb -Xms256m -Xmx1024m 
 -XX:MaxPermSize=192m

  73. 2Gb 1Gb -Xms256m -Xmx1024m 
 -XX:MaxPermSize=192m

  74. 2Gb 1Gb -Xms256m -Xmx1024m 
 -XX:MaxPermSize=192m minimo != maximo

  75. 2Gb 1Gb -Xms1024m -Xmx1024m 
 -XX:MaxPermSize=192m minimo = maximo

  76. 2Gb 1Gb -Xms1024m -Xmx1024m 
 -XX:MaxPermSize=192m Heap Size

  77. 2Gb 1Gb -Xms1024m -Xmx1024m 
 -XX:MaxPermSize=192m

  78. 2Gb 1Gb -Xms1024m -Xmx1024m 
 -XX:MaxPermSize=192m PermGen Size

  79. 2Gb 1Gb

  80. 2Gb 1Gb -Xms1024m -Xmx1024m 
 -XX:MaxPermSize=192m memoria

  81. 2Gb 1Gb -Xms1024m -Xmx1024m 
 -XX:MaxPermSize=192m -server modo servidor memoria

  82. 2Gb 1Gb -Xms1024m -Xmx1024m 
 -XX:MaxPermSize=192m -XX:+UseConcMarkSweepGC
 -XX:+CMSParallelRemarkEnabled -server modo

    servidor memoria coletor de lixo (GC)
  83. Ganhou fôlego, mas…

  84. navegador servidor db requisição resposta

  85. servidor Aplicação

  86. servidor

  87. servidor Produto.java Venda.java BancoDeDados.java FinalizarCompra.java Pagamento.java carrinhoDeCompras.jsp index.jsp site.css app.js

    GravaProduto.java EnviaEmail.java GravaProdutoServlet.java finalizar-compra.jsp
  88. servidor

  89. servidor

  90. servidor

  91. Divisão de Camadas

  92. servidor

  93. servidor modelo

  94. servidor modelo telas

  95. servidor modelo acesso a dados telas

  96. servidor apresentação negócio persistência camadas

  97. servidor apresentação negócio persistência controle das telas camadas

  98. servidor apresentação negócio persistência controle das telas logica de negocio

    camadas
  99. servidor apresentação negócio persistência controle das telas logica de negocio

    acesso a banco e dados camadas
  100. servidor apresentação negócio persistência camadas

  101. servidor apresentação negócio persistência camadas

  102. servidor apresentação negócio persistência camadas

  103. servidor apresentação negócio persistência camadas

  104. servidor apresentação negócio persistência camadas

  105. navegador servidor db requisição resposta

  106. navegador servidor db requisição resposta tempo resposta: 1000ms

  107. navegador servidor db requisição resposta tempo resposta: 1000ms 700ms

  108. navegador servidor db requisição resposta tempo resposta: 1000ms 700ms

  109. servidor db

  110. db apresentação negócio persistência

  111. db apresentação negócio persistência Transaction Response Time

  112. db T = apresentação negócio persistência

  113. db T = Tacq apresentação negócio persistência

  114. db T = Tacq + Treq apresentação negócio persistência

  115. db T = Tacq + Treq + Texec apresentação negócio

    persistência
  116. db T = Tacq + Treq + Texec + Tres

    apresentação negócio persistência
  117. db T = Tacq + Treq + Texec + Tres

    + Tidle apresentação negócio persistência
  118. quanto menor o response time, maior o throughput

  119. db T = Tacq + Treq + Texec + Tres

    + Tidle apresentação negócio persistência
  120. navegador servidor db

  121. navegador servidor db 1 requisição 1 conexão

  122. navegador servidor db 10 requisições 10 conexões

  123. navegador servidor db 100 requisições 100 conexões

  124. navegador servidor db 1000 requisições 1000 conexões

  125. navegador servidor db 1001 requisições 0 conexões

  126. Criar conexões é CARO!

  127. navegador db app

  128. navegador db app

  129. navegador db app

  130. navegador db app ini=5

  131. db app ini=5

  132. db app … max=30 ini=5

  133. db app min=3 max=30 ini=5

  134. navegador db connection pool app min=3 max=30 ini=5 …

  135. quanto mais rápido obter uma conexão, menor o response time

  136. mas qual o tamanho ideal do pool?

  137. https://mobile.twitter.com/Nick_Craver/status/969043553711218691

  138. mensure!

  139. db T = Tacq + Treq + Texec + Tres

    + Tidle apresentação negócio persistência
  140. Habilite o Batch Size

  141. @Entity public class Produto { @Id @GeneratedValue private Integer id;

    private String nome; // outros atributos }
  142. List<Produto> produtos = //... for (Produto p : produtos) {

    entityManager.persist(p); } Persistindo várias entidades
  143. INSERT INTO produto(nome, id) VALUES (‘Prod.1', 1) INSERT INTO produto(nome,

    id) VALUES (‘Prod.2', 2) INSERT INTO produto(nome, id) VALUES (‘Prod.3', 3) INSERT INTO ... 3 roundtrips
  144. <property name="hibernate.jdbc.batch_size" value="5" /> persistence.xml

  145. List<Produto> produtos = //... for (Produto p : produtos) {

    entityManager.persist(p); } Persistindo várias entidades
  146. Query : ["INSERT INTO produto(nome, id) VALUES (?, ?)"] Params:

    [(‘Prod.1', 1), (‘Prod.2', 2), (‘Prod.3', 3)] 1 roundtrip
  147. Para UPDATE e DELETE também

  148. List<Produto> produtos = //... for (Produto p : produtos) {

    p.setNome(p.getNome() .toUpperCase()); } Atualizando várias entidades
  149. Query : [“UPDATE produto SET nome = ? WHERE id

    = ?”] Params: [(‘PROD.1', 1), (‘PROD.2', 2), (‘PROD.3', 3)] 1 roundtrip
  150. List<Produto> produtos = //... for (Produto p : produtos) {

    entityManager.remove(p); } Removendo várias entidades
  151. Query : [“DELETE FROM produto WHERE id = ?”] Params:

    [(1), (2), (3)] 1 roundtrip
  152. quanto menos roundtrips ao banco, menor o response time

  153. AUTO-INCREMENTO (batch_size não funciona)

  154. db T = Tacq + Treq + Texec + Tres

    + Tidle apresentação negócio persistência
  155. Use Consultas Planejadas (DTO Projections)

  156. @Entity class NotaFiscal { … @OneToMany List<Item> itens; }

  157. NotaFiscal nf = entityManager .find(NotaFiscal.class, 42); 
 processaItensDaNota(nf); Processando os

    itens de uma nota
  158. Processando os itens de uma nota NotaFiscal nf = entityManager

    .find(NotaFiscal.class, 42); 
 processaItensDaNota(nf);
  159. SELECT nf.* FROM NotaFiscal nf WHERE nf.id = 42 SELECT

    i.* FROM Item i WHERE i.nota_fiscal_id = 42 Hibernate executa 2 selects NotaFiscal nf = entityManger.find(NotaFiscal.class, 42); processaItensDaNota(nf);
  160. List<NotaFiscal> notas = dao.lista(); for (NotaFiscal nf : notas) {

    processaItensDaNota(nf); } Processando os itens de varias notas
  161. Processando os itens de varias notas List<NotaFiscal> notas = dao.lista();

    for (NotaFiscal nf : notas) { processaItensDaNota(nf); }
  162. SELECT nf.* FROM NotaFiscal nf SELECT i.* FROM Item i

    WHERE i.nota_fiscal_id=? SELECT i.* FROM Item i WHERE i.nota_fiscal_id=? SELECT i.* FROM Item i WHERE i.nota_fiscal_id=? SELECT i.* FROM Item i WHERE i.nota_fiscal_id=? SELECT i.* FROM Item i WHERE i.nota_fiscal_id=? ... Hibernate executa n+1 selects List<NotaFiscal> notas = dao.lista(); for (NotaFiscal nf : notas) { processaItensDaNota(nf); }
  163. são muitos hits ao banco (Select N+1)

  164. solução?

  165. @Entity class NotaFiscal { … @OneToMany(fetch=FetchType.EAGER) List<Item> itens; } Utilizando

    FetchMode=EAGER
  166. SELECT nf.*, i.* FROM NotaFiscal nf LEFT OUTER JOIN Item

    i ON nf.id = i.nota_fiscal_id
 Hibernate executa 1 select List<NotaFiscal> notas = dao.lista();
  167. antes de definir um mapeamento global deste tipo você precisa

    se perguntar...
  168. SEMPRE que uma nota é carregada, todos seus itens também

    são necessários?
  169. não?

  170. @Entity class NotaFiscal { … @OneToMany(fetch=FetchType.LAZY) List<Item> itens; } Utilizando

    FetchMode=LAZY
  171. entityManager
 .createQuery( " SELECT n FROM NotaFiscal n LEFT JOIN

    fetch n.itens")
 .getResultList(); Utilizando Join Fetch
  172. entityManager
 .createQuery( " SELECT n FROM NotaFiscal n LEFT JOIN

    fetch n.itens")
 .getResultList(); Utilizando Join Fetch LAZY permite mudar para EAGER
  173. Opa! Não para aí…

  174. SEMPRE que uma nota é carregada, TODAS as colunas são

    necessárias?
  175. não?

  176. List<NotaFiscal> notas = entityManager
 .createQuery( " SELECT n.numero, n.serie FROM

    NotaFiscal n WHERE n.tipo = 'DEVOLUCAO'")
 .getResultList(); DTO Projections
  177. List<NotaFiscal> notas = entityManager
 .createQuery( " SELECT n.numero, n.serie FROM

    NotaFiscal n WHERE n.tipo = 'DEVOLUCAO'") .getResultList(); DTO Projections
  178. List<?????> notas = entityManager
 .createQuery( " SELECT n.numero, n.serie FROM

    NotaFiscal n WHERE n.tipo = 'DEVOLUCAO'") .getResultList(); DTO Projections
  179. class Devolucao { Integer numero; String serie; public Devolucao(Integer n,

    String s) { this.numero = n; this.serie = s; } // getters e setters } Criando o DTO
  180. List<Devolucao> notas = entityManager
 .createQuery( " SELECT n.numero, n.serie FROM

    NotaFiscal n WHERE n.tipo = 'DEVOLUCAO'") .getResultList(); DTO Projections
  181. List<Devolucao> notas = entityManager
 .createQuery( " SELECT new Devolucao(n.numero, n.serie)

    FROM NotaFiscal n WHERE n.tipo = 'DEVOLUCAO'") .getResultList(); DTO Projections
  182. SELECT nf.numero, nf.serie FROM NotaFiscal nf WHERE nf.tipo = 'DEVOLUCAO'

    SQL otimizado List<NotaFiscal> notas = //...
  183. quanto menor a quantidade de dados recuperados, menor o response

    time
  184. db T = Tacq + Treq + Texec + Tres

    + Tidle apresentação negócio persistência
  185. Como otimizar minha query?

  186. SQL Nativo (deixe seu banco trabalhar)

  187. Stored Procedures (leve o processamento para os dados)

  188. DBA (peça ajuda)

  189. mesmo com todas essas melhorias…

  190. picos de acessos podem aumentar nosso response time

  191. Caching (aliviando o banco de dados)

  192. NotaFiscal nf = entityManager .find(NotaFiscal.class, 42); 
 Carregando uma nota

    por ID
  193. SELECT nf.* FROM NotaFiscal nf WHERE nf.id = 42 Hibernate

    executa 1 select NotaFiscal nf = entityManger.find(NotaFiscal.class, 42);
  194. NotaFiscal nf1 = entityManager .find(NotaFiscal.class, 42); 
 NotaFiscal nf2 =

    entityManager .find(NotaFiscal.class, 42); NotaFiscal nf3 = entityManager .find(NotaFiscal.class, 42); Carregando uma nota por ID
  195. SELECT nf.* FROM NotaFiscal nf WHERE nf.id = 42 Hibernate

    executa 1 select NotaFiscal nf1 = entityManger.find(NotaFiscal.class, 42); NotaFiscal nf2 = entityManger.find(NotaFiscal.class, 42); NotaFiscal nf3 = entityManger.find(NotaFiscal.class, 42); // sem SQL // sem SQL
  196. Banco de Dados EM

  197. Banco de Dados EM First Level Cache

  198. Banco de Dados EM EM EM EM

  199. Banco de Dados ???? EM EM EM EM

  200. Banco de Dados Second Level Cache EM EM EM EM

  201. Banco de Dados Second Level Cache EM Session Session First

    Level Cache Session EM EM EM
  202. Banco de Dados EntityManagerFactory EM EM EM EM

  203. <property name="hibernate.cache.second_level_cache" value="true" /> <property name="hibernate.cache.region.factory_class" value="net.sf...EhCacheRegionFactory" /> persistence.xml #1

    habilitamos o cache
  204. @Entity @Cache(usage=CacheConcurrencyStrategy.READ_WRITE) class Produto { @Id private Long id; private

    String nome; } #2 configuramos as entidades
  205. @Cache( usage=CacheConcurrencyStrategy.READ_WRITE) Caching Strategy READ_ONLY NONSTRICT_READ_WRITE READ_WRITE

  206. @Cache( usage=CacheConcurrencyStrategy.READ_WRITE) Caching Strategy READ_ONLY NONSTRICT_READ_WRITE READ_WRITE Melhor performance

  207. @Cache( usage=CacheConcurrencyStrategy.READ_WRITE) Caching Strategy READ_ONLY NONSTRICT_READ_WRITE READ_WRITE Dados não críticos

  208. @Cache( usage=CacheConcurrencyStrategy.READ_WRITE) Caching Strategy READ_ONLY NONSTRICT_READ_WRITE READ_WRITE Modificações frequentes

  209. <cache name="br.com.app.model.Produto" maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="1800" timeToLiveSeconds="10000" overflowToDisk="true" memoryStoreEvictionPolicy="LRU" /> ehcache.xml

  210. db T = Tacq + Treq + Texec + Tres

    + Tidle apresentação negócio persistência
  211. db apresentação negócio persistência

  212. db apresentação negócio persistência

  213. db negócio persistência apresentação

  214. “There are only two hard things in Computer Science: cache

    invalidation and naming things.” — Phil Karlton
  215. navegador servidor db requisição resposta Performance Consistência

  216. Assincronicidade (processa mais tarde)

  217. @Controller public class PedidoController { @Autowired public PedidoService service; @PostMapping(path="/vendas/finaliza",

    ...) public void finalizaPedido(Pedido pedido) { // faz alguma validação de dados 
 service.finaliza(pedido); // demorado... } }
  218. @Controller public class PedidoController { @Autowired public PedidoService service; @PostMapping(path="/vendas/finaliza",

    ...) public void finalizaPedido(Pedido pedido) { // faz alguma validação de dados 
 service.finaliza(pedido); // demorado... } }
  219. @Service public class PedidoService { public void finaliza(Pedido pedido) {


    // efetua pagamento // dá baixa no estoque // atualiza pedido // envia email de confirmação } }
  220. se a execução é custosa então é um possível gargalo…

  221. @Service public class PedidoService { @Async public void finaliza(Pedido pedido)

    {
 // efetua pagamento // dá baixa no estoque // atualiza pedido // envia email de confirmação } }
  222. Spring usa um pool de threads

  223. @Controller public class PedidoController { @Autowired public PedidoService service; @PostMapping(path="/vendas/finaliza",

    ...) public void finalizaPedido(Pedido pedido) { // faz alguma validação de dados 
 service.finaliza(pedido); // imediato!! } }
  224. mas poderíamos usar uma fila…

  225. @Service public class PedidoService { @Autowired private JmsTemplate fila; public

    void finaliza(Pedido pedido) { fila.convertAndSend("fila.pedidos", pedido);
 } }
  226. @Service public class PedidoService { @Autowired private JmsTemplate fila; public

    void finaliza(Pedido pedido) { fila.convertAndSend("fila.pedidos", pedido);
 } }
  227. e em algum momento um processo consumiria a fila…

  228. @Service public class ProcessadorDePedidos { @JmsListener(destination="fila.pedidos") public void processa(Pedido pedido)

    {
 // efetua pagamento // dá baixa no estoque // atualiza pedido // envia email de confirmação } }
  229. no fim nossa requisição responderia imediatamente

  230. @Controller public class PedidoController { @Autowired public PedidoService service; @PostMapping(path="/vendas/finaliza",

    ...) public void finalizaPedido(Pedido pedido) { // faz alguma validação de dados 
 service.finaliza(pedido); // imediato!! } }
  231. Wow!!

  232. 1) tunamos a JVM; 2) tunanamos a camada de persistência;

    3) adicionamos caching; 4) adicionamos processamento assincrono;
  233. 1) tunamos a JVM; 2) tunanamos a camada de persistência;

    3) adicionamos caching; 4) adicionamos processamento assincrono;
  234. 1) tunamos a JVM; 2) tunanamos a camada de persistência;

    3) adicionamos caching; 4) adicionamos processamento assincrono;
  235. 1) tunamos a JVM; 2) tunanamos a camada de persistência;

    3) adicionamos caching; 4) adicionamos processamento assincrono;
  236. Sistema 
 não aguenta?

  237. Passo 2
 (MELHORANDO A MÁQUINA)

  238. navegador servidor db requisição resposta

  239. navegador servidor db requisição resposta

  240. cpu memoria

  241. None
  242. None
  243. X

  244. None
  245. None
  246. None
  247. x 6 x 6

  248. Mais requisições?

  249. None
  250. None
  251. None
  252. Escalabilidade Vertical (scale up)

  253. None
  254. None
  255. None
  256. None
  257. None
  258. None
  259. None
  260. X

  261. Sistema 
 não aguenta?

  262. Passo 3
 (ADICIONANDO MAIS MÁQUINAS)

  263. navegador servidor db requisição resposta

  264. navegador servidor db requisição resposta

  265. None
  266. =

  267. None
  268. None
  269. None
  270. ip?

  271. None
  272. None
  273. None
  274. 200 reqs

  275. 200 reqs 100 reqs 100 reqs

  276. Balanceador de Carga

  277. Balanceador de Carga

  278. Balanceador de Carga

  279. None
  280. Mais requisições?

  281. None
  282. None
  283. None
  284. None
  285. Cluster

  286. None
  287. None
  288. Escalabilidade Horizontal (scale out)

  289. Apesar de mais barata…

  290. None
  291. (1a requisição)

  292. (1a requisição)

  293. Sessão

  294. (2a requisição) qual?

  295. (2a requisição)

  296. (2a requisição)

  297. Sticky Session

  298. Mas e se…

  299. None
  300. None
  301. None
  302. None
  303. None
  304. None
  305. ?

  306. ?

  307. Falta Redundância

  308. Passo 4
 (REPLICANDO ESTADO)

  309. None
  310. (1a requisição)

  311. (1a requisição)

  312. (2a requisição)

  313. (2a requisição) qual?

  314. (2a requisição)

  315. (2a requisição)

  316. None
  317. Session Replication

  318. None
  319. None
  320. None
  321. None
  322. Replica Estado

  323. None
  324. Alta Disponibilidade (high availability)

  325. Mais requisições?

  326. None
  327. None
  328. None
  329. None
  330. Se tenho mais máquinas…

  331. None
  332. None
  333. None
  334. None
  335. Replicar sessão é CARO

  336. Passo 5
 (REMOVENDO ESTADO)

  337. None
  338. None
  339. None
  340. None
  341. None
  342. ONDE?

  343. None
  344. None
  345. None
  346. None
  347. Cache Distribuído

  348. Cache Distribuído

  349. Cache Distribuído

  350. None
  351. STATELESS (shared nothing architecture)

  352. None
  353. None
  354. None
  355. Mais requisições?

  356. None
  357. 256GB

  358. 256GB 256GB

  359. Recapitulando…

  360. tunando sua aplicação

  361. tunando sua aplicação melhorando sua máquina

  362. tunando sua aplicação adicionando máquinas melhorando sua máquina

  363. tunando sua aplicação replicando estado adicionando máquinas melhorando sua máquina

  364. tunando sua aplicação replicando estado adicionando máquinas melhorando sua máquina

    removendo estado
  365. Todas plataformas

  366. CACHE

  367. CACHE PROCESSAMENTO ASSINCRONO

  368. CACHE BALANCEAMENTO DE CARGA PROCESSAMENTO ASSINCRONO

  369. Não escala ainda…

  370. Nuvens

  371. None
  372. e só então…

  373. None
  374. OBRIGADO!

  375. @rponte http://triadworks.com.br/ @triadworks