$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

    View Slide

  2. O que é um
    Sistema Tolerante
    a Falhas?

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  6. Desenhando
    sistemas
    distribuídos…

    View Slide

  7. View Slide

  8. View Slide

  9. View Slide

  10. View Slide

  11. Spring Boot App

    View Slide

  12. Spring Boot App

    View Slide

  13. Spring Boot App
    Client Service

    View Slide

  14. Spring Boot App
    Client Service

    View Slide

  15. Spring Boot App
    Client Service
    Local Calls

    View Slide

  16. Spring Boot App
    Client Service
    Local Calls

    View Slide

  17. Spring Boot App
    Client Service
    Local Calls

    View Slide

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

    View Slide

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

    View Slide

  20. Spring Boot App
    Client Service
    Local Calls

    View Slide

  21. Em
    contrapartida…

    View Slide

  22. Spring Boot App Spring Boot App

    View Slide

  23. Spring Boot App Spring Boot App
    Client

    View Slide

  24. Spring Boot App Spring Boot App
    Client Service

    View Slide

  25. Spring Boot App Spring Boot App
    Client Service

    Internet

    View Slide

  26. Spring Boot App Spring Boot App
    Client Service

    Internet

    View Slide

  27. Spring Boot App Spring Boot App
    Client Service

    Internet
    Remote Calls

    View Slide

  28. Spring Boot App Spring Boot App
    Client Service

    Internet
    Remote Calls

    View Slide

  29. Spring Boot App
    Client
    Spring Boot App
    Service

    Internet
    Remote Calls

    View Slide

  30. Spring Boot App
    Client
    Spring Boot App
    Service

    Internet
    Remote Calls

    View Slide

  31. Spring Boot App
    Client
    Spring Boot App
    Service

    Internet
    Remote Calls

    View Slide

  32. Spring Boot App
    Client
    Spring Boot App
    Service

    Internet
    Remote Calls

    View Slide

  33. Spring Boot App
    Client
    Spring Boot App
    Service

    Internet
    Remote Calls

    View Slide

  34. Spring Boot App Spring Boot App

    Internet
    Client Service
    Remote Calls

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  40. View Slide

  41. Por que isso
    importa?

    View Slide

  42. Spring Boot App Spring Boot App Spring Boot App

    Local Calls Remote Calls

    View Slide

  43. Spring Boot App Spring Boot App Spring Boot App

    Centralized System Distributed System

    View Slide

  44. Spring Boot App Spring Boot App Spring Boot App

    Centralized System Distributed System

    View Slide

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

    "don’t distribute your
    objects"

    View Slide

  46. Mas se não tiver
    jeito…

    View Slide

  47. Spring Boot App
    Client
    Spring Boot App
    Service

    Internet
    Distributed System

    View Slide

  48. Spring Boot App
    Client
    Spring Boot App
    Service

    Internet
    Distributed System

    View Slide

  49. View Slide

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

    Internet

    View Slide

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

    Internet

    View Slide

  52. @RestController
    public class CalculadoraDeFretesController
    {


    @GetMapping(path="/fretes/calcula")
    public ResponseEntity calcula(@RequestParam String cep)
    {


    // consulta frete em outro microsserviço
    String url = "https://ms.fast-fretes.com/calcula-frete/"
    ;



    ZupHttpClient client = new ZupHttpClient<>()
    ;


    Frete frete = client.get(url
    )


    .withParameter("cep", cep
    )


    .execute();

    return ResponseEntity.ok(frete);


    }


    }

    View Slide

  53. @RestController
    public class CalculadoraDeFretesController
    {


    @GetMapping(path="/fretes/calcula")
    public ResponseEntity calcula(@RequestParam String cep)
    {


    // consulta frete em outro microsserviço
    String url = "https://ms.fast-fretes.com/calcula-frete/"
    ;



    ZupHttpClient client = new ZupHttpClient<>()
    ;


    Frete frete = client.get(url
    )


    .withParameter("cep", cep
    )


    .execute();

    return ResponseEntity.ok(frete);


    }


    }

    View Slide

  54. @RestController
    public class CalculadoraDeFretesController
    {


    @GetMapping(path="/fretes/calcula")
    public ResponseEntity calcula(@RequestParam String cep)
    {


    // consulta frete em outro microsserviço
    String url = "https://ms.fast-fretes.com/calcula-frete/"
    ;



    ZupHttpClient client = new ZupHttpClient<>()
    ;


    Frete frete = client.get(url
    )


    .withParameter("cep", cep
    )


    .execute();

    return ResponseEntity.ok(frete);


    }


    }

    View Slide

  55. @RestController
    public class CalculadoraDeFretesController
    {


    @GetMapping(path="/fretes/calcula")
    public ResponseEntity calcula(@RequestParam String cep)
    {


    // consulta frete em outro microsserviço
    String url = "https://ms.fast-fretes.com/calcula-frete/"
    ;



    ZupHttpClient client = new ZupHttpClient<>()
    ;


    Frete frete = client.get(url
    )


    .withParameter("cep", cep
    )


    .execute();

    return ResponseEntity.ok(frete);


    }


    }

    View Slide

  56. @RestController
    public class CalculadoraDeFretesController
    {


    @GetMapping(path="/fretes/calcula")
    public ResponseEntity calcula(@RequestParam String cep)
    {


    // consulta frete em outro microsserviço
    String url = "https://ms.fast-fretes.com/calcula-frete/"
    ;



    ZupHttpClient client = new ZupHttpClient<>()
    ;


    Frete frete = client.get(url
    )


    .withParameter("cep", cep
    )


    .execute();

    return ResponseEntity.ok(frete);


    }


    }

    View Slide

  57. @RestController
    public class CalculadoraDeFretesController
    {


    @GetMapping(path="/fretes/calcula")
    public ResponseEntity calcula(@RequestParam String cep)
    {


    // consulta frete em outro microsserviço
    String url = "https://ms.fast-fretes.com/calcula-frete/"
    ;



    ZupHttpClient client = new ZupHttpClient<>()
    ;


    Frete frete = client.get(url
    )


    .withParameter("cep", cep
    )


    .execute();

    return ResponseEntity.ok(frete);


    }


    }

    View Slide

  58. @RestController
    public class CalculadoraDeFretesController
    {


    @GetMapping(path="/fretes/calcula")
    public ResponseEntity calcula(@RequestParam String cep)
    {


    // consulta frete em outro microsserviço
    String url = "https://ms.fast-fretes.com/calcula-frete/"
    ;



    ZupHttpClient client = new ZupHttpClient<>()
    ;


    Frete frete = client.get(url
    )


    .withParameter("cep", cep
    )


    .execute();

    return ResponseEntity.ok(frete);


    }


    }

    View Slide

  59. @RestController
    public class CalculadoraDeFretesController
    {


    @GetMapping(path="/fretes/calcula")
    public ResponseEntity calcula(@RequestParam String cep)
    {


    // consulta frete em outro microsserviço
    String url = "https://ms.fast-fretes.com/calcula-frete/"
    ;



    ZupHttpClient client = new ZupHttpClient<>()
    ;


    Frete frete = client.get(url
    )


    .withParameter("cep", cep
    )


    .execute();

    return ResponseEntity.ok(frete);


    }


    }

    View Slide

  60. @RestController
    public class CalculadoraDeFretesController
    {


    @GetMapping(path="/fretes/calcula")
    public ResponseEntity calcula(@RequestParam String cep)
    {


    // consulta frete em outro microsserviço
    String url = "https://ms.fast-fretes.com/calcula-frete/"
    ;



    ZupHttpClient client = new ZupHttpClient<>()
    ;


    Frete frete = client.get(url
    )


    .withParameter("cep", cep
    )


    .execute();

    return ResponseEntity.ok(frete);


    }


    }

    View Slide

  61. @RestController
    public class CalculadoraDeFretesController
    {


    @GetMapping(path="/fretes/calcula")
    public ResponseEntity calcula(@RequestParam String cep)
    {


    // consulta frete em outro microsserviço
    String url = "https://ms.fast-fretes.com/calcula-frete/"
    ;



    ZupHttpClient client = new ZupHttpClient<>()
    ;


    Frete frete = client.get(url
    )


    .withParameter("cep", cep
    )


    .execute();

    return ResponseEntity.ok(frete);


    }


    }

    View Slide

  62. @RestController
    public class CalculadoraDeFretesController
    {


    @GetMapping(path="/fretes/calcula")
    public ResponseEntity calcula(@RequestParam String cep)
    {


    // consulta frete em outro microsserviço
    String url = "https://ms.fast-fretes.com/calcula-frete/"
    ;



    ZupHttpClient client = new ZupHttpClient<>()
    ;


    Frete frete = client.get(url
    )


    .withParameter("cep", cep
    )


    .execute();

    return ResponseEntity.ok(frete);


    }


    }

    View Slide

  63. @RestController
    public class CalculadoraDeFretesController
    {


    @GetMapping(path="/fretes/calcula")
    public ResponseEntity calcula(@RequestParam String cep)
    {


    // consulta frete em outro microsserviço
    String url = "https://ms.fast-fretes.com/calcula-frete/"
    ;



    ZupHttpClient client = new ZupHttpClient<>()
    ;


    Frete frete = client.get(url
    )


    .withParameter("cep", cep
    )


    .execute();

    return ResponseEntity.ok(frete);


    }


    }

    View Slide

  64. Design for
    Failures

    View Slide

  65. Rafael Ponte


    @rponte

    View Slide

  66. View Slide

  67. Fortaleza - Terra do Sol

    View Slide

  68. View Slide

  69. FAULT-TOLERANT CLIENTS
    Implementando clients e services mais resilientes e
    tolerantes a falhas

    View Slide

  70. Implementação
    Ingênua

    View Slide

  71. @RestController
    public class CalculadoraDeFretesController
    {


    @GetMapping(path="/fretes/calcula")
    public ResponseEntity calcula(@RequestParam String cep)
    {


    // consulta frete em outro microsserviço
    String url = "https://ms.fast-fretes.com/calcula-frete/"
    ;



    ZupHttpClient client = new ZupHttpClient<>()
    ;


    Frete frete = client.get(url
    )


    .withParameter("cep", cep
    )


    .execute();

    return ResponseEntity.ok(frete);


    }


    }

    View Slide

  72. @RestController
    public class CalculadoraDeFretesController
    {


    @GetMapping(path="/fretes/calcula")
    public ResponseEntity calcula(@RequestParam String cep)
    {


    // consulta frete em outro microsserviço
    String url = "https://ms.fast-fretes.com/calcula-frete/"
    ;



    ZupHttpClient client = new ZupHttpClient<>()
    ;


    Frete frete = client.get(url
    )


    .withParameter("cep", cep
    )


    .execute();

    return ResponseEntity.ok(frete);


    }


    }

    View Slide

  73. @RestController
    public class CalculadoraDeFretesController
    {


    @GetMapping(path="/fretes/calcula")
    public ResponseEntity calcula(@RequestParam String cep)
    {


    // consulta frete em outro microsserviço
    String url = "https://ms.fast-fretes.com/calcula-frete/"
    ;



    ZupHttpClient client = new ZupHttpClient<>()
    ;


    Frete frete = client.get(url
    )


    .withParameter("cep", cep
    )


    .execute();

    return ResponseEntity.ok(frete);


    }


    }

    View Slide

  74. ZupHttpClient client = new ZupHttpClient<>()
    ;


    Frete frete = client.get(url
    )


    .withParameter("cep", cep
    )


    .execute();

    View Slide

  75. ZupHttpClient client = new ZupHttpClient<>()
    ;


    Frete frete = client.get(url
    )


    .withParameter("cep", cep
    )


    .execute();

    View Slide

  76. ZupHttpClient client = new ZupHttpClient<>()
    ;


    Frete frete = client.get(url
    )


    .withParameter("cep", cep
    )


    .execute();

    View Slide

  77. ZupHttpClient client = new ZupHttpClient<>()
    ;


    Frete frete = client.get(url
    )


    .withParameter("cep", cep
    )


    .execute();
    Pode ser
    qualquer
    HTTP Client!

    View Slide

  78. ZupHttpClient client = new ZupHttpClient<>()
    ;


    Frete frete = client.get(url
    )


    .withParameter("cep", cep
    )


    .execute();

    View Slide

  79. ZupHttpClient client = new ZupHttpClient<>()
    ;


    Frete frete = client.get(url
    )


    .withParameter("cep", cep
    )


    .execute();

    View Slide

  80. ZupHttpClient client = new ZupHttpClient<>()
    ;


    Frete frete = client.get(url
    )


    .withParameter("cep", cep
    )


    .execute();

    View Slide

  81. O problema dessa
    implementação…

    View Slide

  82. Spring Boot App
    Client
    Spring Boot App
    Service

    Internet

    View Slide

  83. Spring Boot App
    Client
    Spring Boot App
    Service

    Internet

    View Slide

  84. Spring Boot App
    Client
    Spring Boot App
    Service

    Internet

    View Slide

  85. Spring Boot App
    Client
    Spring Boot App
    Service

    Internet

    View Slide

  86. Spring Boot App
    Client
    Spring Boot App
    Service

    Internet

    View Slide

  87. Spring Boot App
    Client
    Spring Boot App
    Service

    Internet

    View Slide

  88. Spring Boot App
    Client
    Spring Boot App
    Service

    Internet

    View Slide

  89. Spring Boot App
    Client
    Spring Boot App
    Service

    Internet

    View Slide

  90. Spring Boot App
    Client
    Spring Boot App
    Service

    Internet

    View Slide

  91. Spring Boot App
    Client
    Spring Boot App
    Service

    Internet

    View Slide

  92. Spring Boot App
    Client
    Spring Boot App
    Service

    Internet

    View Slide

  93. Spring Boot App
    Client
    Spring Boot App
    Service

    Internet

    View Slide

  94. Spring Boot App
    Client
    Spring Boot App
    Service

    Internet

    View Slide

  95. Spring Boot App
    Client
    Spring Boot App
    Service

    Internet

    View Slide

  96. Spring Boot App
    Client
    Spring Boot App
    Service

    Internet

    View Slide

  97. Spring Boot App
    Client
    Spring Boot App
    Service

    Internet

    View Slide

  98. Spring Boot App
    Client
    Spring Boot App
    Service

    Internet

    View Slide

  99. View Slide

  100. View Slide

  101. Tudo isso porque
    esperamos demais…

    View Slide

  102. Timeout

    View Slide

  103. ZupClientConfig config = // ... ZupClientConfig.custom(
    )


    .withRequestTimeout(Duration.of(5, SECONDS)
    )


    .build()
    ;


    ZupHttpClient client = new ZupHttpClient<>()
    ;


    Frete frete = client.get(url
    )


    .withParameter("cep", cep
    )


    .execute();

    View Slide

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


    .build()
    ;


    ZupHttpClient client = new ZupHttpClient<>()
    ;


    Frete frete = client.get(url
    )


    .withParameter("cep", cep
    )


    .execute();

    View Slide

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


    .build()
    ;


    ZupHttpClient client = new ZupHttpClient<>(config)
    ;


    Frete frete = client.get(url
    )


    .withParameter("cep", cep
    )


    .execute();

    View Slide

  106. ZupClientConfig config = ZupClientConfig.custom(
    )


    .withRequestTimeout(Duration.of(5, SECONDS)
    )


    .build()
    ;


    ZupHttpClient client = new ZupHttpClient<>(config)
    ;


    Frete frete = client.get(url
    )


    .withParameter("cep", cep
    )


    .execute();

    View Slide

  107. ZupClientConfig config = ZupClientConfig.custom(
    )


    .withRequestTimeout(Duration.of(5, SECONDS)
    )


    .build()
    ;


    ZupHttpClient client = new ZupHttpClient<>(config)
    ;


    Frete frete = client.get(url
    )


    .withParameter("cep", cep
    )


    .execute();

    View Slide

  108. ZupClientConfig config = ZupClientConfig.custom(
    )


    .withRequestTimeout(Duration.of(5, SECONDS)
    )


    .build()
    ;


    ZupHttpClient client = new ZupHttpClient<>(config)
    ;


    Frete frete = client.get(url
    )


    .withParameter("cep", cep
    )


    .execute();

    View Slide

  109. ZupClientConfig config = ZupClientConfig.custom(
    )


    .withRequestTimeout(Duration.of(5, SECONDS)
    )


    .build()
    ;


    ZupHttpClient client = new ZupHttpClient<>(config)
    ;


    Frete frete = client.get(url
    )


    .withParameter("cep", cep
    )


    .execute();
    Depende do caso de
    uso e contexto

    View Slide

  110. ZupClientConfig config = ZupClientConfig.custom(
    )


    .withRequestTimeout(Duration.of(5, SECONDS)
    )


    .build()
    ;


    ZupHttpClient client = new ZupHttpClient<>(config)
    ;


    Frete frete = client.get(url
    )


    .withParameter("cep", cep
    )


    .execute();

    View Slide

  111. Spring Boot App
    Client
    Spring Boot App
    Service

    Internet

    View Slide

  112. Spring Boot App
    Client
    Spring Boot App
    Service

    Internet

    View Slide

  113. Spring Boot App
    Client
    Spring Boot App
    Service

    Internet

    View Slide

  114. Spring Boot App
    Client
    Spring Boot App
    Service

    Internet

    View Slide

  115. Spring Boot App
    Client
    Spring Boot App
    Service

    Internet

    View Slide

  116. Fail Fast

    View Slide

  117. …mas não para
    Transient Failures

    View Slide

  118. Spring Boot App
    Client
    Spring Boot App
    Service

    Internet

    View Slide

  119. Spring Boot App
    Client
    Spring Boot App
    Service

    Internet

    View Slide

  120. Spring Boot App
    Client
    Spring Boot App
    Service

    Internet

    View Slide

  121. Spring Boot App
    Client
    Spring Boot App
    Service

    Internet

    View Slide

  122. Spring Boot App
    Client
    Spring Boot App
    Service

    Internet

    View Slide

  123. Spring Boot App
    Client
    Spring Boot App
    Service

    Internet

    View Slide

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

    View Slide

  125. Retry

    View Slide

  126. ZupClientConfig config = ZupClientConfig.custom(
    )


    .withRequestTimeout(Duration.of(5, SECONDS)
    )


    .build()
    ;


    ZupHttpClient client = new ZupHttpClient<>(config)
    ;


    Frete frete = client.get(url
    )


    .withParameter("cep", cep
    )


    .execute();

    View Slide

  127. ZupClientConfig config = ZupClientConfig.custom(
    )


    .withRequestTimeout(Duration.of(5, SECONDS)
    )


    .withRetryPolicy(
    )


    .build()
    ;


    ZupHttpClient client = new ZupHttpClient<>(config)
    ;


    Frete frete = client.get(url
    )


    .withParameter("cep", cep
    )


    .execute();

    View Slide

  128. ZupClientConfig config = ZupClientConfig.custom(
    )


    .withRequestTimeout(Duration.of(5, SECONDS)
    )


    .withRetryPolicy(RetryPolicy.custom().build()
    )


    .build()
    ;


    ZupHttpClient client = new ZupHttpClient<>(config)
    ;


    Frete frete = client.get(url
    )


    .withParameter("cep", cep
    )


    .execute();

    View Slide

  129. ZupClientConfig config = ZupClientConfig.custom(
    )


    .withRequestTimeout(Duration.of(5, SECONDS)
    )


    .withRetryPolicy(RetryPolicy.custom(
    )


    .retryOn(HttpStatus5xxException.class
    )


    .build()
    )


    .build()
    ;


    ZupHttpClient client = new ZupHttpClient<>(config)
    ;


    Frete frete = client.get(url
    )


    .withParameter("cep", cep
    )


    .execute();

    View Slide

  130. ZupClientConfig config = ZupClientConfig.custom(
    )


    .withRequestTimeout(Duration.of(5, SECONDS)
    )


    .withRetryPolicy(RetryPolicy.custom(
    )


    .retryOn(HttpStatus5xxException.class
    )


    .build()
    )


    .build()
    ;


    ZupHttpClient client = new ZupHttpClient<>(config)
    ;


    Frete frete = client.get(url
    )


    .withParameter("cep", cep
    )


    .execute();
    Transient Failures

    View Slide

  131. ZupClientConfig config = ZupClientConfig.custom(
    )


    .withRequestTimeout(Duration.of(5, SECONDS)
    )


    .withRetryPolicy(RetryPolicy.custom(
    )


    .retryOn(HttpStatus5xxException.class
    )


    .withMaxAttempts(3
    )


    .build()
    )


    .build();
    ZupHttpClient client = new ZupHttpClient<>(config)
    ;


    Frete frete = client.get(url
    )


    .withParameter("cep", cep
    )


    .execute();

    View Slide

  132. ZupClientConfig config = ZupClientConfig.custom(
    )


    .withRequestTimeout(Duration.of(5, SECONDS)
    )


    .withRetryPolicy(RetryPolicy.custom(
    )


    .retryOn(HttpStatus5xxException.class
    )


    .withMaxAttempts(3
    )


    .build()
    )


    .build();
    ZupHttpClient client = new ZupHttpClient<>(config)
    ;


    Frete frete = client.get(url
    )


    .withParameter("cep", cep
    )


    .execute();
    Depende do caso de
    uso e contexto

    View Slide

  133. Spring Boot App
    Client
    Spring Boot App
    Service

    Internet

    View Slide

  134. Spring Boot App
    Client
    Spring Boot App
    Service

    Internet

    View Slide

  135. Spring Boot App
    Client
    Spring Boot App
    Service

    Internet
    Original Request:

    View Slide

  136. Spring Boot App
    Client
    Spring Boot App
    Service

    Internet
    Original Request:

    View Slide

  137. Spring Boot App
    Client
    Spring Boot App
    Service

    Internet
    Retry #1:
    Original Request:

    View Slide

  138. Spring Boot App
    Client
    Spring Boot App
    Service

    Internet
    Retry #1:
    Retry #2:
    Original Request:

    View Slide

  139. Spring Boot App
    Client
    Spring Boot App
    Service

    Internet
    Retry #1:
    Retry #2:
    Original Request:

    View Slide

  140. Clients são
    EGOISTAS

    View Slide

  141. Spring Boot App
    Client
    Spring Boot App
    Service

    Internet

    View Slide

  142. Spring Boot App
    Client
    Spring Boot App
    Service

    Internet

    View Slide

  143. Spring Boot App
    Client
    Spring Boot App
    Service

    Internet

    View Slide

  144. Spring Boot App
    Client
    Spring Boot App
    Service

    Internet

    View Slide

  145. Spring Boot App
    Client
    Spring Boot App
    Service

    Internet

    View Slide

  146. Spring Boot App
    Client
    Spring Boot App
    Service

    Internet

    View Slide

  147. Spring Boot App
    Client
    Spring Boot App
    Service

    Internet

    View Slide

  148. Spring Boot App
    Client
    Spring Boot App
    Service

    Internet

    View Slide

  149. View Slide

  150. RETRY STORM

    Vamo surrar esse servidor ae!

    View Slide

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

    View Slide

  152. Retry with
    Backo
    f

    View Slide

  153. ZupClientConfig config = ZupClientConfig.custom(
    )


    .withRequestTimeout(Duration.of(5, SECONDS)
    )


    .withRetryPolicy(RetryPolicy.custom(
    )


    .retryOn(HttpStatus5xxException.class
    )


    .withMaxAttempts(3
    )


    .build()
    )


    .build()
    ;


    ZupHttpClient client = new ZupHttpClient<>(config)
    ;


    Frete frete = client.get(url
    )


    .withParameter("cep", cep
    )


    .execute();

    View Slide

  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 client = new ZupHttpClient<>(config)
    ;


    Frete frete = client.get(url
    )


    .withParameter("cep", cep
    )


    .execute();

    View Slide

  155. 100ms

    100ms

    100ms

    100ms

    …

    Retry #1
    Retry #2
    Retry #3
    Retry #4

    View Slide

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

    View Slide

  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 client = new ZupHttpClient<>(config)
    ;


    Frete frete = client.get(url
    )


    .withParameter("cep", cep
    )


    .execute();

    View Slide

  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 client = new ZupHttpClient<>(config)
    ;


    Frete frete = client.get(url
    )


    .withParameter("cep", cep
    )


    .execute();

    View Slide

  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 client = new ZupHttpClient<>(config)
    ;


    Frete frete = client.get(url
    )


    .withParameter("cep", cep
    )


    .execute();
    Delay Factor

    View Slide

  160. 100ms

    200ms

    400ms

    800ms

    …

    Retry #1
    Retry #2
    Retry #3
    Retry #4
    Dobramos
    Dobramos
    Dobramos
    Dobramos

    View Slide

  161. Retry with
    Exponential
    Backo
    f

    View Slide

  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 client = new ZupHttpClient<>(config)
    ;


    Frete frete = client.get(url
    )


    .withParameter("cep", cep
    )


    .execute();

    View Slide

  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 client = new ZupHttpClient<>(config)
    ;


    Frete frete = client.get(url
    )


    .withParameter("cep", cep
    )


    .execute();

    View Slide

  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 client = new ZupHttpClient<>(config)
    ;


    Frete frete = client.get(url
    )


    .withParameter("cep", cep
    )


    .execute();

    View Slide

  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 client = new ZupHttpClient<>(config)
    ;


    Frete frete = client.get(url
    )


    .withParameter("cep", cep
    )


    .execute();

    View Slide

  166. Demos folêgo pro
    servidor ter tempo para
    se recuperar, porém…

    View Slide

  167. View Slide

  168. SINCRONIA
    ENTRE CLIENTS

    View Slide

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

    View Slide

  170. Retry with
    Backo
    f
    f
    and
    Jitter

    View Slide

  171. jitter /ˈdʒɪtə/ n.

    the deviation from true
    periodicity of a presumably
    periodic signal.

    View Slide

  172. jitter /ˈdʒɪtə/ n.

    add randomness to the
    periodicity of a periodic
    signal.

    View Slide

  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 client = new ZupHttpClient<>(config)
    ;


    Frete frete = client.get(url
    )


    .withParameter("cep", cep
    )


    .execute();

    View Slide

  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 client = new ZupHttpClient<>(config)
    ;


    Frete frete = client.get(url
    )


    .withParameter("cep", cep
    )


    .execute();

    View Slide

  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 client = new ZupHttpClient<>(config)
    ;


    Frete frete = client.get(url
    )


    .withParameter("cep", cep
    )


    .execute();
    Jitter Factor

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  181. 100ms

    200ms

    400ms

    800ms

    …

    Retry #1
    Retry #2
    Retry #3
    Retry #4

    View Slide

  182. 121ms
    +21ms

    203ms
    +3ms

    393ms
    -7ms

    788ms
    -12ms

    …

    Retry #1
    Retry #2
    Retry #3
    Retry #4

    View Slide

  183. Não só evitamos a
    sincronização…

    View Slide

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

    View Slide

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

    View Slide

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

    e ociosos

    View Slide

  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/

    View Slide

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

    View Slide

  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

    View Slide

  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/

    View Slide

  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/

    View Slide

  192. Pra entender
    melhor como tudo
    isso funciona…

    View Slide

  193. Efeitos de
    Particionamento
    de Rede

    View Slide

  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

    View Slide

  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)

    View Slide

  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)

    View Slide

  197. Efeitos de
    falhas parciais

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  201. Concluindo…

    View Slide

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

    View Slide

  203. Qualquer chamada
    remota é um
    potencial ponto de
    falha

    View Slide

  204. Pontos de atenção

    View Slide

  205. • Sempre de
    f
    i
    na Timeouts


    Pontos de atenção

    View Slide

  206. • Sempre de
    f
    i
    na Timeouts


    • Não faça Retry (por default)


    Pontos de atenção

    View Slide

  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

    View Slide

  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

    View Slide

  209. OBRIGADO!

    View Slide

  210. @rponte
    Rafael Ponte

    View Slide