OpenFeign
Feign是一个声明式 WebService客户端。使用 Feign能让编写 Web Service客户端更加简单。它的使用方法是
定义一个服务接口然后在上面添加注解
。 Feign也支持可拔插式的编码器和解码器。 Spring Cloud对 Feign进行了封装,使其支持了 Spring MVC标准注解和 HttpmessageConverters。 Feign可以与 Eureka和 Ribbon组合使用以支持负载均衡。官方文档
Feign能干什么
Feign旨在使编写 Java Http客户端变得更容易。前面在使用 Ribbon+RestTemplate 时,利用RestTemplate对http请求的封装处理,形成了一套模版化的调用方法。但是在实际开发中,由于对服务依赖的调用可能不止一处,往往一个接口会被多处琱用,所以通常都会针对毎个微服务自行封装一些客户端类来包装这些依赖服务的调用。所以, Feign在此基础上做了进一步封装,由他来帮助我们定乂和实现依赖服务接口的定义。在Feigη的实现下,我们只需创建一个接口并使用注解的方式来配置它(以前是Dao接口上面标注 Mappe注解现在是一个微服务接口上面标注一个Feign注解即可,即可完成对服务提供方的接口绑定,简化了使用 Spring cloud Ribbon时,自动封装服务调用客户端的开发量。
Feign集成了Ribbon
利用 Ribbon维护了 Payment的服务列表信息,并目通过轮洵实现了客户端的负载均衡。而与 Ribbon不同的是,通过 feign只需要定义服务绑定接口且以声明式的方法,优雅而简单的实现了服务调用
OpenFeign使用
-
微服务调用接口 + @FeignClient
server:port: 80spring:application:name: hzl-order-service-feigneureka:client:# 表示是否将自己注册进Eureka Serverregister-with-eureka: true# 是否从EurekaServer抓取已有的注册信息,集群必须为true才能配合ribbon使用fetch-registry: trueservice-url:defaultZone: http://eureka7001.com:7001/eureka , http://eureka7002.com:7002/eureka
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId></dependency>
@SpringBootApplication
@EnableFeignClients
public class OrderMainFeign {
public static void main(String[] args) {
SpringApplication.run(OrderMainFeign.class,args);}
}
@FeignClient("hzl-payment-service")
public interface PaymentService
{
@RequestMapping(method = RequestMethod.GET, value = "/payment/get/{id}")CommonResult getById(@PathVariable("id")Long id);@RequestMapping(method = RequestMethod.POST, value = "/payment/create", consumes = "application/json")CommonResult create(Payment payment);
}
@RestController
@Slf4j
public class OrderFeignController
{
@Resourceprivate PaymentService paymentService;@GetMapping("/consumer/payment/get/{id}")public CommonResult getById(@PathVariable("id")Long id){
return paymentService.getById(id);}@PostMapping(value = "/consumer/payment/create",consumes = "application/json")public CommonResult create(Payment payment){
return paymentService.create(payment);}
}
OpenFeign超时使用
…
OpenFeign日志增强
Feign提供了日志打印功能,我们可以通过配置来调整日志级别,从而了解 Feign中Http请求的细节。说白了就是对 Feign接口的调用情况进行监控和输出
- NONE:默认的,不显示任何日志
- BASC:仅记录请求方法、URL、响应状态码及执行时间
- HEADERS:除了BASC中定义的信息之外,还有请求和响应的头信息
- FULL:除了 HEADERS中定义的信息之外,还有请求和响应的正文及元据
@Configuration
public class FeignConfig {
@BeanLogger.Level feignLoggerLevel(){
return Logger.Level.FULL;}
}
logging:level:# 接口:级别com.hzl.springcloud.service.PaymentService: debug
Hystrix熔断器
- Hystrix,是个用于处理分布式系统的
延迟
和容错
的开源库,在分布式系统里,许多依赖不可避免的会调用失败,比如超时、异常等。- Hystrix能够保证在—个依赖出问题的情况下,不会导致整体服务失败,
避免级联故障,以提高分布式系统的弹性
。- “断路器”本身是—种开关装置,当某个服务单元发生故障之后,通过断路器的故障监控(类似熔断保险丝),向调用方返回一个符合预期的、可处理的
备选响应(FallBack)
,而不是长时间的等待或者拋出调用方无法处理的异常,这样就保证了服务调用方的线程不会被长时间、不必要地占用,从而避免了故障在分布式系统中的蔓延,乃至雪崩。
官方文档
Hystrix重要概念,属性类HystrixCommandProperties
服务降级(fallback)
- 程序运行异常
- 超时
- 服务熔断服务服务降级
- 线程池/信号量打满也会导致服务降级
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-hystrix</artifactId><version>2.2.9.RELEASE</version></dependency>
@RestController
public class PaymentController {
@Resourceprivate PaymentService paymentService;@GetMapping("/payment/hystrix/ok/{id}")public String paymentInfo_ok(@PathVariable("id") Integer id){
return paymentService.paymentInfo_ok(id);}/*** 内部暂停三秒*/@GetMapping("/payment/hystrix/timeout/{id}")public String paymentInfo_timeout(@PathVariable("id")Integer id){
return paymentService.paymentInfo_timeout(id);}
}
@SpringBootApplication
@EnableFeignClients
public class OrderHystrixMain {
public static void main(String[] args) {
SpringApplication.run(OrderHystrixMain.class,args);}
}
@FeignClient("cloud-provider-hystrix-payment")
public interface OrderHystrixService
{
@GetMapping("/payment/hystrix/ok/{id}")String paymentInfo_ok(@PathVariable("id") Integer id);/*** 故障方法*/@GetMapping("/payment/hystrix/timeout/{id}")String paymentInfo_timeout(@PathVariable("id")Integer id);
}
测试结果,两个接口都变慢了
理想状态:超时不再等待,宕机响应,快速响应
- 服务提供者service,@HystrixCommand:
@Service
public class PaymentService {
public String paymentInfo_ok(Integer id){
return "线程池:"+Thread.currentThread().getName()+",方法:paymentInfo_ok,id:"+id;}/*** 故障方法(超时)*/@HystrixCommand(fallbackMethod = "paymentInfo_timeout_handler", commandProperties = {
//设置自身调用超时时间峰值,峰值内可以正常运行,超过了服务降级,fallback@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "3000")})public String paymentInfo_timeout(Integer id){
int timeNumber = 5;try {
// 暂停三秒TimeUnit.SECONDS.sleep(timeNumber);} catch (InterruptedException e) {
e.printStackTrace();}return "线程池:"+Thread.currentThread().getName()+",方法:paymentInfo_timeout,id:"+id+",耗时:"+timeNumber+"秒";}/*** 超时处理方法*/public String paymentInfo_timeout_handler(Integer id){
return "超时3秒处理线程池:"+Thread.currentThread().getName()+",方法:paymentInfo_timeout_handler,id:"+id;}
}
- 服务提供者启动类,@EnableHystrix:
@SpringBootApplication(exclude = {
DataSourceAutoConfiguration.class})
@EnableEurekaClient
@EnableHystrix
public class PaymentHystrixMain8001 {
public static void main(String[] args) {
SpringApplication.run(PaymentHystrixMain8001.class,args);}
}
- 全局服务降级@DefaultProperties
@RestController
@DefaultProperties(defaultFallback = "GlobalFallback")
public class OrderHystrixController {
@Resourceprivate OrderHystrixService orderHystrixService;@GetMapping("/consumer/payment/hystrix/ok/{id}")public String paymentInfo_ok(@PathVariable("id") Integer id){
return orderHystrixService.paymentInfo_ok(id);}/*** 故障方法*/
// @HystrixCommand(fallbackMethod = "paymentInfo_timeout_handler", commandProperties = {
// //设置自身调用超时时间峰值,峰值内可以正常运行,超过了服务降级,fallback
// @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "3000")
// })@GetMapping("/consumer/payment/hystrix/timeout/{id}")@HystrixCommandpublic String paymentInfo_timeout(@PathVariable("id") Integer id){
return orderHystrixService.paymentInfo_timeout(id);}/*** 全局fallback*/public String GlobalFallback(){
return "全局异常处理,请稍后再试";}
}
服务熔断(break)
- 类比保险丝达到最大服务访问后,直接拒绝访问,拉闸限电,然后调用服务降级的方法并返回友好提示
- 服务降级->熔断->恢复调用链路
- 熔断机制概述
熔断机制是应对雪崩效应的一种微服务链路保护机制。当扇岀链路的某个微服务岀错不可用或者晌应时间太长时,
会进行服务的降级,进而熔断该节点微服务的调用,快速返回错误的响应信息。当检测到该节点微服努调用响应正常后,恢复调用链路
。
在 Spring Cloud框架里,熔断机制通过 Hystrix实现。 Hystrix会监控微服务间调用的状况,
当失败的调用到一定阈值,缺省是5秒内20次调用失败,就会启动熔断机制。熔断机制的注解是@ HystrixCommand
10秒钟的时间窗口期,10次访问,失败率60%
10秒内的10次请求失败率在60%以上,降级->熔断
全开->半开->关闭
/*服务熔断*/@HystrixCommand (fallbackMethod ="paymentCircuitBreaker_fallback",commandProperties={
@HystrixProperty (name ="circuitBreaker.enabled",value ="true"), // 是否开启断路器@HystrixProperty (name ="circuitBreaker.requestVolumeThreshold",value ="10"), // 请求次数@HystrixProperty (name ="circuitBreaker.sleepWindowInMilliseconds",value ="10000"), // 时间窗口期@HystrixProperty (name ="circuitBreaker.errorThresholdPercentage",value ="60")}) // 失败率达到多少后跳闸public String paymentCircuitBreaker(Integer id){
if(id<0){
throw new RuntimeException("id不能为负数");}String serviceId = IdUtils.getUnresolvedServiceId();return Thread.currentThread().getName()+"\t"+"调用成功,流水号:"+serviceId;}public String paymentCircuitBreaker_fallback(Integer id){
return "id不能为负数"+id;}
服务限流(flowlimit),后面高级篇讲解 alibaba的 Sentine说明
- 秒杀高并发等操作,严禁一窝蜂的过来拥挤,大家排队,一秒钟N个,有序进行
Hystrix图形化Dashboard
- 启动类添加@EnableHystrixDashboard
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId><version>2.2.9.RELEASE</version></dependency><!-- actuator监控信息完善--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId></dependency>
@SpringBootApplication(exclude = {
DataSourceAutoConfiguration.class})
@EnableHystrixDashboard
public class HystrixDashboardMain {
public static void main(String[] args) {
SpringApplication.run(HystrixDashboardMain.class,args);}
}
图形化地址:http://localhost:9001/hystrix
没测试成功,后面等用sentinel先
/**此配置是为了服务监控而置,与服务容本身无关,springcloud开级后的坑ServletRegistrationBean因为 springboot的默认路径不是"/hystrix, stream",只要在自已的项日里配置上下面的 servlet就以了*/@Beanpublic ServletRegistrationBean getServlet(){
HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();ServletRegistrationBean registrationBean= new ServletRegistrationBean(streamServlet);registrationBean.setLoadOnStartup(1);registrationBean.addUrlMappings("/hystrix.stream");registrationBean.setName("HystrixMetricsStreamServlet");return registrationBean;}