一、什么是服务雪崩
1.分布式系统中经常会出现某个基础服务不可用造成整个系统不可用的情况, 这种现象被称为服务雪崩效应. 为了应对服务雪崩, 一种常见的做法是手动服务降级. 而Hystrix的出现,给我们提供了另一种选择.下面这张图片讲解一下实例中雪崩效应。
二、模拟服务雪崩
1.压力测试
我使用的压力测试工具是:apache的jmeter,这是一个非常好用的给工具,我们可以通过它来达到我们的服务雪崩效应,在这块我们还要设置tomcat的最大连接数,不然我们压力测试会呈现不出来效果,下面我会把所有的工程代码贴出来,老是让你们看上篇博客,我自己看着都有点懵逼,在这个博客中我将会贴出所有的测试代码。
2.jmeter压测工具界面(在这里我模拟了1000个线程,把效果演示出来了)
三、项目代码
1.Eureka项目代码,你们还是参考我之前的博客,这个注册中心我基本上是没有修改过,博客地址:https://blog.csdn.net/chenmingxu438521/article/details/90513283
2.项目demo-service-member
2.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>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>demo-service-member</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo-service-member</name>
<description>Demo project for Spring Boot</description>
<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.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</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>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>
2.2.application.yml
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8888/eureka/
server:
port: 8763
spring:
application:
name: demo-service-member
2.3.controller
@RestController
public class MemberController {
@Value("${server.port}")
private String serverPort;
private static int count = 0;
@RequestMapping("/getMemberAll")
public List<String> getMemberAll() {
try{
Thread.sleep(3000);
}catch (Exception e){
}
count++;
List<String> listUser = new ArrayList<String>();
listUser.add("zhangsan");
listUser.add("lisi");
listUser.add("cmx");
listUser.add("count"+count);
System.out.println("count:" + count);
listUser.add("serverPort:"+serverPort);
return listUser;
}
@RequestMapping("/getMemberServiceApi")
public String getMemberServiceApi(){
return "this is 会员服务工程";
}
}
2.4.启动类
@SpringBootApplication
@EnableEurekaClient
public class DemoServiceMemberApplication {
public static void main(String[] args) {
SpringApplication.run(DemoServiceMemberApplication.class, args);
}
}
3.项目demo-service-order
3.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>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>demo-service-order</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo-service-order</name>
<description>Demo project for Spring Boot</description>
<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.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>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>
3.2.application.yml
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8888/eureka/
server:
port: 8764
spring:
application:
name: demo-service-order
3.3.controller
@RestController
public class OrderController {
@Autowired
private OrderMemberService orderMemberService;
@RequestMapping("/getOrderUserAll")
public List<String> getOrderUserAll() {
System.out.println("订单服务开始调用会员服务");
return orderMemberService.getOrderUserAll();
}
@RequestMapping("/getOrderServiceApi")
public String getOrderServiceApi(){
return "this is order 服务工程";
}
}
3.4.service
@Service
public class OrderMemberService {
@Autowired
private RestTemplate restTemplate;
public List<String> getOrderUserAll() {
return restTemplate.getForObject("http://demo-service-member/getMemberAll", List.class);
}
}
3.5.启动类
@SpringBootApplication
@EnableEurekaClient
public class DemoServiceOrderApplication {
public static void main(String[] args) {
SpringApplication.run(DemoServiceOrderApplication.class, args);
}
@Bean
//开启负载均衡
//@LoadBalanced
RestTemplate restTemplate() {
return new RestTemplate();
}
}
4.项目demo-serviceorder-fegin
4.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>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>demo-serviceorder-fegin</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo-serviceorder-fegin</name>
<description>Demo project for Spring Boot</description>
<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>
</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>
4.2.application.yml
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8888/eureka/
server:
port: 8765
tomcat:
max-threads: 50 //设置tomcat最大访问连接
spring:
application:
name: demo-serviceorder-feign
4.3.controller
@RestController
public class FeignMemberController {
@Autowired
private MemberFeign memberFeign;
@RequestMapping("/getFeignOrderByUserList")
public List<String> getFeignOrderByUserList() {
System.out.println("order fegin 工程调用member工程");
return memberFeign.getOrderByUserList();
}
@RequestMapping("/getOrderInfo")
public String getOrderInfo(){
return "getOrderInfo";
}
}
4.4.service
@FeignClient("demo-service-member")
public interface MemberFeign {
@RequestMapping("/getMemberAll")
public List<String> getOrderByUserList();
}
4.5.启动类
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
public class DemoServiceorderFeginApplication {
public static void main(String[] args) {
SpringApplication.run(DemoServiceorderFeginApplication.class, args);
}
}
5.测试产生雪崩的效果图
5.1.如下图(看红框一直在转圈,这就证明了那1000个线程压测阻塞,造成的服务雪崩的问题)
四、解决雪崩的问题
五、代码实战(使用Hystrix)
1.服务降级处理
1.1.修改demo-service-fegin项目
1.2.pom.xml(添加依赖hystrix)
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
</dependency>
1.3.application.yml
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8888/eureka/
server:
port: 8765
tomcat:
max-threads: 50
spring:
application:
name: demo-serviceorder-feign
feign:
hystrix:
enabled: true //开启熔断
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 100000 //默认1000就会去调用fallback
1.4.fallback(项目结构)包
@Component
public class MemberFallBack implements MemberFeign {
@Override
public List<String> getOrderByUserList() {
//服务降级处理
List<String> list = new ArrayList<String>();
list.add("服务发生异常...");
return list;
}
}
3.修改MemberFeign接口
@FeignClient(value = "demo-service-member",fallback = MemberFallBack.class)
public interface MemberFeign {
@RequestMapping("/getMemberAll")
public List<String> getOrderByUserList();
}
4.效果图
六、同时也能解决了我们的雪崩效应了
1.如下图(响应很快):