扇出:多个微服务调用的时候,假设微服务A调用微服务B和C,微服务B和C又调用其他的服务。
服务雪崩:如果扇出的链路上某个微服务的调用时间过长或不可用,对微服务A的调用就会越来多的系统资源,进而引起系统崩溃。
Hystrix是一个用于处理分布式系统的延迟和容错的开源库,能够保证在一个依赖出现问题的情况下,不会导致整体服务失败,从而提高分布式系统的弹性。它的功能有服务降级、服务熔断、服务限流等。
断路器:一种开关装置,当某个服务单元发生故障后,通过断路器的故障监控向调用方返回一个符合预期的、可处理的备选响应(FallBack),而不是长时间的等待或抛出异常。
服务熔断:当扇出链路的某个微服务不可用火响应时间太长时,会进行服务的降级,进而熔断该节点微服务的调用,快速返回错误的响应信息。当检测到该节点微服务调用响应正常后恢复调用链路。
服务降级:在客户端实现的
源代码:https://github.com/zhongyushi-git/cloud-hystrix.git
1)参考feign的搭建来搭建hystrix的项目,只需要eureka集群、api和consumer80。
2)按照provider8001创建服务提供者cloud-provider-hystrix-8001,再导入hystrix依赖
<!--hystrix--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency>
3)对发生异常的方法进行处理
在服务提供者的UserController中的get方法添加结果为空的异常处理
@GetMapping("/get/{id}") @HystrixCommand(fallbackMethod = "hystrix_get") public User getUser(@PathVariable("id")long id){ User user=userService.getUser(id); //数据为空就抛出异常 if(user==null){ throw new RuntimeException("未查询到数据"); } return user; } //服务熔断 public User hystrix_get(@PathVariable("id")long id){ User user=new User(); user.setId(id); user.setName("未查询到数据"); user.setPhone(new Date().toString()); return user; }
4)在服务提供者启动类添加注解@EnableCircuitBreaker
@SpringBootApplication @EnableEurekaClient @EnableCircuitBreaker public class ProviderMain8001 { public static void main(String[] args) { SpringApplication.run(ProviderMain8001.class, args); } }
5)启动测试
先启动eureka集群,然后启动8001。分别访问http://localhost:8001/user/get/1和http://localhost:8001/user/get/123,get/1能获取正常数据,get/123不能获取正常数据而显示的错误信息。
1)把服务提供者进行异常处理的地方给注释掉
@GetMapping("/get/{id}") @HystrixCommand(fallbackMethod = "hystrix_get") public User getUser(@PathVariable("id")long id){ User user=userService.getUser(id); //数据为空就抛出异常 // if(user==null){ // throw new RuntimeException("未查询到数据"); // } return user; }
2)在cloud-feign-consumer80导入hystrix依赖
<!--hystrix--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency>
3)修改cloud-feign-consumer80的yml
feign: hystrix: enabled: true
4)创建service接口,用于feign获取服务
package com.zys.cloud.serivce; import com.zys.cloud.entity.User; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; //添加注解,指定微服务名称 @FeignClient(value="CLOUD-PROVIDER") public interface UserClientService { @GetMapping("/user/get/{id}") public User getUser(@PathVariable("id")long id); @PostMapping("/user/add") int addUser(User user); }
5)创建controller
package com.zys.cloud.controller; import com.netflix.hystrix.contrib.javanica.annotation.DefaultProperties; import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; import com.zys.cloud.entity.User; import com.zys.cloud.serivce.UserClientService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; import java.util.Date; @RestController @RequestMapping("/consumer") public class UserController { @Resource private UserClientService userClientService; @GetMapping("/get/{id}") // @HystrixCommand(fallbackMethod = "hystrix_get") public User getUser(@PathVariable("id") long id){ User user=userClientService.getUser(id); //数据为空就抛出异常 if(user==null){ throw new RuntimeException("抱歉,未查询到数据"); } return user; } //服务熔断 public User hystrix_get(@PathVariable("id")long id){ User user=new User(); user.setId(id); user.setName("抱歉,未查询到数据"); user.setPhone(new Date().toString()); return user; } @PostMapping("/add") public int addUser(User user){ return userClientService.addUser(user); } }
6)在服务消费者启动类添加注解@EnableHystrix
@SpringBootApplication @EnableEurekaClient @EnableFeignClients @EnableHystrix public class ConsumerFeignMain80 { public static void main(String[] args) { SpringApplication.run(ConsumerFeignMain80.class, args); } }
7)启动测试
先启动eureka集群,然后启动8001,最后80启动。分别访问http://localhost/consumer/get/1和http://localhost/consumer/get/123,get/1能获取正常数据,get/123不能获取正常数据而显示的错误信息。然后关闭8001,再次访问http://localhost/consumer/get/1也是显示错误信息。
在上面的服务提供者和消费者中,对服务进行降级,都有一些问题。就是要对每一个方法进行降级,降级的方法又混合在controller中,显示很繁琐,配置起来也很麻烦。不过是可以进行全局配置的。
(1)DefaultProperties设置默认的处理方法
在80的controller中加入注解进行配置
package com.zys.cloud.controller; import com.netflix.hystrix.contrib.javanica.annotation.DefaultProperties; import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; import com.zys.cloud.entity.User; import com.zys.cloud.serivce.UserClientService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; import java.util.Date; @RestController @RequestMapping("/consumer") @DefaultProperties(defaultFallback = "globalFallBack") public class UserController { @Resource private UserClientService userClientService; @GetMapping("/get/{id}") // @HystrixCommand(fallbackMethod = "hystrix_get") //未指定fallback,就使用默认的 @HystrixCommand public User getUser(@PathVariable("id") long id){ User user=userClientService.getUser(id); //数据为空就抛出异常 if(user==null){ throw new RuntimeException("抱歉,未查询到数据"); } return user; } //服务熔断 public User hystrix_get(@PathVariable("id")long id){ User user=new User(); user.setId(id); user.setName("抱歉,未查询到数据"); user.setPhone(new Date().toString()); return user; } @PostMapping("/add") public int addUser(User user){ return userClientService.addUser(user); } //设置全局的fallback public User globalFallBack(){ User user=new User(); user.setName("服务器维护中,请稍后再试!"); user.setPhone(new Date().toString()); return user; } }
当没有指定fallback时,就会去使用默认的fallback。
(2)代码解耦
在service中新建一个类UserClientServiceFallBackFactory,实现FallbackFactory
package com.zys.cloud.serivce; import com.zys.cloud.entity.User; import feign.hystrix.FallbackFactory; import org.springframework.stereotype.Component; @Component public class UserClientServiceFallBackFactory implements FallbackFactory<UserClientService> { @Override public UserClientService create(Throwable throwable) { return new UserClientService() { @Override public User getUser(long id) { User user=new User(); user.setId(id); user.setName("未查询到数据,服务降级-停止服务"); return user; } @Override public int addUser(User user) { return 0; } }; } }
在UserClientService中给FeignClient注解加fallbackFactory属性
@FeignClient(value="CLOUD-PROVIDER",fallbackFactory = UserClientServiceFallBackFactory.class)
对于微服务,也是需要进行监控的。Hystrix也提供了准实时的服务监控(Hystrix Dashboard),它会持续的记录所有通过Hystrix发起的请求的执行信息,并以统计报表和图形的形式展现给用户。在1.2的基础上继续开发。
1)新建cloud-feign-hystrix-dashboard-consumer9001的maven工程
2)在pom中添加依赖
<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>
3)配置yml文件
server: port: 9001
4)在包com.zys.cloud下创建启动类并添加注解@EnableHystrixDashboard
package com.zys.cloud; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard; @SpringBootApplication @EnableHystrixDashboard public class ConsumerFeignHystrixDashboardMain9001 { public static void main(String[] args) { SpringApplication.run(ConsumerFeignHystrixDashboardMain9001.class, args); } }
5)在8001的启动类加配置方法
//指定监控路径 @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; }
6)启动测试
先启动9001,然后启动eureka集群,然后启动8001。然后在浏览器输入http://localhost:9001/hystrix,可以看到下面的界面,说明配置成功。
在第一个输入框输入http://localhost:8001/hystrix.stream,点击下面的按钮,可以进入服务的监控页面。
再输入http://localhost:8001/user/get/1,快速的刷新几次,再回到监控页面看到有图形在实时变化,这就是实时的监控效果。
原文:https://www.cnblogs.com/zys2019/p/12652314.html