SpringCloud之熔断(六)

我们耳熟能详的就是Netflix Hystrix,这个断路器是SpringCloud中最早支持的一种容错方案,现在这个断路器已经处于维护状态,已经不再更新了。Hystrix官方推荐使用Resilience4j。

关于Netflix为什么会宣布停止在开源版本上提供新功能,目前官方并没有给出原因,只是提供了一些解决方案。但我看到Netflix官方博客的一篇文章,也许能找到技术层面的考量:Netflix 现在正在探索更自动化的熔断方式。所以我们猜测Netflix内部会逐步不再使用Hystrix ,没有继续更新的动力;再加上 Hystrix 作为一个熔断降级组件已经非常稳定了,因此停止开发是可以理解的。另一个是非技术层面,技术的开源是需要业务的增长和完整的技术团队来支撑的,无论是国内还是国外,开源项目能否持续,依赖于企业在技术上是否能长期投入。通知原文地址

现在还有阿里开发的sentinel 也可以作为熔断器

功能对比:

 SentinelHystrixresilience4j
隔离策略 信号量隔离(并发控制) 线程池隔离/信号量隔离

信号量隔离

熔断降级策略 基于慢调用比例、异常比例、异常数 基于异常比例 基于异常比例、响应时间
实时统计实现 滑动窗口(LeapArray) 滑动窗口(基于 RxJava) Ring Bit Buffer
动态规则配置 支持多种数据源 支持多种数据源 有限支持
扩展性 多个扩展点 插件的形式 接口的形式
基于注解的支持 支持 支持 支持
限流 基于 QPS,支持基于调用关系的限流 有限的支持 Rate Limiter
流量整形 支持预热模式与匀速排队控制效果 不支持 简单的 Rate Limiter 模式
系统自适应保护 支持 不支持 不支持
多语言支持 Java/Go/C++ Java Java
Service Mesh 支持 支持 Envoy/Istio 不支持 不支持
控制台 提供开箱即用的控制台,可配置规则、实时监控、机器发现等 简单的监控查看 不提供控制台,可对接其它监控系统

Sentinel不创建线程依赖tomcat或jetty容器的线程池,存在的问题就是运行容器的线程数量限制了sentinel设置值的上限可能设置不准。比如tomcat线程池为10,sentinel设置100是没有意义的,同时隔离性不好hystrix使用自己创建的线程池,隔离性会更好

 例子:使用nacos+sentinel

在https://github.com/alibaba/nacos下载nacos服务

默认地址:http://127.0.0.1:8848/nacos,用户和密码是:nacos

建立项目结构,一个提供者和消费者

 在父类pom配置相关版本,本来打算使用最新Hoxton.SR10+com.alibaba.cloud,2.2.5.RELEASE,结果发现出现错误:https://github.com/alibaba/spring-cloud-alibaba/issues/1974

Requested bean is currently in creation: Is there an unresolvable circular reference

看来版本间还是有点问题,就换成了低一点的版本Hoxton.SR9+com.alibaba.cloud,2.2.5.RELEASE

版本之间关系

https://github.com/alibaba/spring-cloud-alibaba/wiki/%E7%89%88%E6%9C%AC%E8%AF%B4%E6%98%8E

 1.父类定义版本pom.xml

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>testnacos</artifactId>
    <packaging>pom</packaging>
    <version>1.0-SNAPSHOT</version>
    <modules>
        <module>nacos-provider</module>
        <module>nacos-consumer</module>
    </modules>

    <name>testnacos</name>
    <!-- FIXME change it to the project's website -->
    <url>http://www.example.com</url>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <spring-boot.version>2.3.2.RELEASE</spring-boot.version>
        <spring-cloud.version>Hoxton.SR9</spring-cloud.version>
        <spring-cloud.Alibaba.version>2.2.5.RELEASE</spring-cloud.Alibaba.version>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>${spring-cloud.Alibaba.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
</project>

提供者nacos-provider

pom.xml

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>testnacos</artifactId>
        <groupId>org.example</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>nacos-provider</artifactId>

    <name>nacos-provider</name>
    <!-- FIXME change it to the project's website -->
    <url>http://www.example.com</url>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
    </dependencies>

</project>

提供者的启动类和测试接口

@SpringBootApplication
@EnableDiscoveryClient
public class NacosProviderApplication {

    public static void main(String[] args) {
        SpringApplication.run(NacosProviderApplication.class, args);
    }

    @RestController
    class EchoController {
        @GetMapping("/echo/{param}")
        public String echo(@PathVariable("param") String param) {
            return "Hello Nacos Discovery " + param;
        }
    }
}

配置文件application.properties:

server.port=8070
spring.application.name=service-provider
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848

消费者nacos-consumer

pom.xml

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>testnacos</artifactId>
        <groupId>org.example</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>nacos-consumer</artifactId>

    <name>nacos-consumer</name>
    <!-- FIXME change it to the project's website -->
    <url>http://www.example.com</url>

    <properties>
        <spring-cloud-openfeign.version>2.2.6.RELEASE</spring-cloud-openfeign.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
            <version>${spring-cloud-openfeign.version}</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>
    </dependencies>
</project>

启动类NacosConsumerApplication,打开注册和服务调用注解

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class NacosConsumerApplication {
    @Autowired
    private ProviderClient providerClient;

    public static void main(String[] args) {
        SpringApplication.run(NacosConsumerApplication.class, args);
    }

    @RestController
    class EchoController {
        @GetMapping("/echo/{param}")
        public String echo(@PathVariable("param") String param) {
            return providerClient.echo(param);
        }
    }
}

定义远程调用ProviderClient

@FeignClient(value = "service-provider", fallback = ProviderClientFallback.class)
//@FeignClient(value="service-provider",fallbackFactory = ProviderClientFallbackFactory.class)
public interface ProviderClient {
    @GetMapping("/echo/{param}")
    String echo(@PathVariable("param") String param);
}

服务失败的回调ProviderClientFallback

@Component
public class ProviderClientFallback implements ProviderClient {
    @Override
    public String echo(String param) {
        return "echo-Fallback";
    }
}

也可以继承FallbackFactory进行回调,这样可以得到异常的信息

@Component
public class ProviderClientFallbackFactory implements FallbackFactory<ProviderClient> {
    @Override
    public ProviderClient create(Throwable cause) {
        System.out.println(cause.getMessage());
        return new ProviderClient() {
            @Override
            public String echo(String param) {
                return "FallbackFactory-echo";
            }
        };
    }
}

设置application.properties打开Sentinel

server.port=8081
spring.application.name=service-consumer
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
feign.sentinel.enabled=true
#feign.hystrix.enabled=true

整体项目结构

先启动消费服务nacos-consumer,然后在nacos服务中心观察注册情况

 发现已经注册到服务中心了,然后调用接口

 观察到执行到熔断的结果了,然后在运行提供服务nacos-provider。并观察nacos服务中心

 发现已经也注册到服务中心了,等待一段时间后在调用测试接口(因为消费者客户端定时会想服务中心查询服务列表)

发现成功调用接口

参考

https://developer.aliyun.com/article/633786

https://github.com/alibaba/Sentinel/wiki/Guideline:-%E4%BB%8E-Hystrix-%E8%BF%81%E7%A7%BB%E5%88%B0-Sentinel

https://www.sohu.com/a/282806665_268033

https://www.cnblogs.com/zhyg/p/11474406.html

原文地址:https://www.cnblogs.com/grasp/p/14451254.html