你要足够努力,才能够游刃有余
一直在纠结熔断设置在服务端提供端还是在消费者端;然后又想着如果在两端都设置的话,那么他们执行的顺序回是什么,在自己一个人瞎捣鼓几天之后,大概摸清一些,在消费端和服务提供端都设置了服务降级之后,我选择的是服务端controller,消费端controller和消费端熔断层hystrix。在服务端设置了容错之后,如果消费端没有设置会发生调用异常的错误,如果三处都设置了,如果是消费者端抛出的异常会在controller中处理,如果是在服务端则会是在hystrix层处理。而服务端的hystrix则可能因为openfrign的调用导致方法不生效。而不作处理。
服务熔断和服务降级
出于在消费端保护的更加方便和全面,让服务端更加的专注于数据操纵功能和业务逻辑的实现。我认为利用前端页面和在消费者端对数据进行检索和校验和差错处理更加的合适。
改pom
增加一个netflix-hystrix的依赖
<dependencies>
<!--Spring cloud Hoxton.SR1-->
<!--springboot 初始化和图形监控管理-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--Eureka-Client-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--注解注入功能-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--热部署-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.example</groupId>
<artifactId>cloud-api-book-commons</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!--Hystrix-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
</dependencies>
写yml
server:
port: 80
spring:
application:
name: cloud-book-consumer
CLOUD-BOOK-SERVICE:
ribbon:
#NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
#指的是建立连接所用的时间,适用于网络状况正常的情况下,两端连接所用的时间
ReadTimeout: 5000
#指的是建立连接后从服务器读取到可用资源所用的时间
ConnectTimeout: 5000
eureka:
client:
register-with-eureka: false
fetch-registry: true
service-url:
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
logging:
level:
# feign日志以什么级别监控哪个接口
com.atguigu.springcloud.service.PaymentFeignService: debug
feign:
hystrix:
enabled: true #开启服务容错保护功能
主启动
@SpringBootApplication
@EnableFeignClients
@EnableHystrix //开启容错保护注解
public class ConsumerBook80 {
public static void main(String[] args) {
SpringApplication.run(ConsumerBook80.class,args);
}
/**
* 用于dashboard
* 此配置是为了服务监控而配置,与服务容错本身无观,springCloud 升级之后的坑
* ServletRegistrationBean因为springboot的默认路径不是/hystrix.stream
* 只要在自己的项目中配置上下面的servlet即可
* @return
*/
@Bean
public ServletRegistrationBean getServlet(){
HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();
ServletRegistrationBean<HystrixMetricsStreamServlet> registrationBean = new ServletRegistrationBean<>(streamServlet);
registrationBean.setLoadOnStartup(1);
registrationBean.addUrlMappings("/hystrix.stream");
registrationBean.setName("HystrixMetricsStreamServlet");
return registrationBean;
}
}
service层
新建service接口,添加fallback方法
@Component
@FeignClient(value = "CLOUD-BOOK-SERVICE", fallback = BookHystrix.class) //eureka上的服务名,
public interface BookService {
@GetMapping(value = "/book/getAllBooks")
public CommonResult getAllBooks();
@RequestMapping(value = "/book/addBook")
public CommonResult addBook(@RequestBody BookInf book);
@PostMapping(value = "/book/updateBook")
public CommonResult updateBook(@RequestBody BookInf book);
@RequestMapping(value = "/book/deleteBook/{id}")
public CommonResult deleteBook(@PathVariable("id") int id);
@GetMapping(value = "/book/index/{id}")
public CommonResult index(@PathVariable("id") Integer id);
}
hystrix层
新建BookHystrix.class文件,继承service接口,对服务端方法进行保护
@Component
public class BookHystrix implements BookService {
@Override
public CommonResult getAllBooks() {
return new CommonResult(500,"error","查询图书详情时调用出现错误");
}
@Override
public CommonResult addBook(BookInf book) {
return new CommonResult(500,"80","添加图书详情时调用出现错误");
}
@Override
public CommonResult updateBook(BookInf book) {
return new CommonResult(500,"80","更新图书详情时调用出现错误");
}
@Override
public CommonResult deleteBook(int id) {
return new CommonResult(500,"80","删除图书详情时调用出现错误");
}
@Override
public CommonResult index(@PathVariable("id") Integer id) {
return new CommonResult(500,"80","index访问出现错误");
}
}
config层
原有的openfeign方法,设置feign日志的级别
@Configuration
public class FeignConfig {
@Bean
Logger.Level feignLoggerLevel(){
return Logger.Level.FULL;
} //记录请求和响应的头文件,正文和元数据。
}
controller层
产生异常时熔断和降级处理
@RestController
@Slf4j
@DefaultProperties(defaultFallback = "defaultFallbackMeth")
public class BookController {
@Resource
private BookService bookService;
@HystrixCommand(fallbackMethod = "getAllBooks_Hystrix",commandProperties = { //作服务降级
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "5000")
})
@GetMapping(value = "/consumer/book/getAllBooks")
public CommonResult getAllBooks(HttpServletRequest request, HttpServletResponse response){
CommonResult commonResult = bookService.getAllBooks();
System.out.println(commonResult);
return commonResult;
}
public CommonResult getAllBooks_Hystrix(HttpServletRequest request, HttpServletResponse response){
return new CommonResult(500,"error","出现错误,线程响应时间过长,请稍后再试");
}
//消费端controller,消费端hystrix,服务端controller存在熔断时,优先执行消费端controller,然后执行消费端hystrix,而后是服务端controller
@HystrixCommand
@RequestMapping(value = "/consumer/book/addBook")
public String addBook(BookInf book){
System.out.println(book);
CommonResult commonResult = bookService.addBook(book);
System.out.println("-------->"+commonResult.getCode());
System.out.println(commonResult.getData());
if (commonResult.getCode() == 200){
return "redirect:/consumer/book/getAllBooks";
}else {
return "404";
}
}
@HystrixCommand
@RequestMapping(value = "/consumer/book/updateBook")
public String updateBook(BookInf book){
System.out.println("-------->"+book);
CommonResult commonResult = bookService.updateBook(book);
System.out.println("-------->"+commonResult.getCode());
if (commonResult.getCode() == 200){
return "redirect:/consumer/book/getAllBooks";
}else {
return "404";
}
}
@HystrixCommand
@RequestMapping(value = "/consumer/book/deleteBook/{id}")
public String deleteBook(@PathVariable("id") int id, HttpServletRequest request, HttpServletResponse response){
CommonResult commonResult = bookService.deleteBook(id);
System.out.println("-------->"+commonResult.getCode());
if (commonResult.getCode() == 200){
return "redirect:/consumer/book/getAllBooks";
}else {
return "404";
}
}
@GetMapping(value = "/consumer/book/index/{id}")
//服务熔断
@HystrixCommand(fallbackMethod = "index_hystrix" , commandProperties = {
@HystrixProperty(name = "circuitBreaker.enabled", value = "true"), //是否开启断路器
@HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "5"), //请求次数
@HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "10000"), //时间范围
@HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "60"), //失败率达到多少后跳闸(百分比)
})
public CommonResult index(@PathVariable("id") Integer id){
if(id < 0){
throw new RuntimeException("输入异常");
}
return bookService.index(id);
}
public CommonResult index_hystrix(@PathVariable("id") Integer id){
return new CommonResult(500,"error","检测到id为负数,输入异常,请重新输入"+"id为"+id);
}
public CommonResult defaultFallbackMeth(){
return new CommonResult(500,"error","调用服务时产生未知错误,请联系管理员处理");
}
}
对于springcloud还是有很多不清楚的知识点,上网也不好找资料。有大佬带的话就好了,害。
dashboard的建立
写pom
<dependencies>
<!--hystrix dashboard-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
<!--监控-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--热部署-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
写yml
server:
port: 9001
主启动
@SpringBootApplication
@EnableHystrixDashboard
public class HystrixDashboardMain9001 {
public static void main(String[] args) {
SpringApplication.run(HystrixDashboardMain9001.class,args);
}
}
然后输入网址http://localhost:9001/hystrix
出现以下页面
在输入http://localhost:80/hystrix.stream服务名就可以对其监控了。