Hystrix概述.
Hytrix工作原理:https://github.com/Netflix/Hystrix/wiki/How-it-Works#benefits-of-thread-pools
spring cloud 用的是 hystrix,是一个容错组件。Hystrix实现了 超时机制和断路器模式。
Hystrix是Netflix开源的一个类库,用于隔离远程系统、服务或者第三方库,防止级联失败,从而提升系统的可用性与容错性。
Hystrix主要有以下几点功能:
- 为系统提供保护机制。在依赖的服务出现高延迟或失败时,为系统提供保护和控制。
- 防止雪崩。
- 包裹请求:使用HystrixCommand(或HystrixObservableCommand)包裹对依赖的调用逻辑,每个命令在独立线程中运行。
- 跳闸机制:当某服务失败率达到一定的阈值时,Hystrix可以自动跳闸,停止请求该服务一段时间。
- 资源隔离:Hystrix为每个请求都的依赖都维护了一个小型线程池,如果该线程池已满,发往该依赖的请求就被立即拒绝,而不是排队等候,从而加速失败判定。防止级联失败。
- 快速失败:Fail Fast。同时能快速恢复。侧重点是:(不去真正的请求服务,发生异常再返回),而是直接失败。
- 监控:Hystrix可以实时监控运行指标和配置的变化,提供近实时的监控、报警、运维控制。
- 回退机制:fallback,当请求失败、超时、被拒绝,或当断路器被打开时,执行回退逻辑。回退逻辑我们自定义,提供优雅的服务降级。
- 自我修复:断路器打开一段时间后,会自动进入“半开”状态,可以进行打开,关闭,半开状态的转换。前面有介绍。 ```powershell 1、设置失败次数阈值、http请求线程池
2、发出一个远程调用请求,消耗一个线程
3、判断连接超时,如果超时,记录超时次数,并将服务记录下来
4、根据重试配置重试,依旧失败
5、返回服务降级处理
6、当失败次数到达阈值时进行服务熔断,后续请求不发起远程调用,直接返回降级处理结果
7、一定时间后再次尝试远程调用,成功返回则取消熔断
<a name="vEHyX"></a>
### 单独使用Hytrix
```powershell
package com.ixiaoyu2.web.hystrix;
import com.netflix.hystrix.HystrixCommand;
import com.netflix.hystrix.HystrixCommandGroupKey;
import com.netflix.hystrix.HystrixThreadPoolKey;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
/**
* @author :Administrator
* @date :2022/4/19 0019
*/
public class HystrixDemo extends HystrixCommand {
protected HystrixDemo(HystrixCommandGroupKey group) {
super(group);
}
protected HystrixDemo(HystrixCommandGroupKey group, HystrixThreadPoolKey threadPool) {
super(group, threadPool);
}
@Override
protected Object run() throws Exception {
System.out.println("执行逻辑");
int i = 1 / 0;
return "执行结束,i=" + i;
}
@Override
protected Object getFallback() {
return "fallback,i=-1";
}
public static void main(String[] args) {
Future<String> futureResult = new HystrixDemo(HystrixCommandGroupKey.Factory.asKey("ext")).queue();
String res = "";
String s = null;
try {
s = futureResult.get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
System.out.println("结果:" + s);
}
}
RestTemplate整合Hystrix
手动模拟服务降级
@GetMapping("/users")
public List<User> query() {
List<User> list = new ArrayList<>(10);
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
for (int i = 0; i < 10; i++) {
list.add(new User(i + 1, "黑岩射手:number" + i + 1, 18 + i));
}
return list;
}
@HystrixCommand(fallbackMethod = "fallback")
public List<User> users() {
String path = servicePath("users");
return restTemplate.getForObject(path, List.class);
}
public List<User> fallback() {
List<User> users = new ArrayList<>();
users.add(new User(0, "我是替补", 19));
return users;
}
@GetMapping("/users")
public List<User> users() {
return consumerService.users();
}
spring:
application:
name: consumer
eureka:
client:
service-url:
defaultZone: http://ixiaoyu2:ixiaoyu2@127.0.0.1:7000/eureka
healthcheck:
enabled: true
ribbon:
ConnectTimeout: 1000
ReadTimeout: 3000
Feign整合Hystrix
public interface UserApi {
/**
* 获取全部用户
*
* @return 返回用户列表
*/
List<User> users();
/**
* 根据id获取用户
*
* @param id id
* @return 用户
*/
User oneUser(@RequestParam("id") Integer id);
/**
* 添加用户
*
* @param map 封装用户信息
* @return 新创建的用户
*/
User add(@RequestParam HashMap<String, String> map);
}
@RestController
public class ProviderController implements UserApi {
@Override
public List<User> users() {
List<User> list = new ArrayList<>(10);
for (int i = 0; i < 10; i++) {
list.add(new User(i + 1, "黑岩射手:number" + i + 1, 18 + i));
}
return list;
}
@Override
public User oneUser(Integer id) {
try {
// 模拟业务超时
System.out.println("要睡4s啦~");
Thread.sleep(4000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("接收的id: " + id);
return new User(id, "Black Rock Shooter", id + 1);
}
@Override
public User add(HashMap<String, String> map) {
System.out.println(map);
return new User(1, map.get("name"), Integer.parseInt(map.get("age")));
}
}
@FeignClient(name = "provider", fallback = AliveBack.class)
@Qualifier
public interface UserService extends UserApi {
@GetMapping("provider/users")
@Override
List<User> users();
@GetMapping("provider/user")
@Override
User oneUser(Integer id);
@PostMapping("provider/user")
@Override
User add(HashMap<String, String> map);
}
@Component
public class AliveBack implements UserService {
@Override
public List<User> users() {
List<User> list = new ArrayList<>();
list.add(new User(0, "我是替补", 19));
return list;
}
@Override
public User oneUser(Integer id) {
return new User(1, "w我是替补", 19);
}
@Override
public User add(HashMap<String, String> map) {
return new User(1, "w我是替补", 19);
}
}
@RestController
@RequestMapping("consumer")
public class ConsumerController {
@Autowired
@Qualifier
UserService userService;
@GetMapping("/users")
public List<User> users() {
return userService.users();
}
@GetMapping("/user")
public User oneUser(Integer id) {
return userService.oneUser(id);
}
@PostMapping("/user")
public User oneUser2(@RequestParam HashMap<String, String> map) {
System.out.println(map);
return userService.add(map);
}
}
spring:
application:
name: consumer
eureka:
client:
service-url:
defaultZone: http://ixiaoyu2:ixiaoyu2@127.0.0.1:7000/eureka
healthcheck:
enabled: true
server:
port: 8081
logging:
level:
com.ixiaoyu2: debug
ribbon:
# 连接超时时间(ms)
ConnectTimeout: 1000
# 业务逻辑超时时间(ms)
ReadTimeout: 4000
# 同一台实例最大重试次数,不包括首次调用
MaxAutoRetries: 1
# 重试负载均衡其他的实例最大重试次数,不包括首次调用
MaxAutoRetriesNextServer: 1
# 是否所有操作都重试
OkToRetryOnAllOperations: false
#开启Hystrix
feign:
hystrix:
enabled: true
注意:
(1)AliveBack实现了UserService,也是一个Feign实例,因此在ConsumerController注入时需要使用@Qualifier注解
(2)AliveBack实现了UserService,因此UserApi不能加@RequestMapping()注解
使用FallbackFactory
@Component
public class AFallBackFactory implements FallbackFactory<UserService> {
User user = new User(1, "替补xx", 0);
@Override
public UserService create(Throwable throwable) {
return new UserService() {
@Override
public List<User> users() {
System.out.println("异常信息如下:");
System.out.println(throwable.getLocalizedMessage());
System.out.println("异常堆栈信息如下:");
throwable.printStackTrace();
return Collections.singletonList(user);
}
@Override
public User oneUser(Integer id) {
System.out.println("异常信息如下:");
System.out.println(throwable.getLocalizedMessage());
System.out.println("异常堆栈信息如下:");
throwable.printStackTrace();
return user;
}
@Override
public User add(HashMap<String, String> map) {
System.out.println("异常信息如下:");
System.out.println(throwable.getLocalizedMessage());
System.out.println("异常堆栈信息如下:");
throwable.printStackTrace();
return user;
}
};
}
}
@FeignClient(name = "provider", fallbackFactory = AFallBackFactory.class)
@Qualifier
public interface UserService extends UserApi {
@Override
@GetMapping("provider/users")
List<User> users();
@Override
@GetMapping("provider/user")
User oneUser(@RequestParam Integer id);
@Override
@PostMapping("provider/user")
User add(@RequestBody HashMap<String, String> map);
}
信号量隔离与线程隔离
默认情况下hystrix使用线程池控制请求隔离
线程池隔离技术,是用 Hystrix 自己的线程去执行调用;
而信号量隔离技术,是直接让 tomcat 线程去调用依赖服务。信号量隔离,只是一道关卡,信号量有多少,就允许多少个 tomcat 线程通过它,然后去执行。
信号量隔离主要维护的是Tomcat的线程,不需要内部线程池,更加轻量级。
线程隔离
Hytrix 线程池大小为10,队列大小为5