$30 off During Our Annual Pro Sale. View Details »

Fault-Tolerant Clients: Escrevendo Clients e Services Tolerantes a Falhas

Rafael Ponte
September 23, 2020

Fault-Tolerant Clients: Escrevendo Clients e Services Tolerantes a Falhas

Com a moda de microservices a industria de software voltou a favorecer o desenvolvimento de sistemas altamente distribuídos, o que possibilitou melhorar a cadência nas entregas dos times e também escalar componentes de maneira independente e isolada. Apesar das vantagens, muitos trade-offs foram colocados na mesa, agora o desenvolvedor precisa lidar com maior complexidade nas integrações e principalmente lidar com os percalços de uma rede instável, com atrasos e falhas parciais.

É justamente essa instabilidade na rede que tira sistemas do ar e, cedo ou tarde, leva a falhas em cascata. Agora, o que era simples não é mais: uma troca de mensagem entre módulos deixou de ser uma chamada de método em memória para se tornar uma jornada lenta e cheia de problemas na rede. Entender a diferença entre escrever código com chamadas locais e remotas é essencial nesse mundo de processos, máquinas e regiões interconectados por protocolos, switches e roteadores na rede.

Por esse motivo, nessa talk, pretendo discutir como nós desenvolvedores podemos escrever sistemas e serviços mais resilientes e tolerantes a falhas, trazendo assim alguma estabilidade dentro desses ambientes distribuídos e instáveis por natureza.

