Skip to main content

服务保护

雪崩问题/级联失败问题

某个服务出现异常导致众多服务请求阻塞,导致集群不可用

解决方案:

  • 请求限流:限制或控制接口访问的并发流量,避免服务因流量激增而出现故障。

  • 线程隔离:将不同服务的请求分给不同的线程池,限制每个线程池的线程数量

  • 服务熔断:在线程隔离的基础上,避免大量请求在线程池前等待导致故障

    • 编写服务降级逻辑:就是服务调用失败后的处理逻辑,根据业务场景,可以抛出异常,也可以返回友好提示或默认数据。

    • 异常统计和熔断:统计服务提供方的异常比例,当比例过高表明该接口会影响到其它服务,应该拒绝调用该接口,而是直接走降级逻辑。

      • 可由断路器同级服务调用的异常比例、慢请求比例,若超出阈值则会熔断该服务。断路器仅开启一段时间,到达时间后进行一次放行测试,如果依然超出阈值,则继续熔断

服务保护技术

SentinelHystrix
线程隔离信号量隔离线程池隔离/信号量隔离
熔断策略基于慢调用比例或异常比例基于异常比例
限流基于QPS,支持流量整形有限的支持
Fallback支持支持
控制台开箱即用,可配置规则、查看秒级监控、机器发现等不完善
配置方式基于控制台,重启后失效基于注解或配置文件,永久生效

Sentinel

阿里巴巴开源的一款服务保护框架

Sentinel 的使用可以分为两个部分:

  • 核心库(Jar包):不依赖任何框架/库,能够运行于 Java 8 及以上的版本的运行时环境,同时对 Dubbo / Spring Cloud 等框架也有较好的支持。在项目中引入依赖即可实现服务限流、隔离、熔断等功能。

  • 控制台(Dashboard):Dashboard 主要负责管理推送规则、监控、管理机器信息等。

使用:

  1. 下载jar包:https://github.com/alibaba/Sentinel/releases

  2. 放在任意纯英文路径下,启动shell控制台,运行:

    java '-Dserver.port=8090' '-Dcsp.sentinel.dashboard.server=localhost:8090' '-Dproject.name=sentinel-dashboard' '-jar' sentinel-dashboard-1.8.6.jar

    其它启动时可配置参数可参考官方文档:https://b11et3un53m.feishu.cn/wiki/QfVrw3sZvihmnPkmALYcUHIDnff#AlXcdXIfQotaH9xDR32crYg5nyf

  3. 访问 http://localhost:8090 页面,就可以看到sentinel的控制台

    账号密码都是sentinel,登录后默认监控sentinel-dashboard本身

配置

  1. 引入sentinel依赖

    <!--sentinel-->
    <dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
    </dependency>
  2. 配置控制台

    修改application.yaml文件,添加下面内容:

    spring:
    cloud:
    sentinel:
    transport:
    dashboard: localhost:8090

    或者在Nacos中创建共享配置文件,内容相同,并在需要共享的微服务的bootstrap.yaml中加入

    spring:
    cloud:
    nacos:
    server-addr: 192.168.88.130:8848
    config:
    file-extension: yaml
    shared-configs:
    - data-id: shared-sentinel.yaml
    ……

簇点链路

是单机调用链路,是一次请求进入服务后经过的每一个被Sentinel监控的资源。默认情况下,Sentinel会监控SpringMVC的每一个Endpointhttp接口)。

/路由名这个接口路径就是其中一个簇点,可以对其进行限流、熔断、隔离等保护措施。

对于Restful风格设计来说,查询、删除、修改等接口全部都是同一个路径,区别在于请求方式不同,所以可以选择打开Sentinel的请求方式前缀,把请求方式 + 请求路径作为簇点资源名

只需要在配置sentinel的文件里加上一段配置就可打开:

spring:
cloud:
sentinel:
transport:
dashboard: localhost:8090
http-method-specify: true # 开启请求方式前缀

线程隔离

  1. OpenFeign整合Sentinel,修改application.yaml文件或Nacos里对fegin定义的内容,加入下面的内容:

    feign:
    sentinel:
    enabled: true # 开启feign对sentinel的支持
  2. 定义fallback内容

    在控制Fegin的微服务api下,创建client.fallback.服务名ClientFallbackFactory.java文件

    例子:

    @Slf4j
    public class ItemClientFallbackFactory implements FallbackFactory<ItemClient> {
    @Override
    public ItemClient create(Throwable cause) {
    return new ItemClient() {
    @Override
    public List<ItemDTO> queryItemByIds(Collection<Long> ids) {
    log.error("查询商品失败!", cause);
    return Collections.emptyList();
    }

    @Override
    public void deductStock(List<OrderDetailDTO> items) {
    log.error("扣减商品库存失败!", cause);
    throw new RuntimeException(cause);
    }
    };
    }
    }
  3. client同级的config目录下创建对应的.java文件,创建Bean容器

    例子:

    public class DefaultFeignConfig {
    @Bean
    public ItemClientFallbackFactory itemClientFallbackFactory() {
    return new ItemClientFallbackFactory();
    }
    }
  4. 在对应的服务名Client.java文件配置写好的fallbackfactory

例子:

@FeignClient(value = "item-service", fallbackFactory = ItemClientFallbackFactory.class)
public interface ItemClient {……}

在对应的微服务启动类中配置:

例子:这里是cart微服务在调用item,所以对应的启动类是cart

@EnableFeignClients(basePackages = "com.hmall.api.client", defaultConfiguration = DefaultFeignConfig.class)
@SpringBootApplication
public class CartApplication {
public static void main(String[] args) {
SpringApplication.run(CartApplication.class, args);
}
}

服务熔断