【微服务架构】SpringCloud之断路器(hystrix)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u012081441/article/details/80814250

说在前面

在微服务架构中,根据业务来拆分成一个个的服务,服务与服务之间可以相互调用(RPC),在Spring Cloud可以用RestTemplate+Ribbon和Feign来调用。为了保证其高可用,单个服务通常会集群部署。由于网络原因或者自身的原因,服务并不能保证100%可用,如果单个服务出现问题,调用这个服务就会出现线程阻塞,此时若有大量的请求涌入,Servlet容器的线程资源会被消耗完毕,导致服务瘫痪。服务与服务之间的依赖性,故障会传播,会对整个微服务系统造成灾难性的严重后果,这就是服务故障的“雪崩”效应。

解决或缓解服务雪崩的方案

一般情况对于服务依赖的保护主要有3中解决方案:
(1)熔断模式:这种模式主要是参考电路熔断,如果一条线路电压过高,保险丝会熔断,防止火灾。放到我们的系统中,如果某个目标服务调用慢或者有大量超时,此时,熔断该服务的调用,对于后续调用请求,不在继续调用目标服务,直接返回,快速释放资源。如果目标服务情况好转则恢复调用。
(2)隔离模式:这种模式就像对系统请求按类型划分成一个个小岛的一样,当某个小岛被火少光了,不会影响到其他的小岛。例如可以对不同类型的请求使用线程池来资源隔离,每种类型的请求互不影响,如果一种类型的请求线程资源耗尽,则对后续的该类型请求直接返回,不再调用后续资源。这种模式使用场景非常多,例如将一个服务拆开,对于重要的服务使用单独服务器来部署,再或者公司最近推广的多中心。
(3)限流模式:上述的熔断模式和隔离模式都属于出错后的容错处理机制,而限流模式则可以称为预防模式。限流模式主要是提前对各个类型的请求设置最高的QPS阈值,若高于设置的阈值则对该请求直接返回,不再调用后续资源。这种模式不能解决服务依赖的问题,只能解决系统整体资源分配问题,因为没有被限流的请求依然有可能造成雪崩效应。

Netflix提供了一个叫Hystrix的类库,它实现了断路器模式。在微服务架构中,通常一个微服务会调用多个其他的微服务。一个相对低层级的服务失败可能造成上层应用的级联失败,服务访问量越大失败率越高。当断路打开的时候,这个调用就被终止了。打开的断路可以阻止级联失败。

启动EureKaserver工程(注册中心)和SpringCloud-Service工程(服务生产者)

可以参考:https://blog.csdn.net/u012081441/article/details/80708060

一、Feign中使用断路器

创建项目SpringCloud-Feign

pom.xml文件

<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>com.fit</groupId>
    <artifactId>SpringCloud-Feign</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.2.RELEASE</version>
        <relativePath /> <!-- lookup parent from repository -->
    </parent>

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

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-ribbon</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-feign</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-hystrix</artifactId>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Dalston.RC1</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
    <repositories>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>
</project>

application.yml文件

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8888/eureka/
server:
  port: 8765
spring:
  application:
    name: SpringCloud-Feign
feign:
   hystrix:
     enabled: true
hystrix:
   command: 
     default: 
       execution: 
        isolation:
         thread: 
          timeoutInMilliseconds: 1000

service层

@FeignClient(value = "SpringCloud-Service",fallback = UserServiceErrorImpl.class)
public interface UserService {  
    @RequestMapping(value ="getUser")
    public Map<String,Object> getUser();
}

UserServiceErrorImpl.java 实现UserService 接口,并注入到Ioc容器中,代码如下:

@Component
public class UserServiceErrorImpl implements UserService {
    public Map<String, Object> getUser() {
        // TODO Auto-generated method stub
        Map<String, Object> errorMap = new HashMap<String, Object>();
        errorMap.put("code", "500");
        errorMap.put("message", "后台异常");
        return errorMap;
    }
}

FeignApp.java文件

@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
public class FeignApp {
    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        SpringApplication.run(FeignApp.class, args);
    }
}

验证断路器
启动SpringCloud-Feign项目,停掉SpringCloud-Service,访问http://localhost:8765/getUser,返回如下图,说明断路器起作用了:
这里写图片描述

二、在ribbon使用断路器

创建项目SpringCloud-Consumer

pom.xml文件如下:

<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>com.fit</groupId>
  <artifactId>SpringCloud-Consumer</artifactId>
  <version>0.0.1-SNAPSHOT</version>
   <!-- SpringBoot父类依赖引用 -->
   <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.2.RELEASE</version>
        <relativePath />
    </parent>

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

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-ribbon</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-hystrix</artifactId>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Dalston.RC1</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

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

    <repositories>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>

</project>

application.yml

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8888/eureka/
server:
  port: 8764
spring:
  application:
    name: SpringCloud-Consumer
hystrix:
   command: 
     default: 
       execution: 
        isolation:
         thread: 
          timeoutInMilliseconds: 1000

service层

@Service
public class UserService {
    @Autowired
    private RestTemplate restTemplate;
    @HystrixCommand(fallbackMethod = "getServiceUserError")
    public Map<String,Object> getServiceUser(){
        @SuppressWarnings("unchecked")
        Map<String,Object> user = restTemplate.getForObject("http://SpringCloud-Service/getUser", Map.class);
        return user;
    }
    public Map<String,Object> getServiceUserError(){
        // TODO Auto-generated method stub
        Map<String, Object> errorMap = new HashMap<String, Object>();
        errorMap.put("code", "500");
        errorMap.put("message", "后台异常");
        return errorMap;
    }
}

controller层

@Controller
public class ConsumerUserController {

    @Resource
    private UserService userService;

    @ResponseBody
    @RequestMapping(value ="getServiceUser")
    public Map<String,Object> getServiceUser(){
        Map<String,Object> user = userService.getServiceUser();
        return user;
    }
}

SpringCloudConsumerApp.java

@EnableEurekaClient
@EnableHystrix
@SpringBootApplication
public class SpringCloudConsumerApp {

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        SpringApplication.run(SpringCloudConsumerApp.class, args);
    }
    @Bean
    @LoadBalanced // 添加负载均衡支持
    RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

验证断路器
启动SpringCloud-Consumer项目,停掉SpringCloud-Service,访问http://localhost:8764/getServiceUser,返回如下图,说明断路器起作用了:
这里写图片描述

案例下载

猜你喜欢

转载自blog.csdn.net/u012081441/article/details/80814250