「微服务设计之禅」限流模式
前言
微服务本质上分布式架构,当我们使用分布式系统时任何不可预知的问题都会发生(例如网络可用性问题、服务可用性问题、中间件可用性问题)。一个系统的问题可能会直接影响另外一个系统的使用或性能。所以在系统设计过程既要保证自身运行的弹性需求,也要避免对下游服务级联故障。
限流模式
在微服务技术架构中,当有多个服务(A,B,C, D)时,一个服务(A)可能依赖于另一服务(B),而另一服务(B)又可能依赖于 C,依此类推。
如下图我们有 2 个服务 A 和 B,B 服务要进行大量的业务计算和其他依赖接口调用导致 B 的最大请求处理个数小于请求 A 的并发数。

当服务 A 接收到很多的服务请求时,由于 B 服务能够处理的请求数量多,从而导致服务宕机。
作为服务 B 为了保证自身高,通过拒绝无法处理的请求来保证服务正常运行。

限流模式通过限制在指定时间窗内运行的请求处理数量,帮助提升服务的可用性。
示例程序
架构图

如上图所示,简单模拟电商下单逻辑
用户登录浏览商品 (商品库存模块) 扣减商品库存 (商品库存模块) 创建商品订单 (订单模块) 
product-service 通过调用 order-service 服务下单
代码实现
├── ratelimiter-demo
   ├── order-service        #订单服务  (8070)
   └── product-service      #商品库存服务  (8050)
依赖说明。由于 hystrix 年久失修,这里使用 resilience4j 断路保护器做演示 
<dependency>
    <groupId>io.github.resilience4jgroupId>
    <artifactId>resilience4j-spring-boot2artifactId>
    <version>1.6.1version>
dependency>
针对接口定义重试策略 10s 内最多允许通过 5 个请求 
resilience4j.ratelimiter:
  instances:
    createOrder:
      limitForPeriod: 5        # 最多运行多少个
      limitRefreshPeriod: 10s  #时间窗限制 10s
消费方接口。product-service 8050 
/**
 * 用户点击购买
 */
@SneakyThrows
@GetMapping("/order")
public String buy() {
    // 模拟调用 订单服务下单
    orderService.createOrder().get();
    return "success";
}
定义远程调用类使用 Retry 包装 
/**
 * 创建订单
 * name: 指定接口限流配置名称
 * fallbackMethod: 限流后降级方法
 */
@RateLimiter(name = "createOrder", fallbackMethod = "getError")
public CompletableFuture createOrder()  {
    return CompletableFuture.supplyAsync(() -> restTemplate.getForEntity("http://localhost:8070/createOrder"
            , String.class).getBody());
}
public CompletableFuture getError(Throwable error)  {
    log.warn("创建订单失败了 {}", error.getMessage());
    throw new RuntimeException("创建订单失败了");
}
服务提供方。order-service 8070 
@RestController
public class PayController {
    @SneakyThrows
    @GetMapping("/createOrder")
    public String createOrder() {
        return "创建订单服务";
    }
}
开始测试
并发 10 个线程,请求商品服务 (由于我们设置策略 10 秒内只允许 5 个请求) 


订单服务日志,由于是第一次请求触发异常,然后服务调用方自动重试产生第二次调用。 
2020-12-07 15:53:46.698  WARN 52265 --- [nio-8050-exec-6] c.example.product.service.OrderService   : 创建订单失败了 RateLimiter 'createOrder' does not permit further calls
... 异常日志 ...
源码:https://github.com/lltx/microservices-pattern
参考资料和部分图片来源 https://www.vinsguru.com
往期推荐
评论
