Dubbo中没有提供熔断限流和自动权重调整等服务治理机制。因此,这里采用SpringCloud中的Hystrix实现服务熔断。
在微服务架构中,根据业务来拆分成一个个服务、服务与服务之间可以通过RPC相互调用。为了保证高可用,单个服务通常会集群部署。由于网络原因或者自身的原因,服务并不能保证100%可用,如果单个服务出现问题,调用这个服务就会出现线程阻塞,此时若有大量的请求涌入,servlet容器的线程资源会被消耗完毕,导致服务瘫痪。服务与服务之间的依赖性,故障会传播,会对整个微服务造成灾难性的严重后果,这就是服务故障的雪崩效应。
为了解决这一问题,业界采用熔断器模型。Netflix开源了Hystrix组件,实现了熔断器模型,SpringCloud对这一组件进行了整合,在微服务架构中,一个请求需要调用多个服务是非常常见的。
当较底层的服务出现故障,可能会导致连锁故障。当对特定的服务的调用的不可用达到一个阈值时(Hystrix是5秒20次)熔断器将会断开。
熔断器断开后,为了避免连锁故障,通过fallback方法可以直接返回一个固定值。
org.springframework.cloud
spring-cloud-starter-netflix-hystrix
2.2.3.RELEASE
@HystrixCommand(commandProperties = {
@HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value="10"),
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value="2000")
})
第一步和第二步和Provider相同,第三步,向服务消费者的Controller方法上加入@HystrixCommand注解,定义并指定熔断方法。
package com.funt.hello.dubbo.service.user.consumer.Controller;
import com.funt.hello.dubbo.service.user.api.UserService;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class UserController {
@Reference(version = "1.0.0")
private UserService userService;
@HystrixCommand(fallbackMethod = "hiError")
@GetMapping("/hi")
public String sayHi(){
return userService.sayHi();
}
/**
* 熔断方法
* @return
*/
public String hiError(){
return "hello hystrix";
}
}
除了服务阻塞,当服务抛出运行时异常时,也会触发熔断。为了掩饰实验效果,这里在服务提供者方法中抛出异常。
org.springframework.cloud
spring-cloud-starter-netflix-hystrix-dashboard
2.2.3.RELEASE
package com.funt.hello.dubbo.service.user.consumer.config;
import com.netflix.hystrix.contrib.metrics.eventstream.HystrixMetricsStreamServlet;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Arrays;
@Configuration
public class HystrixDashboardConfiguration {
@Bean
public ServletRegistrationBean getServlet(){
HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();
ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet);
registrationBean.setLoadOnStartup(1);
registrationBean.addUrlMappings("/hystrix.stream");
registrationBean.setName("HystrixMetricsStreamServlet");
return registrationBean;
}
}