在分布式系统中,如果服务提供者响应缓慢,会导致消费者请求等待,直到收到响应或超时。如果在高并发、高负载的场景下,会导致消费者大量线程等待服务提供者响应,持续下去的话很容易导致整个系统因为资源耗尽而崩溃。比如,电影服务作为上层的消费者,需要从下层的用户服务查询用户信息,这时候用户服务因为某些原因导致响应非常缓慢,正常只需要10毫秒的响应被延长到几十秒。电影服务持续不断收到外部请求,并等待用户服务响应,很快,电影服务自身也崩溃了。
因为依赖的服务不可用或不稳定时,导致自身被拖垮,分布式系统中时常会上演,这种情况也被称为“雪崩效应”。
那么,该如何防止雪崩效应呢?一般需要做两点:
- 设置网络请求超时时间,尽快释放系统资源,减少不必要的等待
- 使用熔断器,为系统安装过载保护功能
下面我们要介绍的Hystrix就是熔断器的一个实现。
Hystrix
Hystrix时Netflix开发的一个容错库,用于隔离远程调用,防止引发级联失败,避免雪崩效应。它类似于电路中的断路器,当系统超过了容忍的错误限度时,开启断路保护,阻止错误放大,从而提升系统的稳定性和容错性。
Hystrix主要提供以下功能:
- 代理请求,即使用HystrixCommand代理调用逻辑
- 跳闸保护,当某个依赖服务错误率达到设定的阀值,可以自动或手动开启跳闸,阻止继续请求依赖的服务
- 资源隔离,将依赖的服务放到单独的线程池中执行,避免过度资源占有和应用其他模块
- 回退机制,即在请求失败、超时、被拒绝等场景下,多断路器打开状态下,执行回退逻辑(快速失败),开发者自定义回退逻辑
- 自我修复,即断路器打开一段时间后会自动进入“半开”状态,并测试依赖的服务是否已经恢复,如果恢复,则将断路器关闭,即自动管理断路器的开启、半开和关闭状态
实战
修改用户服务
服务provider-user,并改名为provider-user-hystrix
修改用户服务代码
将findById方法修改成 i>=3时,抛出异常。
package com.huluohu.cloud.user.presentation.web;
import com.huluohu.cloud.user.presentation.mode.UserDTO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import java.util.Random;
import java.util.concurrent.atomic.AtomicInteger;
public class UserController {
private Random random = new Random();
private static volatile AtomicInteger counter = new AtomicInteger();
/**
* 查询用户
*
* @param id
* @return
*/
public UserDTO findById( { Integer id)
final int i = counter.incrementAndGet();
log.info("i========={}", i);
if (i >= 3) {
throw new RuntimeException("测试断路器");
}
return UserDTO.builder()
.id(id)
.username("root_" + id)
.name("huluohu_" + id)
.age(random.nextInt(30) % (30 - 15 + 1) + 15)
.balance(random.nextLong())
.build();
}
}
修改电影服务
复制consumer-movie-feign,并改名为consumer-movie-hystrix
添加依赖
pom.xml中增加以下hystrix的依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
</dependency>修改配置
在application-local.yml中增加hystrix配置
feign:
hystrix:
enabled: true #开启hystrix修改启动类
package com.huluohu.cloud.movie;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.feign.EnableFeignClients;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;
//开启hystrix
public class MovieApplication {
public static void main(String[] args) {
SpringApplication.run(MovieApplication.class, args);
}
}添加回退逻辑代码
创建回退逻辑类,该类型需要实现
UserServiceClient
并增加@Component
注解package com.huluohu.cloud.movie.application.client.hystrix;
import com.huluohu.cloud.movie.application.client.UserServiceClient;
import com.huluohu.cloud.movie.application.model.User;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.PathVariable;
public class UserServiceClientHystrix implements UserServiceClient {
public User findById( { Integer id)
return User.builder()
.username("random")
.name("default")
.age(0)
.balance(0L)
.build();
}
}设置回退逻辑类型
package com.huluohu.cloud.movie.application.client;
import com.huluohu.cloud.movie.application.client.hystrix.UserServiceClientHystrix;
import com.huluohu.cloud.movie.application.model.User;
import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.web.bind.annotation.*;
//设置回退逻辑类
public interface UserServiceClient {
/**
* 根据ID查询User
*
* @param id
* @return
*/
User findById(; Integer id)
}
测试
- 启动Eureka Server(local profile)
- 启动Config Server(不需要区分profile)
- 启动provider-user-hystrix(local profile)
- 启动consumer-movie-hystrix(local profile)
启动服务列表
服务注册情况
测试
使用浏览器或Postman访问
http://localhost:9009/test/user/1
3次,正常返回用户服务的结果此时,hystrix状态正常,断路器没有打开:
使用Postman Runner快速请求
http://localhost:9009/test/user/1
每次返回的结果都是默认值:
{
"id": null,
"username": "random",
"name": "default",
"age": 0,
"balance": 0
}此时,hystrix的断路器是打开的:
Hystrix监控
除了提供熔断功能外,Hystrix还提供了实时监控模块,可以对断路器的运行状态和指标进行监控。
查看Hystrix状态
在上面的例子中,consumer-movie-hystrix已经整合了Feign和Hystrix,并添加了spring-boot-starter-actuator
依赖,可以在浏览器中请求http://localhost:9009/hystrix.stream
,查看监控情况:
Hystrix使用hystrix-metrics-event-stream模块实现将监控指标以text/evanet-stream格式输出。
整合Dashboard
直接访问http://localhost:9009/hystrix.stream
返回的数据不太直观,我们可以通过整合Hystrix Dashboard,让数据可视化。
创建Maven项目
添加依赖
pom.xml添加dashboard依赖
<dependencies> |
添加配置
application.yml配置
spring: |
创建启动类
package com.huluohu.cloud.hystrix; |
测试
- 启动Eureka Server(local profile)
- 启动Config Server(不需要区分profile)
- 启动provider-user-hystrix(local profile)
- 启动consumer-movie-hystrix(local profile)
- 启动hystrix-dashboard(不区分profile)
应用列表
浏览器中打开
http://localhost:7777/hystrix
在上面图中url输入框中输入
http://localhost:9009/hystrix.stream
,Title输入框随意输入一个名字,然后点击Monitor Stream
按钮
到达监控页面,此时没用请求,监控数据都是初始值。
在Postman上执行查询用户接口测试,在查看监控页面
怎么样,很简单吧!