(GRAVAÇÃO: https://youtu.be/TMmN9cR_IsM?list=PLHMMERsvy9EyWQPru4SrJAYHEGKfkjRgP&t=481)

Rafael Ponte

September 23, 2020
Tweet

More Decks by Rafael Ponte

Other Decks in Technology

Transcript

  1. FAULT-TOLERANT CLIENTS Implementando clients e services mais resilientes e tolerantes

    a falhas
  2. O que é um Sistema Tolerante a Falhas? 


  3. https://deniseyu.io/art/

  4. https://deniseyu.io/art/

  5. https://deniseyu.io/art/

  6. Desenhando sistemas distribuídos…

  7. None
  8. None
  9. None
  10. None
  11. Spring Boot App

  12. Spring Boot App

  13. Spring Boot App Client Service

  14. Spring Boot App Client Service

  15. Spring Boot App Client Service Local Calls

  16. Spring Boot App Client Service Local Calls

  17. Spring Boot App Client Service Local Calls

  18. Spring Boot App Client Service Local Calls Mas não aqui!

  19. Spring Boot App Client Service Local Calls Mas não aqui!

  20. Spring Boot App Client Service Local Calls

  21. Em contrapartida…

  22. Spring Boot App Spring Boot App

  23. Spring Boot App Spring Boot App Client

  24. Spring Boot App Spring Boot App Client Service

  25. Spring Boot App Spring Boot App Client Service 
 Internet

  26. Spring Boot App Spring Boot App Client Service 
 Internet

  27. Spring Boot App Spring Boot App Client Service 
 Internet

    Remote Calls
  28. Spring Boot App Spring Boot App Client Service 
 Internet

    Remote Calls
  29. Spring Boot App Client Spring Boot App Service 
 Internet

    Remote Calls
  30. Spring Boot App Client Spring Boot App Service 
 Internet

    Remote Calls
  31. Spring Boot App Client Spring Boot App Service 
 Internet

    Remote Calls
  32. Spring Boot App Client Spring Boot App Service 
 Internet

    Remote Calls
  33. Spring Boot App Client Spring Boot App Service 
 Internet

    Remote Calls
  34. Spring Boot App Spring Boot App 
 Internet Client Service

    Remote Calls
  35. https://deniseyu.io/art/

  36. https://deniseyu.io/art/

  37. https://deniseyu.io/art/

  38. https://deniseyu.io/art/

  39. https://deniseyu.io/art/

  40. None
  41. Por que isso importa?

  42. Spring Boot App Spring Boot App Spring Boot App 


    Local Calls Remote Calls
  43. Spring Boot App Spring Boot App Spring Boot App 


    Centralized System Distributed System
  44. Spring Boot App Spring Boot App Spring Boot App 


    Centralized System Distributed System
  45. — Martin Fowler First Law of Distributed Object Design: 


    "don’t distribute your objects"
  46. Mas se não tiver jeito…

  47. Spring Boot App Client Spring Boot App Service 
 Internet

    Distributed System
  48. Spring Boot App Client Spring Boot App Service 
 Internet

    Distributed System
  49. None
  50. Distributed System Spring Boot App Client Spring Boot App Service

    
 Internet
  51. Distributed System Spring Boot App Client Spring Boot App Service

    
 Internet
  52. @RestController public class CalculadoraDeFretesController { @GetMapping(path="/fretes/calcula") public ResponseEntity<Frete> calcula(@RequestParam String

    cep) { // consulta frete em outro microsserviço String url = "https://ms.fast-fretes.com/calcula-frete/" ; 
 ZupHttpClient<Frete> client = new ZupHttpClient<>() ; Frete frete = client.get(url ) .withParameter("cep", cep ) .execute();
 return ResponseEntity.ok(frete); } }
  53. @RestController public class CalculadoraDeFretesController { @GetMapping(path="/fretes/calcula") public ResponseEntity<Frete> calcula(@RequestParam String

    cep) { // consulta frete em outro microsserviço String url = "https://ms.fast-fretes.com/calcula-frete/" ; 
 ZupHttpClient<Frete> client = new ZupHttpClient<>() ; Frete frete = client.get(url ) .withParameter("cep", cep ) .execute();
 return ResponseEntity.ok(frete); } }
  54. @RestController public class CalculadoraDeFretesController { @GetMapping(path="/fretes/calcula") public ResponseEntity<Frete> calcula(@RequestParam String

    cep) { // consulta frete em outro microsserviço String url = "https://ms.fast-fretes.com/calcula-frete/" ; 
 ZupHttpClient<Frete> client = new ZupHttpClient<>() ; Frete frete = client.get(url ) .withParameter("cep", cep ) .execute();
 return ResponseEntity.ok(frete); } }
  55. @RestController public class CalculadoraDeFretesController { @GetMapping(path="/fretes/calcula") public ResponseEntity<Frete> calcula(@RequestParam String

    cep) { // consulta frete em outro microsserviço String url = "https://ms.fast-fretes.com/calcula-frete/" ; 
 ZupHttpClient<Frete> client = new ZupHttpClient<>() ; Frete frete = client.get(url ) .withParameter("cep", cep ) .execute();
 return ResponseEntity.ok(frete); } }
  56. @RestController public class CalculadoraDeFretesController { @GetMapping(path="/fretes/calcula") public ResponseEntity<Frete> calcula(@RequestParam String

    cep) { // consulta frete em outro microsserviço String url = "https://ms.fast-fretes.com/calcula-frete/" ; 
 ZupHttpClient<Frete> client = new ZupHttpClient<>() ; Frete frete = client.get(url ) .withParameter("cep", cep ) .execute();
 return ResponseEntity.ok(frete); } }
  57. @RestController public class CalculadoraDeFretesController { @GetMapping(path="/fretes/calcula") public ResponseEntity<Frete> calcula(@RequestParam String

    cep) { // consulta frete em outro microsserviço String url = "https://ms.fast-fretes.com/calcula-frete/" ; 
 ZupHttpClient<Frete> client = new ZupHttpClient<>() ; Frete frete = client.get(url ) .withParameter("cep", cep ) .execute();
 return ResponseEntity.ok(frete); } }
  58. @RestController public class CalculadoraDeFretesController { @GetMapping(path="/fretes/calcula") public ResponseEntity<Frete> calcula(@RequestParam String

    cep) { // consulta frete em outro microsserviço String url = "https://ms.fast-fretes.com/calcula-frete/" ; 
 ZupHttpClient<Frete> client = new ZupHttpClient<>() ; Frete frete = client.get(url ) .withParameter("cep", cep ) .execute();
 return ResponseEntity.ok(frete); } }
  59. @RestController public class CalculadoraDeFretesController { @GetMapping(path="/fretes/calcula") public ResponseEntity<Frete> calcula(@RequestParam String

    cep) { // consulta frete em outro microsserviço String url = "https://ms.fast-fretes.com/calcula-frete/" ; 
 ZupHttpClient<Frete> client = new ZupHttpClient<>() ; Frete frete = client.get(url ) .withParameter("cep", cep ) .execute();
 return ResponseEntity.ok(frete); } }
  60. @RestController public class CalculadoraDeFretesController { @GetMapping(path="/fretes/calcula") public ResponseEntity<Frete> calcula(@RequestParam String

    cep) { // consulta frete em outro microsserviço String url = "https://ms.fast-fretes.com/calcula-frete/" ; 
 ZupHttpClient<Frete> client = new ZupHttpClient<>() ; Frete frete = client.get(url ) .withParameter("cep", cep ) .execute();
 return ResponseEntity.ok(frete); } }
  61. @RestController public class CalculadoraDeFretesController { @GetMapping(path="/fretes/calcula") public ResponseEntity<Frete> calcula(@RequestParam String

    cep) { // consulta frete em outro microsserviço String url = "https://ms.fast-fretes.com/calcula-frete/" ; 
 ZupHttpClient<Frete> client = new ZupHttpClient<>() ; Frete frete = client.get(url ) .withParameter("cep", cep ) .execute();
 return ResponseEntity.ok(frete); } }
  62. @RestController public class CalculadoraDeFretesController { @GetMapping(path="/fretes/calcula") public ResponseEntity<Frete> calcula(@RequestParam String

    cep) { // consulta frete em outro microsserviço String url = "https://ms.fast-fretes.com/calcula-frete/" ; 
 ZupHttpClient<Frete> client = new ZupHttpClient<>() ; Frete frete = client.get(url ) .withParameter("cep", cep ) .execute();
 return ResponseEntity.ok(frete); } }
  63. @RestController public class CalculadoraDeFretesController { @GetMapping(path="/fretes/calcula") public ResponseEntity<Frete> calcula(@RequestParam String

    cep) { // consulta frete em outro microsserviço String url = "https://ms.fast-fretes.com/calcula-frete/" ; 
 ZupHttpClient<Frete> client = new ZupHttpClient<>() ; Frete frete = client.get(url ) .withParameter("cep", cep ) .execute();
 return ResponseEntity.ok(frete); } }
  64. Design for Failures

  65. Rafael Ponte @rponte

  66. None
  67. Fortaleza - Terra do Sol

  68. None
  69. FAULT-TOLERANT CLIENTS Implementando clients e services mais resilientes e tolerantes

    a falhas
  70. Implementação Ingênua

  71. @RestController public class CalculadoraDeFretesController { @GetMapping(path="/fretes/calcula") public ResponseEntity<Frete> calcula(@RequestParam String

    cep) { // consulta frete em outro microsserviço String url = "https://ms.fast-fretes.com/calcula-frete/" ; 
 ZupHttpClient<Frete> client = new ZupHttpClient<>() ; Frete frete = client.get(url ) .withParameter("cep", cep ) .execute();
 return ResponseEntity.ok(frete); } }
  72. @RestController public class CalculadoraDeFretesController { @GetMapping(path="/fretes/calcula") public ResponseEntity<Frete> calcula(@RequestParam String

    cep) { // consulta frete em outro microsserviço String url = "https://ms.fast-fretes.com/calcula-frete/" ; 
 ZupHttpClient<Frete> client = new ZupHttpClient<>() ; Frete frete = client.get(url ) .withParameter("cep", cep ) .execute();
 return ResponseEntity.ok(frete); } }
  73. @RestController public class CalculadoraDeFretesController { @GetMapping(path="/fretes/calcula") public ResponseEntity<Frete> calcula(@RequestParam String

    cep) { // consulta frete em outro microsserviço String url = "https://ms.fast-fretes.com/calcula-frete/" ; 
 ZupHttpClient<Frete> client = new ZupHttpClient<>() ; Frete frete = client.get(url ) .withParameter("cep", cep ) .execute();
 return ResponseEntity.ok(frete); } }
  74. ZupHttpClient<Frete> client = new ZupHttpClient<>() ; Frete frete = client.get(url

    ) .withParameter("cep", cep ) .execute();
  75. ZupHttpClient<Frete> client = new ZupHttpClient<>() ; Frete frete = client.get(url

    ) .withParameter("cep", cep ) .execute();
  76. ZupHttpClient<Frete> client = new ZupHttpClient<>() ; Frete frete = client.get(url

    ) .withParameter("cep", cep ) .execute();
  77. ZupHttpClient<Frete> client = new ZupHttpClient<>() ; Frete frete = client.get(url

    ) .withParameter("cep", cep ) .execute(); Pode ser qualquer HTTP Client!
  78. ZupHttpClient<Frete> client = new ZupHttpClient<>() ; Frete frete = client.get(url

    ) .withParameter("cep", cep ) .execute();
  79. ZupHttpClient<Frete> client = new ZupHttpClient<>() ; Frete frete = client.get(url

    ) .withParameter("cep", cep ) .execute();
  80. ZupHttpClient<Frete> client = new ZupHttpClient<>() ; Frete frete = client.get(url

    ) .withParameter("cep", cep ) .execute();
  81. O problema dessa implementação…

  82. Spring Boot App Client Spring Boot App Service 
 Internet

  83. Spring Boot App Client Spring Boot App Service 
 Internet

  84. Spring Boot App Client Spring Boot App Service 
 Internet

  85. Spring Boot App Client Spring Boot App Service 
 Internet

  86. Spring Boot App Client Spring Boot App Service 
 Internet

  87. Spring Boot App Client Spring Boot App Service 
 Internet

  88. Spring Boot App Client Spring Boot App Service 
 Internet

  89. Spring Boot App Client Spring Boot App Service 
 Internet

  90. Spring Boot App Client Spring Boot App Service 
 Internet

  91. Spring Boot App Client Spring Boot App Service 
 Internet

  92. Spring Boot App Client Spring Boot App Service 
 Internet

  93. Spring Boot App Client Spring Boot App Service 
 Internet

  94. Spring Boot App Client Spring Boot App Service 
 Internet

  95. Spring Boot App Client Spring Boot App Service 
 Internet

  96. Spring Boot App Client Spring Boot App Service 
 Internet

  97. Spring Boot App Client Spring Boot App Service 
 Internet

  98. Spring Boot App Client Spring Boot App Service 
 Internet

  99. None
  100. None
  101. Tudo isso porque esperamos demais…

  102. Timeout

  103. ZupClientConfig config = // ... ZupClientConfig.custom( ) .withRequestTimeout(Duration.of(5, SECONDS) )

    .build() ; ZupHttpClient<Frete> client = new ZupHttpClient<>() ; Frete frete = client.get(url ) .withParameter("cep", cep ) .execute();
  104. ZupClientConfig config = // ... .withRequestTimeout(Duration.of(5, SECONDS) ) .build() ;

    ZupHttpClient<Frete> client = new ZupHttpClient<>() ; Frete frete = client.get(url ) .withParameter("cep", cep ) .execute();
  105. ZupClientConfig config = // ... .withRequestTimeout(Duration.of(5, SECONDS) ) .build() ;

    ZupHttpClient<Frete> client = new ZupHttpClient<>(config) ; Frete frete = client.get(url ) .withParameter("cep", cep ) .execute();
  106. ZupClientConfig config = ZupClientConfig.custom( ) .withRequestTimeout(Duration.of(5, SECONDS) ) .build() ;

    ZupHttpClient<Frete> client = new ZupHttpClient<>(config) ; Frete frete = client.get(url ) .withParameter("cep", cep ) .execute();
  107. ZupClientConfig config = ZupClientConfig.custom( ) .withRequestTimeout(Duration.of(5, SECONDS) ) .build() ;

    ZupHttpClient<Frete> client = new ZupHttpClient<>(config) ; Frete frete = client.get(url ) .withParameter("cep", cep ) .execute();
  108. ZupClientConfig config = ZupClientConfig.custom( ) .withRequestTimeout(Duration.of(5, SECONDS) ) .build() ;

    ZupHttpClient<Frete> client = new ZupHttpClient<>(config) ; Frete frete = client.get(url ) .withParameter("cep", cep ) .execute();
  109. ZupClientConfig config = ZupClientConfig.custom( ) .withRequestTimeout(Duration.of(5, SECONDS) ) .build() ;

    ZupHttpClient<Frete> client = new ZupHttpClient<>(config) ; Frete frete = client.get(url ) .withParameter("cep", cep ) .execute(); Depende do caso de uso e contexto
  110. ZupClientConfig config = ZupClientConfig.custom( ) .withRequestTimeout(Duration.of(5, SECONDS) ) .build() ;

    ZupHttpClient<Frete> client = new ZupHttpClient<>(config) ; Frete frete = client.get(url ) .withParameter("cep", cep ) .execute();
  111. Spring Boot App Client Spring Boot App Service 
 Internet

  112. Spring Boot App Client Spring Boot App Service 
 Internet

  113. Spring Boot App Client Spring Boot App Service 
 Internet

  114. Spring Boot App Client Spring Boot App Service 
 Internet

  115. Spring Boot App Client Spring Boot App Service 
 Internet

  116. Fail Fast

  117. …mas não para Transient Failures

  118. Spring Boot App Client Spring Boot App Service 
 Internet

  119. Spring Boot App Client Spring Boot App Service 
 Internet

  120. Spring Boot App Client Spring Boot App Service 
 Internet

  121. Spring Boot App Client Spring Boot App Service 
 Internet

  122. Spring Boot App Client Spring Boot App Service 
 Internet

  123. Spring Boot App Client Spring Boot App Service 
 Internet

  124. Não podemos jogar esse problema no usuário…

  125. Retry

  126. ZupClientConfig config = ZupClientConfig.custom( ) .withRequestTimeout(Duration.of(5, SECONDS) ) .build() ;

    ZupHttpClient<Frete> client = new ZupHttpClient<>(config) ; Frete frete = client.get(url ) .withParameter("cep", cep ) .execute();
  127. ZupClientConfig config = ZupClientConfig.custom( ) .withRequestTimeout(Duration.of(5, SECONDS) ) .withRetryPolicy( )

    .build() ; ZupHttpClient<Frete> client = new ZupHttpClient<>(config) ; Frete frete = client.get(url ) .withParameter("cep", cep ) .execute();
  128. ZupClientConfig config = ZupClientConfig.custom( ) .withRequestTimeout(Duration.of(5, SECONDS) ) .withRetryPolicy(RetryPolicy.custom().build() )

    .build() ; ZupHttpClient<Frete> client = new ZupHttpClient<>(config) ; Frete frete = client.get(url ) .withParameter("cep", cep ) .execute();
  129. ZupClientConfig config = ZupClientConfig.custom( ) .withRequestTimeout(Duration.of(5, SECONDS) ) .withRetryPolicy(RetryPolicy.custom( )

    .retryOn(HttpStatus5xxException.class ) .build() ) .build() ; ZupHttpClient<Frete> client = new ZupHttpClient<>(config) ; Frete frete = client.get(url ) .withParameter("cep", cep ) .execute();
  130. ZupClientConfig config = ZupClientConfig.custom( ) .withRequestTimeout(Duration.of(5, SECONDS) ) .withRetryPolicy(RetryPolicy.custom( )

    .retryOn(HttpStatus5xxException.class ) .build() ) .build() ; ZupHttpClient<Frete> client = new ZupHttpClient<>(config) ; Frete frete = client.get(url ) .withParameter("cep", cep ) .execute(); Transient Failures
  131. ZupClientConfig config = ZupClientConfig.custom( ) .withRequestTimeout(Duration.of(5, SECONDS) ) .withRetryPolicy(RetryPolicy.custom( )

    .retryOn(HttpStatus5xxException.class ) .withMaxAttempts(3 ) .build() ) .build(); ZupHttpClient<Frete> client = new ZupHttpClient<>(config) ; Frete frete = client.get(url ) .withParameter("cep", cep ) .execute();
  132. ZupClientConfig config = ZupClientConfig.custom( ) .withRequestTimeout(Duration.of(5, SECONDS) ) .withRetryPolicy(RetryPolicy.custom( )

    .retryOn(HttpStatus5xxException.class ) .withMaxAttempts(3 ) .build() ) .build(); ZupHttpClient<Frete> client = new ZupHttpClient<>(config) ; Frete frete = client.get(url ) .withParameter("cep", cep ) .execute(); Depende do caso de uso e contexto
  133. Spring Boot App Client Spring Boot App Service 
 Internet

  134. Spring Boot App Client Spring Boot App Service 
 Internet

  135. Spring Boot App Client Spring Boot App Service 
 Internet

    Original Request:
  136. Spring Boot App Client Spring Boot App Service 
 Internet

    Original Request:
  137. Spring Boot App Client Spring Boot App Service 
 Internet

    Retry #1: Original Request:
  138. Spring Boot App Client Spring Boot App Service 
 Internet

    Retry #1: Retry #2: Original Request:
  139. Spring Boot App Client Spring Boot App Service 
 Internet

    Retry #1: Retry #2: Original Request:
  140. Clients são EGOISTAS

  141. Spring Boot App Client Spring Boot App Service 
 Internet

  142. Spring Boot App Client Spring Boot App Service 
 Internet

  143. Spring Boot App Client Spring Boot App Service 
 Internet

  144. Spring Boot App Client Spring Boot App Service 
 Internet

  145. Spring Boot App Client Spring Boot App Service 
 Internet

  146. Spring Boot App Client Spring Boot App Service 
 Internet

  147. Spring Boot App Client Spring Boot App Service 
 Internet

  148. Spring Boot App Client Spring Boot App Service 
 Internet

  149. None
  150. RETRY STORM 
 Vamo surrar esse servidor ae!

  151. Não demos tempo pro serviço se recuperar

  152. Retry with Backo f

  153. ZupClientConfig config = ZupClientConfig.custom( ) .withRequestTimeout(Duration.of(5, SECONDS) ) .withRetryPolicy(RetryPolicy.custom( )

    .retryOn(HttpStatus5xxException.class ) .withMaxAttempts(3 ) .build() ) .build() ; ZupHttpClient<Frete> client = new ZupHttpClient<>(config) ; Frete frete = client.get(url ) .withParameter("cep", cep ) .execute();
  154. ZupClientConfig config = ZupClientConfig.custom( ) .withRequestTimeout(Duration.of(5, SECONDS) ) .withRetryPolicy(RetryPolicy.custom( )

    .retryOn(HttpStatus5xxException.class ) .withMaxAttempts(3 ) .withDelay(Duration.of(100, MILLIS) ) .build() ) .build(); ZupHttpClient<Frete> client = new ZupHttpClient<>(config) ; Frete frete = client.get(url ) .withParameter("cep", cep ) .execute();
  155. 100ms
 100ms
 100ms
 100ms
 …
 Retry #1 Retry #2 Retry

    #3 Retry #4
  156. Não resolvemos o problema, somente "empurramos" ele 100ms pra frente…

  157. ZupClientConfig config = ZupClientConfig.custom( ) .withRequestTimeout(Duration.of(5, SECONDS) ) .withRetryPolicy(RetryPolicy.custom( )

    .retryOn(HttpStatus5xxException.class ) .withMaxAttempts(3 ) .withDelay(Duration.of(100, MILLIS) ) .build() ) .build(); ZupHttpClient<Frete> client = new ZupHttpClient<>(config) ; Frete frete = client.get(url ) .withParameter("cep", cep ) .execute();
  158. ZupClientConfig config = ZupClientConfig.custom( ) .withRequestTimeout(Duration.of(5, SECONDS) ) .withRetryPolicy(RetryPolicy.custom( )

    .retryOn(HttpStatus5xxException.class ) .withMaxAttempts(3 ) .withDelay(Duration.of(100, MILLIS), 2 ) .build() ) .build(); ZupHttpClient<Frete> client = new ZupHttpClient<>(config) ; Frete frete = client.get(url ) .withParameter("cep", cep ) .execute();
  159. ZupClientConfig config = ZupClientConfig.custom( ) .withRequestTimeout(Duration.of(5, SECONDS) ) .withRetryPolicy(RetryPolicy.custom( )

    .retryOn(HttpStatus5xxException.class ) .withMaxAttempts(3 ) .withDelay(Duration.of(100, MILLIS), 2 ) .build() ) .build() ; ZupHttpClient<Frete> client = new ZupHttpClient<>(config) ; Frete frete = client.get(url ) .withParameter("cep", cep ) .execute(); Delay Factor
  160. 100ms
 200ms
 400ms
 800ms
 …
 Retry #1 Retry #2 Retry

    #3 Retry #4 Dobramos Dobramos Dobramos Dobramos
  161. Retry with Exponential Backo f

  162. ZupClientConfig config = ZupClientConfig.custom( ) .withRequestTimeout(Duration.of(5, SECONDS) ) .withRetryPolicy(RetryPolicy.custom( )

    .retryOn(HttpStatus5xxException.class ) .withMaxAttempts(3 ) .withDelay(Duration.of(100, MILLIS), 2 ) .build() ) .build() ; ZupHttpClient<Frete> client = new ZupHttpClient<>(config) ; Frete frete = client.get(url ) .withParameter("cep", cep ) .execute();
  163. ZupClientConfig config = ZupClientConfig.custom( ) .withRequestTimeout(Duration.of(5, SECONDS) ) .withRetryPolicy(RetryPolicy.custom( )

    .retryOn(HttpStatus5xxException.class ) .withMaxAttempts(3 ) .withDelay(Duration.of(100, MILLIS), 2 ) .build() ) .build() ; ZupHttpClient<Frete> client = new ZupHttpClient<>(config) ; Frete frete = client.get(url ) .withParameter("cep", cep ) .execute();
  164. ZupClientConfig config = ZupClientConfig.custom( ) .withRequestTimeout(Duration.of(5, SECONDS) ) .withRetryPolicy(RetryPolicy.custom( )

    .retryOn(HttpStatus5xxException.class ) .withMaxAttempts(3 ) .withDelay(Duration.of(100, MILLIS), 2 ) .build() ) .build() ; ZupHttpClient<Frete> client = new ZupHttpClient<>(config) ; Frete frete = client.get(url ) .withParameter("cep", cep ) .execute();
  165. ZupClientConfig config = ZupClientConfig.custom( ) .withRequestTimeout(Duration.of(5, SECONDS) ) .withRetryPolicy(RetryPolicy.custom( )

    .retryOn(HttpStatus5xxException.class ) .withMaxAttempts(3 ) .withExponentialBackoff(Duration.of(100, MILLIS) ) .build() ) .build() ; ZupHttpClient<Frete> client = new ZupHttpClient<>(config) ; Frete frete = client.get(url ) .withParameter("cep", cep ) .execute();
  166. Demos folêgo pro servidor ter tempo para se recuperar, porém…

  167. None
  168. SINCRONIA ENTRE CLIENTS

  169. Precisamos diminuir as chances dessa sincronização…

  170. Retry with Backo f f and Jitter

  171. jitter /ˈdʒɪtə/ n. 
 the deviation from true periodicity of

    a presumably periodic signal.
  172. jitter /ˈdʒɪtə/ n. 
 add randomness to the periodicity of

    a periodic signal.
  173. ZupClientConfig config = ZupClientConfig.custom( ) .withRequestTimeout(Duration.of(5, SECONDS) ) .withRetryPolicy(RetryPolicy.custom( )

    .retryOn(HttpStatus5xxException.class ) .withMaxAttempts(3 ) .withExponentialBackoff(Duration.of(100, MILLIS) ) .build() ) .build();
 ZupHttpClient<Frete> client = new ZupHttpClient<>(config) ; Frete frete = client.get(url ) .withParameter("cep", cep ) .execute();
  174. ZupClientConfig config = ZupClientConfig.custom( ) .withRequestTimeout(Duration.of(5, SECONDS) ) .withRetryPolicy(RetryPolicy.custom( )

    .retryOn(HttpStatus5xxException.class ) .withMaxAttempts(3 ) .withExponentialBackoff(Duration.of(100, MILLIS) ) .withJitter(0.25 ) .build() ) .build() ; ZupHttpClient<Frete> client = new ZupHttpClient<>(config) ; Frete frete = client.get(url ) .withParameter("cep", cep ) .execute();
  175. ZupClientConfig config = ZupClientConfig.custom( ) .withRequestTimeout(Duration.of(5, SECONDS) ) .withRetryPolicy(RetryPolicy.custom( )

    .retryOn(HttpStatus5xxException.class ) .withMaxAttempts(3 ) .withExponentialBackoff(Duration.of(100, MILLIS) ) .withJitter(0.25 ) .build() ) .build() ; ZupHttpClient<Frete> client = new ZupHttpClient<>(config) ; Frete frete = client.get(url ) .withParameter("cep", cep ) .execute(); Jitter Factor
  176. delay random(0, delay*0.25) + -

  177. delay random(0, delay*0.25) + -

  178. delay random(0, delay*0.25) + -

  179. delay random(0, delay*0.25) + -

  180. delay random(0, delay*0.25) Jitter + -

  181. 100ms
 200ms
 400ms
 800ms
 …
 Retry #1 Retry #2 Retry

    #3 Retry #4
  182. 121ms +21ms 
 203ms +3ms 
 393ms -7ms 
 788ms

    -12ms 
 …
 Retry #1 Retry #2 Retry #3 Retry #4
  183. Não só evitamos a sincronização…

  184. … como também distribuímos melhor os requests entre os intervalos

  185. Retry with Exponential Backo f https://aws.amazon.com/blogs/architecture/exponential-backo f f -and-jitter/

  186. Retry with Exponential Backo f https://aws.amazon.com/blogs/architecture/exponential-backo f f -and-jitter/ Intervalos

    longos 
 e ociosos
  187. Intervalos longos 
 e ociosos Retry with Exponential Backo f

    Picos ainda podem ocorrer https://aws.amazon.com/blogs/architecture/exponential-backo f f -and-jitter/
  188. Retry with Exponential Backo f f and Jitter https://aws.amazon.com/blogs/architecture/exponential-backo f

    f -and-jitter/
  189. Retry with Exponential Backo f f and Jitter https://aws.amazon.com/blogs/architecture/exponential-backo f

    f -and-jitter/ Distribui as requisições entre os intervalos
  190. Distribui as requisições entre os intervalos Retry with Exponential Backo

    f f and Jitter Menor incidência de picos https://aws.amazon.com/blogs/architecture/exponential-backo f f -and-jitter/
  191. Distribui as requisições entre os intervalos Retry with Exponential Backo

    f f and Jitter Menor incidência de picos https://aws.amazon.com/blogs/architecture/exponential-backo f f -and-jitter/
  192. Pra entender melhor como tudo isso funciona…

  193. Efeitos de Particionamento de Rede

  194. RetryPolicy.custom( ) .retryOn(HttpStatus5xxException.class ) .withMaxAttempts(3 ) .withDelay(ofMillis(100)) .build( ) (Rede

    particionada) https://www.usenix.org/sites/default/ f i les/conference/protected- f i les/srecon18asia_slides_goh.pdf
  195. RetryPolicy.custom( ) .retryOn(HttpStatus5xxException.class ) .withMaxAttempts(3 ) .withExponentialBackoff(ofMillis(100)) .build( ) https://www.usenix.org/sites/default/

    f i les/conference/protected- f i les/srecon18asia_slides_goh.pdf (Rede particionada)
  196. RetryPolicy.custom( ) .retryOn(HttpStatus5xxException.class ) .withMaxAttempts(3 ) .withExponentialBackoff(ofMillis(100)) .withJitter(0.25)
 .build() https://www.usenix.org/sites/default/

    f i les/conference/protected- f i les/srecon18asia_slides_goh.pdf (Rede particionada)
  197. Efeitos de falhas parciais

  198. RetryPolicy.custom( ) .retryOn(HttpStatus5xxException.class ) .withMaxAttempts(3 ) .withDelay(ofMillis(100)) .build( ) (taxa

    de falha de 25 %) https://www.usenix.org/sites/default/ f i les/conference/protected- f i les/srecon18asia_slides_goh.pdf
  199. RetryPolicy.custom( ) .retryOn(HttpStatus5xxException.class ) .withMaxAttempts(3 ) .withExponentialBackoff(ofMillis(100)) .build( ) (taxa

    de falha de 25 %) https://www.usenix.org/sites/default/ f i les/conference/protected- f i les/srecon18asia_slides_goh.pdf
  200. RetryPolicy.custom( ) .retryOn(HttpStatus5xxException.class ) .withMaxAttempts(3 ) .withExponentialBackoff(ofMillis(100)) .withJitter(0.25)
 .build() (taxa

    de falha de 25 %) https://www.usenix.org/sites/default/ f i les/conference/protected- f i les/srecon18asia_slides_goh.pdf
  201. Concluindo…

  202. Sistemas Distribuídos são complexos por natureza

  203. Qualquer chamada remota é um potencial ponto de falha

  204. Pontos de atenção

  205. • Sempre de f i na Timeouts Pontos de atenção

  206. • Sempre de f i na Timeouts • Não faça

    Retry (por default) Pontos de atenção
  207. • Sempre de f i na Timeouts • Não faça

    Retry (por default) • Se f i zer Retry, faça Backo f f (exponential) Pontos de atenção
  208. • Sempre de f i na Timeouts • Não faça

    Retry (por default) • Se f i zer Retry, faça Backo f f (exponential) • Sempre use Jitter Pontos de atenção
  209. OBRIGADO!

  210. @rponte Rafael Ponte