说明:Feign技术是用来连接微服务之间通信的。在微服务框架中,当服务A接收到请求,因为宕机或者其他原因,迟迟未做出响应时,发送请求的服务B一直处于“等待中”,而期间还将接收到其他服务(服务C)发来的请求,这会不断地消耗服务B的资源,造成服务B的宕机,同样的,因为服务B的宕机,又会造成服务C的宕机,这一连锁反应称为雪崩。
为了解决雪崩问题,可以配置Feign的降级处理方案,当请求未能正常处理时,执行降级处理方案,即对请求进行打折扣响应。
环境搭建:创建两个服务,订单服务、用户服务。查询订单时,订单服务会发请求给用户服务,查询该订单对应的用户信息。注册中心使用Nacos,服务间通信使用Feign。
Nacos
用户服务客户端(UserServiceClient)
import com.hzy.pojo.User;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.*;
/**
* 用户服务客户端
*/
@FeignClient(value = "userservice")
public interface UserServiceClient {
/**
* 查询用户
* @param id
* @return
*/
@GetMapping("/user")
User getUser(@RequestParam Long id);
}
订单查询业务代码
@Autowired
private UserServiceClient userServiceClient;
@Override
public Order getOrder(Long id) {
// 查询订单
Order order = orderMapper.getOrder(id);
// 使用订单中的用户ID查询用户信息
User user = userServiceClient.getUser(order.getUserId());
// 设置用户信息
order.setUser(user);
return order;
}
测试,效果如下
在用户服务这边的Controller层中手动设置异常,使请求不能被成功处理
@Autowired
private UserService userService;
@GetMapping
public User getUser(Long id){
// 手动设置异常
System.out.println(1/0);
return userService.getUser(id);
}
此时,订单服务向用户服务发送了请求,因为用户服务未能成功处理请求,导致订单也不能正常返回请求。
以上是微服务框架中出现的问题,因为一个请求需要多个服务共同完成,其中一个服务的错误会导致整个请求的错误。在Feign中,可以使用降级处理方案解决此类问题,降级方案有以下两种实现。
另外,需要注意的是,降级处理方案和Feign客户端一样,是写在发送请求的一方的,编写降级处理方案前,要在配置文件中开启feign的熔断器
# 2. feign配置
feign:
# 微服务保护组件 熔断器
hystrix:
enabled: true
方案一:
方案一是直接设置降级方案类,实现用户服务客户端接口,对接口内的方法进行实现
import com.hzy.pojo.User;
import org.springframework.stereotype.Component;
/**
* Feign的降级方案一
*/
@Component
public class UserServiceClientFallback implements UserServiceClient {
/**
* 降级方案为查询用户失败时,返回一个空的用户对象
* @param id
* @return
*/
@Override
public User getUser(Long id) {
System.out.println("启动降级方案");
return new User();
}
}
用户服务客户端,在@FeignClient()注解中,添加fallback,指定降级处理方案的类
import com.hzy.pojo.User;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.*;
/**
* 用户服务客户端
*/
@FeignClient(value = "userservice",fallback = UserServiceClientFallback.class)
public interface UserServiceClient {
/**
* 查询用户
* @param id
* @return
*/
@GetMapping("/user")
User getUser(@RequestParam Long id);
}
启动测试,可以看到订单模块的查询结果有返回,只不过用户信息是null,因为用户服务那边有错误,于是请求了降级方案,返回了空对象。
方案二:
方案一有一个缺点,无法知道请求因为什么原因走的降级方案,即错误的原因无法排查,方案二在这点优于方案一
实现FallbackFactory,泛型指定为UserServiceClient,实现create方法
import com.hzy.pojo.User;
import feign.hystrix.FallbackFactory;
import org.springframework.stereotype.Component;
/**
* Feign的降级方案二
*/
@Component
public class UserServiceClientFallback2 implements FallbackFactory<UserServiceClient> {
/**
* 降级方案二处理
* @param throwable
* @return
*/
@Override
public UserServiceClient create(Throwable throwable) {
return new UserServiceClient() {
// 返回空对象,并打印异常信息
@Override
public User getUser(Long id) {
System.out.println("降级方案二");
System.out.println("throwable.getMessage() = " + throwable.getMessage());
return new User();
}
};
}
}
用户服务客户端,在@FeignClient()注解中,添加fallbackFactory ,指定降级处理方案的类
import com.hzy.pojo.User;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.*;
/**
* 用户服务客户端
*/
@FeignClient(value = "userservice",fallbackFactory = UserServiceClientFallback2.class)
public interface UserServiceClient {
/**
* 查询用户
* @param id
* @return
*/
@GetMapping("/user")
User getUser(@RequestParam Long id);
}
启动测试,可以看到也达到了效果,并打印了异常信息
总结
在微服务框架中,Feign的降级处理方案,可以在当服务未能正常处理请求时(如宕机、超时),返回一个打折扣的请求。这种处理思想需要和异常处理区别开,异常处理是对异常的安排,如异常捕获、打印内容等等;而降级处理方案,是对请求未能正常执行的安排。