Spring Cloud课题实验手册(五)

在本系列的 上一篇文章 中,我们演示了如何适用 Gateway 的限流功能。本文中,我们将演示如何使用 Hystrix 的熔断功能。

新建一个微服务项目

在 IDEA 中新建一个普通的 maven 项目,将其 groupId 命名为: cn.com.hohistar.tutorial, artifactId 命名为: springcloud-hystrix-service, 然后将项目的 pom.xml 替换为如下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
<?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>cn.com.hohistar.tutorial</groupId>
<artifactId>springcloud-hystrix-service</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>

<name>springcloud-hystrix-service</name>
<description>Demo project for Spring Boot</description>

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.5.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>
<spring-cloud.version>Finchley.SR1</spring-cloud.version>
</properties>

<dependencies>

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

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

<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.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.4</version>
<scope>provided</scope>
</dependency>

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

<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>

<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>

新增服务消费者

在本示例中,我们将构建一个访问(消费)前面建立的 todo-service 的类,并在该类的方法中使用熔断机制。

新建数据类

在 src/main/java 中新建一个名为: cn.com.hohistar.tutorial.springcloudhystrixservice.model 的包(package), 并在其中增加一个名为: Todo 的类, 代码如下:

1
2
3
4
5
6
7
8
9
10
@Data
public class Todo {

private Long id;

private String title;

private String desc;

}

因为所有的服务返回都别规范为 ApiResult 的格式,所以还需要加入 ApiResult 类的定义在 model 包中。 代码如下:

1
2
3
4
5
6
7
8
9
10
11
@Data
public class ApiResult<T> {

private Boolean succ;

private String code;

private String msg;

private T data;
}

定义访问服务

在 src/main/java 中新建一个名为: cn.com.hohistar.tutorial.springcloudhystrixservice.service 的包(package),并在其中新增一个名为: HystrixedClientService 的类, 并填入以下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
@Service
public class HystrixedClientService {

private static final Logger LOG = LoggerFactory.getLogger(HystrixedClientService.class);

@Autowired
RestTemplate restTemplate;

@HystrixCommand(fallbackMethod = "todoFailed")
public ApiResult< List<Todo> > getTodos() {

ApiResult< List<Todo> > resp = restTemplate.getForObject("http://cloud-todo-service/todo", ApiResult.class);

return resp;
}

public ApiResult<List<Todo>> todoFailed() {

LOG.info("todo failed");
ApiResult<List<Todo>> resp = new ApiResult<>();
resp.setSucc(false);
return resp;
}

@Bean
@LoadBalanced
public RestTemplate restTemplate() {

return new RestTemplate();
}

}

新建API服务

在 src/main/java 中新建一个名为: cn.com.hohistar.tutorial.springcloudhystrixservice.api 的包(package),并在其中新增一个名为: HystrixedClientController 的类, 并填入以下代码:

1
2
3
4
5
6
7
8
9
10
11
12
@RestController
public class HystrixedClientController {

@Autowired
private HystrixedClientService clientService;

@GetMapping("/todo")
public ApiResult< List<Todo> > getTodos() {
return clientService.getTodos();
}

}

新建启动类

在 src/main/java 中新建一个名为: cn.com.hohistar.tutorial.springcloudhystrixservice 的包(package),并在其中新增一个名为: SpringcloudHystrixServiceApplication 的类, 并填入以下代码:

1
2
3
4
5
6
7
8
9
10
@EnableEurekaClient
@EnableCircuitBreaker
@SpringBootApplication
public class SpringcloudHystrixServiceApplication {

public static void main(String[] args) {

SpringApplication.run(SpringcloudHystrixServiceApplication.class, args);
}
}

建立配置文件

在 src/main/resource 目录中新建名为 application.yml 的文件,加入以下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
server:
port: 9090

spring:
application:
name: cloud-hystrix-service

eureka:
instance:
leaseRenewalIntervalInSeconds: 1
leaseExpirationDurationInSeconds: 2
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
healthcheck:
enabled: true
lease:
duration: 5

启动应用

启动应用,然后在浏览器中访问:

1
http://localhost:9090/todo

可以得到 todo-service 中返回的 json 数据。类似如下:

1
succ":true,"code":null,"msg":null,"data":[{"id":1,"title":"Call Metting","desc":""},{"id":2,"title":"Print File","desc":""}]}

验证熔断机制

Hystrix默认的超时时间是1秒,也就是服务消费者在等待服务提供者返回信息时,如果超过1秒没有得到返回信息的话,就认为服务提供者故障,直接执行本地设置的降级策略,也就是fallbackMethod指定的方法。

因此我们修改 todo-service 项目,将 cn.com.hohistar.tutorial.springcloudtodoservice.service 包中的 TodoService 类的方法中加入强制延迟 20 秒, 修改后的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@RestController
public class TodoService {

@GetMapping("/todo")
public List<Todo> getAllTodo() {

List<Todo> todos = new ArrayList<>();

Todo t = new Todo();
t.setTitle("make a call");
t.setDesc("call jack");

todos.add(t);

try {
Thread.currentThread().sleep(20 * 1000);
} catch(Exception e) {
e.printStackTrace();
}

return todos;
}
}

这时再访问

1
http://localhost:9090/todo

可以看到返回的结果为空的 json 数组,并且在后台的日志中能看到 todoFailed 方法被执行了。

修改默认的超时时间

可在 application.yml 中加入一下内容,将超时时间设置为3秒:

1
2
3
4
5
6
7
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 3000

熔断配置项信息

Hystrix官方熔断配置项信息

本文标题:Spring Cloud课题实验手册(五)

文章作者:晨星

发布时间:2019年11月02日 - 19:11

最后更新:2020年05月28日 - 16:05

原始链接:https://www.mls-tech.info/microservice/spring-cloud/springcloud-practise-manual-05/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。