雪崩问题
微服务调用链路中的某个服务故障,引起整个链路中的所有微服务都不可用,这就是雪崩
雪崩问题产生的原因?
- 微服务相互调用,服务提供者出现故障或阻塞
- 服务调用者没做好异常处理,导致自身故障
- 调用链中的所有服务级联失败,导致整个集群故障
解决问题的思路有哪些?
尽量避免服务中出现问题或阻塞
- 保证代码的健壮性
- 保证网络畅通
- 能应对较高的并发请求
解决方案
服务保护方案-请求限流
限制流量在服务可以处理的范围,避免因突发流量和故障
服务保护方案-线程隔离
控制业务可用的线程数量,将故障隔离在一定范围
服务保护方案-服务熔断
将异常比例过高的接口断开,拒绝所有请求,直接走fallback
Sentinel
搭建Sentinel
Sentinel: The Sentinel of Your Microservices
1
| java -Dserver.port=8090 -Dcsp.sentinel.dashboard.server=localhost:8090 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.8.8.jar
|
sentinel是一个控制台应用程序,可以将其看作类似于Nacos的独立服务
整合Sentinel
1 2 3 4 5
| <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> </dependency>
|
簇点链路
簇点链路就是单机调用链路,是一次请求进入服务后经过的每一个被Sentinel监控的资源链。默认Sentinel会监控SpringMVC的每一个Endpoint(http接口)。限流、熔断都是针对于簇点链路的资源设置的。而资源名默认就是接口的请求路径。
请求方式前缀
Restful风格的API请求路径一般都相同,这会导致簇点资源名称重复,因此我们要修改配置,把请求方式+请求路径作为簇点资源名称
1 2 3 4 5 6
| spring: cloud: sentinel: transport: dashboard: localhost:8090 http-method-specify: true
|
配置
在Sentinel中,可以针对于簇点链路进行限流/线程数量控制
当一个服务调用过慢,会将资源抢占耗尽,别的服务则无法正常调用,这个时候就应该配置线程隔离
将FeignClient作为Sentinel的簇点资源,让服务间调用也被sentinel监控
1 2 3
| feign: sentinel: enabled: true
|
Fallback
基于FallbackFactory,编写FeignClient的fallback逻辑
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| @Slf4j public class ItemClientFallbackFactory implements FallbackFactory<ItemClient> { @Override public ItemClient create(Throwable cause) { return new ItemClient() { @Override public List<ItemApiDTO> queryItemByIds(Collection<Long> ids) { log.error("查询商品失败", cause); return CollUtils.emptyList(); }
@Override public void deductStock(List<OrderDetailApiDTO> items) { log.error("减少商品库存失败", cause); throw new RuntimeException(cause); } }; } }
|
在Feign的配置文件中,将fallback注册到bean中
1 2 3 4
| @Bean public ItemClientFallbackFactory itemClientFallbackFactory() { return new ItemClientFallbackFactory(); }
|
在APIClient中,加载该bean
1 2 3 4 5 6 7 8
| @FeignClient(value = "item-service", fallbackFactory = ItemClientFallbackFactory.class) public interface ItemClient { @GetMapping("/items") List<ItemApiDTO> queryItemByIds(@RequestParam("ids") Collection<Long> ids );
@PutMapping("/items/stock/deduct") public void deductStock(@RequestBody List<OrderDetailApiDTO> items); }
|
Nacos提供注册服务 -> Feign调用服务 -> Sentinel进行流控或线程隔离抛出异常 -> fallback逻辑触发
配置熔断
熔断可以进一步增加性能优化,线程隔离和QPS可以保证服务可用,但仍然会尝试去请求,只有超时或线程不够才会失败
而熔断是设置一个规则,在尝试不行时直接先断开不用这个服务,过一段时间再尝试请求一下,如果还是失败,就继续断开