整体资源快不够了,忍痛将某些服务先关掉,待渡过难关,再开启。
服务降级的处理是在客户端实现完成的,与服务端没有关系。
我们去银行排队办理业务,大部分的银行分为 普通窗口、特殊窗口(VIP窗口,老年窗口)。
某一天,银行大厅 普通窗口 的人过多,这时 特殊窗口的工作人员 贴出告示:暂停服务,某时刻之后再开放
—— 这就是 服务降级。
特殊窗口的工作人员就可以空出来去帮助 普通窗口 办理业务,提高办事效率,解决 普通窗口 排队人过多。
这就是 降级,降级的目的是为了解决整体项目的压力,而牺牲掉某个服务模块而采取的措施。
贴出告示:暂停服务,某时刻之后再开放
,是给在特殊窗口 办理业务的人的一个告知响应。
一般是某个服务故障或者是异常引起的,类似现实世界中的 保险丝 ,当某个异常条件被触发,直接熔断整个服务,而不是一直等待,直到此服务超时。
生活中每家每户都在用电,小明家的电线因为故障导致了小明家停电了,
而隔避的小李、小张家的用电是正常使用的。
电力公司没有因为小明家有故障线路而停掉其他人家的电,同时小明家没有使用有故障的电路的电。
这就是 熔断。
熔断的目的是当A服务模块中的某块程序出现故障后为了不影响其他客户端的请求而做出的及时回应。
触发原因不太一样:
服务降级一般是从 整体负荷考虑;
服务熔断一般是 某个服务(下游服务)故障引起 ;
管理目标的层次不太一样:
降级一般需要对业务有层级之分(核心业务,非核心业务);
熔断 其实是一个框架级的处理,每个微服务都需要(无层级之分),
1) 代码:
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-hystrixartifactId>
dependency>
@RestController
public class DeptController {
@Autowired
private DeptService service; //DeptService 中调用DeptDao ,DeptDao 调用的是通过 mybatis 调用mysql 数据库。
@RequestMapping(value = "/dept/get/{id}", method = RequestMethod.GET)
@HystrixCommand(fallbackMethod = "processHystrix_Get") // processHystrix_Get 对应的响应方法
public Dept get(@PathVariable("id") Long id) {
Dept dept = this.service.get(id);
if (null == dept) {
throw new RuntimeException("该ID:" + id + "没有没有对应的信息");
}
return dept;
}
public Dept processHystrix_Get(@PathVariable("id") Long id) {
return new Dept().setDeptno(id).setDname("该ID:" + id + "没有没有对应的信息,null--@HystrixCommand")
.setDb_source("no this database in MySQL");
}
}
@SpringBootApplication
@EnableEurekaClient // 本服务启动后会自动注册进eureka服务中
@EnableCircuitBreaker // 对hystrixR熔断机制的支持
public class DeptProvider8001_Hystrix_App {
public static void main(String[] args) {
SpringApplication.run(DeptProvider8001_Hystrix_App.class, args);
}
}
2)测试:
请求 http://127.0.0.1/dept/get/{id}
,
当 id 的值 在数据库中有数据时,正常返回;
当 id 的值在数据库不存在时,则抛出 RuntimeException
异常时,被 @HystrixCommand
注释指定的 processHystrix_Get
方法拦截,并返回 processHystrix_Get()
中已经设定好的值。
3) 疑问:
当 则抛出
RuntimeException
等异常时,用统一的异常(下面有代码),也可以给出响应信息, 我感觉 Hystrix 的熔断 用处不大。
@ControllerAdvice
public class GlobalExceptionHandler {
private static final Logger LOG = LoggerFactory.getLogger(GlobalExceptionHandler.class);
@ResponseBody
@ExceptionHandler(value={Exception.class,RuntimeException.class})
public R handlerException(Exception ex) {
ex.printStackTrace();
LOG.error("handlerException 异常【{}】",ex);
return R.exception();
}
//省略 .....
}
1) 代码
Hystrix 与 Feign 配合使用
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-feignartifactId>
dependency>
feign:
hystrix:
enabled: true
fallbackFactory=DeptClientServiceFallbackFactory.class
指定降级的调用类。
@FeignClient(value = "MICROSERVICECLOUD-DEPT",fallbackFactory=DeptClientServiceFallbackFactory.class)
public interface DeptClientService {
@RequestMapping(value = "/dept/get/{id}", method = RequestMethod.GET)
public Dept get(@PathVariable("id") long id);
@RequestMapping(value = "/dept/list", method = RequestMethod.GET)
public List<Dept> list();
@RequestMapping(value = "/dept/add", method = RequestMethod.POST)
public boolean add(Dept dept);
}
DeptClientServiceFallbackFactory 的定义
@Component // 不要忘记添加,不要忘记添加
public class DeptClientServiceFallbackFactory implements FallbackFactory<DeptClientService> {
@Override
public DeptClientService create(Throwable throwable) {
return new DeptClientService() {
@Override
public Dept get(long id) {
return new Dept().setDeptno(id).setDname("该ID:" + id + "没有没有对应的信息,Consumer客户端提供的降级信息,此刻服务Provider已经关闭")
.setDb_source("no this database in MySQL");
}
@Override
public List<Dept> list() {
return null;
}
@Override
public boolean add(Dept dept) {
return false;
}
};
}
}
@RestController
public class DeptController {
@Autowired
private DeptClientService service ;
@RequestMapping(value = "/consumer/dept/get/{id}")
public Dept get(@PathVariable("id") Long id) {
return service.get(id);
}
@RequestMapping(value = "/consumer/dept/list")
public List<Dept> list() {
return service.list();
}
@RequestMapping(value = "/consumer/dept/add")
public Object add(Dept dept) {
return service.add(dept);
}
}
Dept 服务的代码
参考下面的 4.1、Hystrix 服务熔断
2)测试
请求 http://127.0.0.1/consumer/dept/get/{id}
,
当 Dept 服务正常运行时,无论id是否存在,都可能返回响应信息。
当 Dept 服务 关闭后,则返回 DeptClientServiceFallbackFactory
中定义的对应方法的响应信息