「微服务设计之禅」限流模式
JAVA架构日记
共 2312字,需浏览 5分钟
· 2020-12-19
前言
微服务本质上分布式架构,当我们使用分布式系统时任何不可预知的问题都会发生(例如网络可用性问题、服务可用性问题、中间件可用性问题)。一个系统的问题可能会直接影响另外一个系统的使用或性能。所以在系统设计过程既要保证自身运行的弹性需求,也要避免对下游服务级联故障。
限流模式
在微服务技术架构中,当有多个服务(A,B,C, D)时,一个服务(A)可能依赖于另一服务(B),而另一服务(B)又可能依赖于 C,依此类推。
如下图我们有 2 个服务 A 和 B,B 服务要进行大量的业务计算和其他依赖接口调用导致 B 的最大请求处理个数小于请求 A 的并发数。
![](https://filescdn.proginn.com/1980930ae1b97027aaa32608d4448af6/0479681652e855a54f9b046627e5e0aa.webp)
当服务 A 接收到很多的服务请求时,由于 B 服务能够处理的请求数量多,从而导致服务宕机。
作为服务 B 为了保证自身高,通过拒绝无法处理的请求来保证服务正常运行。
![](https://filescdn.proginn.com/978abd114ac02ff0242a324e86b59c52/38771cd046f3d25d0db02d1ceab08e2e.webp)
限流模式通过限制在指定时间窗内运行的请求处理数量,帮助提升服务的可用性。
示例程序
架构图
![](https://filescdn.proginn.com/984764442ca66e8ffdc4779c917a28eb/45736a86b7091f222bcedd5a0b4c0e9f.webp)
如上图所示,简单模拟电商下单逻辑
用户登录浏览商品 (商品库存模块) 扣减商品库存 (商品库存模块) 创建商品订单 (订单模块)
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 个请求)
![](https://filescdn.proginn.com/12cc1222d3c1680b213ac4ea5088c39f/1f8db4ef91826255036a5d4ae55f8206.webp)
![](https://filescdn.proginn.com/1c5e4e17123e9d708313676285cd98d2/58494b47faee0e7fafd5a08cf53fe5bd.webp)
订单服务日志,由于是第一次请求触发异常,然后服务调用方自动重试产生第二次调用。
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
往期推荐
评论