SpringCloud之Hystrix的入门实战

SpringCloud之Hystrix的入门实战

一、Hystrix的基础概念

1.1 Hystrix是什么

Hystrix是由Netflix开源的一个针对分布式系统容错处理的开源组件。2011-2012年相继诞生和成熟,Netflix公司很多项目都使用了它,Hystrix单词意为”豪猪”,浑身有刺来保护自己,Hystrix库就是这样一个用来捍卫应用程序健康的利器。

在这里插入图片描述
Hystrix官方代码托管在http://github.com/Netflix/Hystrix,大家可以登录查看相关的信息,官方首页上写着这么一段话:

Hystrix is a latency and fault tolerance library designed to isolate points of access to remote systems, services and 3rd party libraries, stop cascading failure and enable resilience in complex distributed systems where failure is inevitable.

大意是:Hystrix是一个延迟和容错库,旨在隔离远程系统、服务和第三方库,阻止级联故障,在复杂的分布式系统中实现恢复能力。

1.2 Hystrix用来做什么

为什么要使用Hystrix,它可以解决什么样的问题,这里引用官方Hystrix的图来解释一下,在应用拆分成多个服务的情况下:

  • 1.当用户需要请求APHI四个服务获取数据时,在平时正常流量情况下,系统稳定运行,如下图所示。

在这里插入图片描述

  • 2.某一天公司进行促销,效果明显使得超越平时几倍数量的用户涌入进来,对其中服务I并发超过50+,这时对服务I出现一定程度的影响,逐渐导致CPU、内存占用过高等问题,结果导致服务I延迟,响应过慢。如下图所示。

在这里插入图片描述

  • 3.随着压力持续增加,服务I承受不住压力或发生其他内部错误导致机器内部资源耗尽,请求堆积等情况使服务I彻底宕机不可用,更糟糕的情况是其他服务对I有依赖,导致其他服务也同样出现请求堆积,资源占用等问题,这时会导致整个系统出现大面积的延迟或瘫痪,直到整个系统不可用。如下图。

在这里插入图片描述
总结:在这种多系统和微服务的情况下,需要一种机制来处理延迟和故障,并保护整个系统处于可用稳定的状态,此时就是Hystrix大显身手的时候了。

详细图和官方解释可见官方Wiki:http://github.com/Netflix/Hystrix/wiki。

  • 4.最后通过服务熔断或降级的方法,来保证整个服务的可用,以防止服务雪崩。如下图。

在这里插入图片描述

1.3 Hystrix的实现的效果

Hystrix is designed to do the following:

  • Give protection from and control over latency and failure from dependencies accessed (typically over the network) via third-party client libraries.
  • Stop cascading failures in a complex distributed system.
  • Fail fast and rapidly recover.
  • Fallback and gracefully degrade when possible.
  • Enable near real-time monitoring, alerting, and operational control.

翻译过来的大意是:

1)通过客户端库对延迟和故障进行保护和控制。
2)在一个复杂的分布式系统中停止级联故障。
3)快速失败和迅速恢复。
4)在合理的情况下回退和优雅地降级。
5)开启近实时监控、告警和操作控制。

Hystrix底层大量使用了Rxjava,本节暂不解析源代码,如果想了解源代码可以先了解下Rxjava,对学习Hystrix底层源码会有很大的帮助。

二、快速入门

2.1 创建hystrix-parent父工程

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>
    <packaging>pom</packaging>
    <modules>
        <module>eureka-server</module>
        <module>client-server</module>
        <module>consumer-server</module>
        <module>provider-server</module>
    </modules>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.3.RELEASE</version>
    </parent>

    <groupId>com.gyoomi</groupId>
    <artifactId>hystrix-parent</artifactId>
    <version>1.0-SNAPSHOT</version>

    <!-- 管理依赖 -->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Finchley.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>


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



    <!--注意: 这里必须要添加, 否者各种依赖有问题 -->
    <repositories>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/libs-milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

2.2 创建eureka-server工程作为注册中心

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>hystrix-parent</artifactId>
        <groupId>com.gyoomi</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>client-server</artifactId>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <!-- hystrix的依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

application.yml

server:
  port: 8761
eureka:
  instance:
    hostname: localhost
  client:
    registerWithEureka: false
    fetchRegistry: false
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/

启动类

