科技实验室|3分钟简述熔断器使用方法

熔断器是一种设计模式 , 广泛用于分布式系统中 , 以防止级联故障 。 在这篇文章中 , 我们将通过级联故障的问题 , 来介绍熔断器模式的使用方法 。
动机:级联故障的问题
在进入熔断器模式之前 , 让我们来看看它到底要解决什么问题 。
当服务A尝试与服务B通信时 , 它会分配一个线程来进行该调用 。 在进行调用的时候 , 有2种故障可能发生 , 以user调用friends服务为例 。
'''userservice'''defget_user_info(user_id:str):try:friends_service.get_friends(user_id)exceptExceptionase:raiseInternalServerError即时故障:在即时故障中 , 会立即引发一个异常(如:连接拒绝) , 并释放服务A线程 。
超时故障:如果service_b需要很长的时间来响应 , 当收到服务A的新请求时 , 会有越来越多的线程在等待service_b 。 如果在等待超时的过程中发出了多个请求 , 这就会耗尽服务A的线程池 , 会使服务A瘫痪 。
“您的代码不能永远等待一个不会返回的响应 , 迟早需要放弃等待 , 希望这不是一个设计方法 。 ”-MichaelT.Nygard , ReleaseIt!
下面通过一个社交媒体应用的例子来更好的解释这个问题 。 我们有一个聚合器服务 , 这是客户端交互的内容 , 它聚合了一堆服务的结果 , 包括User服务 。 User服务调用Photos服务和Friends服务 , 而Friends服务又依赖friends_db 。
科技实验室|3分钟简述熔断器使用方法
文章图片
在这里 , friends服务试图向friends_db发出请求 , 但是 , friends_db并没有立即响应失败 , 而是让friends服务的线程一直在等待 。 Friends服务尝试重试 , 从而使用更多线程 。 随着它收到新请求 , 更多线程正在等待friends_db返回结果 。
科技实验室|3分钟简述熔断器使用方法
文章图片
现在可以看到 , Friends服务现在如何成为User服务超时的来源 。 User用尽了它的线程池来等待来自Friends服务的请求 , 就像Friends服务是如何等待friends_db一样 。 现在 , 我们可以看到friends_db中的故障是如何导致间接依赖于它的服务级联失败的 。
科技实验室|3分钟简述熔断器使用方法
文章图片
最终 , 聚合器服务也会由于相同的原因而崩溃 。 客户端调用了聚合服务 , 因此我们的系统实际也变得不可用 。
我们看到架构的一个组件中的一个错误是如何导致级联故障 , 而导致所有其他服务崩溃 。
科技实验室|3分钟简述熔断器使用方法
文章图片
熔断器模式
熔断器通常以拦截器模式/责任链/过滤器的形式实现 , 它包含3个状态:
关闭:允许拦截器将所有请求传递给上游服务 , 并将上游服务的响应传递给调用方 。
打开:不允许请求传递给上游 , 默认返回通常是错误响应 。
半开放式:某些请求被允许传递到上游 , 其他请求被终止并返回默认响应 。
科技实验室|3分钟简述熔断器使用方法
文章图片
下图显示了处于三种状态的熔断器拦截器
科技实验室|3分钟简述熔断器使用方法
文章图片
让我们看一下熔断器的Python示例 , 可以使用以下方法创建自己的熔断器:
fromcircuitbreakerimportCircuitBreakerclassMyCircuitBreaker(CircuitBreaker):FAILURE_THRESHOLD=20RECOVERY_TIMEOUT=60EXPECTED_EXCEPTION=RequestException@MyCircuitBreakerdefget_user_info(user_id):try:friends_service.get_friends(user_id)exceptExceptionase:raiseInternalServerError我们也可以利用sidecar模式 。 通过这种方法 , 不必通过熔断器来修改服务 , 而是使用诸如Envoy之类的辅助工具来交付我们的应用序 。 该服务的所有出站流量都是通过envoy进行代理 。 Envoy支持开箱即用的断路功能 。 以下是Envoy的断路配置示例:


推荐阅读