@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {

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

2.3 创建client-server工程作为服务提供方(使用熔断试验效果)

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>hystrix-parent</artifactId>
        <groupId>com.gyoomi</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>client-server</artifactId>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <!-- hystrix的依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

application.yml

server:
  port: 8888
spring:
  application:
    name: sc-client-service
eureka:
  client:
    serviceUrl:
      defaultZone: http://${eureka.host:127.0.0.1}:${eureka.port:8761}/eureka/
  instance:
    prefer-ip-address: true

启动类

@SpringBootApplication
@EnableHystrix
// 启动熔断器功能
@EnableDiscoveryClient
public class ClientApplication {
	
    public static void main(String[] args) {
        SpringApplication.run(ClientApplication.class, args);
    }
}

测试Controller及service类

TestController

@RestController
public class TestController {

    @Autowired
    private IUserService userService;

    @GetMapping(value = "/getUser")
    public String getUser(String username) throws Exception {
        return userService.getUser(username);
    }
}

IUserService

public interface IUserService {

    String getUser(String username) throws Exception;
}

UserServiceImpl

@Service
public class UserServiceImpl implements IUserService {


    @Override
    // 使用HystrixCommand注册为该方法开启熔断的降级方法
    @HystrixCommand(fallbackMethod = "defaultUser")
    public String getUser(String username) throws Exception {
        if ("hystrix".equals(username)) {
            return "hello hystrix, this is real user!!!";
        } else {
            throw new Exception();
        }
    }

    public String defaultUser(String usename) {
        return "The user does not exist in this system";
    }
}

依次启动eureka-server,client-server项目。使用浏览器或rest工具访问http://localhost:8888/getUser?username=hystrixhttp://localhost:8888/getUser?username=xxxx。分别返回hello hystrix, this is real user!!!, The user does not exist in this system。由此看见Hystrix的确起到了熔断的作用。

三、与Feign的整合实战

在Feign中,默认是自带Hystrix的功能的,在很老的版本中默认是打开的,只是最近的几个新的版本默认是关闭的,需要在配置文件中进行配置然后打开。

3.1 创建hystrix-parent父工程

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>
    <packaging>pom</packaging>
    <modules>
        <module>eureka-server</module>
        <module>client-server</module>
        <module>consumer-server</module>
        <module>provider-server</module>
    </modules>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.3.RELEASE</version>
    </parent>

    <groupId>com.gyoomi</groupId>
    <artifactId>hystrix-parent</artifactId>
    <version>1.0-SNAPSHOT</version>

    <!-- 管理依赖 -->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Finchley.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>


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



    <!--注意: 这里必须要添加, 否者各种依赖有问题 -->
    <repositories>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/libs-milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

3.2 创建eureka-server工程作为注册中心

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>hystrix-parent</artifactId>
        <groupId>com.gyoomi</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>client-server</artifactId>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <!-- hystrix的依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

application.yml

server:
  port: 8761
eureka:
  instance:
    hostname: localhost
  client:
    registerWithEureka: false
    fetchRegistry: false
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/

启动类

@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {

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

3.3 创建provider-server工程作为服务的提供者

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>hystrix-parent</artifactId>
        <groupId>com.gyoomi</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>provider-server</artifactId>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

application.yml

server:
  port: 7777
spring:
  application:
    name: sc-provider-service
eureka:
  client:
    serviceUrl:
      defaultZone: http://${eureka.host:127.0.0.1}:${eureka.port:8761}/eureka/
  instance:
    prefer-ip-address: true

启动类

@SpringBootApplication
@EnableDiscoveryClient
public class ProviderApplication {

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

对外提供的接口服务

@RestController
public class TestController {

	@RequestMapping(value = "/getUser",method = RequestMethod.GET)
	public String getUser(@RequestParam("username") String username) throws Exception{
		if(username.equals("hystrix")) {
			return "This is real user";
		}else {
			throw new Exception();
		}
	}
}

3.4 创建consumer-server工程作为服务的消费者

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>hystrix-parent</artifactId>
        <groupId>com.gyoomi</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>consumer-server</artifactId>


    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

application.xml

server:
  port: 8888
spring:
  application:
    name: sc-consumer-service
eureka:
  client:
    serviceUrl:
      defaultZone: http://${eureka.host:127.0.0.1}:${eureka.port:8761}/eureka/
  instance:
    prefer-ip-address: true
feign:
  hystrix:
    enabled: true #开启feign的熔断熔断功能。可以动态修改此值,进行访问接口查看效果。

启动类


@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
@EnableHystrix//开启熔断
public class ConsumerApplication {

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

访问接口

TestController

@RestController
public class TestController {

    @Autowired
    private IUserService userService;

    @RequestMapping(value = "/getUser",method = RequestMethod.GET)
    public String getUser(@RequestParam("username") String username) throws Exception{
        return userService.getUser(username);
    }
}

IUserService

@FeignClient(value = "sc-provider-service", fallback = UserServiceFallback.class)//这里指定熔断的默认方法
public interface IUserService {

    @GetMapping(value = "/getUser")
    String getUser(@RequestParam("username") String username) throws Exception;
}

UserServiceFallback

@Component
public class UserServiceFallback implements IUserService {

    /**
     * 出错则调用该方法返回友好错误
     *
     * @param username
     * @return
     * @throws Exception
     */
    @Override
    public String getUser(String username) throws Exception {
        return "The user does not exist in this system, please confirm username";
    }
}

3.5 测试

依次,启动eureka-server, provider-server, consumer-server工程,在开启熔断功能下,访问http://localhost:8888/getUser?username=hystrixhttp://localhost:8888/getUser?username=xxxx,查看效果。然后关闭熔断功能,再试试效果。这里就不展示,请大家动手做一下吧。

下一篇文章我会写一些Hystrix的进阶用法和实际开发中实战经验,敬请期待!

其他

  • 项目源码:案例源码
  • 个人开源的SpingCloud的脚手架项目 地址 喜欢的老铁欢迎给星星!!
  • 参考书籍及文献:《重新定义SpringCloud实战》 Hystrix官方Github库
发布了158 篇原创文章 · 获赞 147 · 访问量 27万+

猜你喜欢

转载自blog.csdn.net/weixin_39723544/article/details/102520282