复杂的链路结构调用,在其中一个服务出现问题时,会导致与其协调的服务运行压力越来越大,引起雪崩效应。
Hystrix通过断路器的故障监控,向调用方返回一个符合预期的、可处理的备选响应,而不是长时间等待或抛出异常。避免故障蔓延。
降级:服务不可用时,向调用方返回一个符合预期的,可处理的的备选响应(fallback),运行异常、超时、熔断、线程池满等会触发降级。熔断:达到最大访问量,拒绝访问,调用服务降级方法返回。限流:高并发操作时,有序进行。 1、模拟超时
1.1 支付模块模拟高并发访问(Eureka服务注册);
PaymentController .java
@RestController
@RequestMapping("/payment")
@Slf4j
@RequiredArgsConstructor
public class PaymentController {
private final PaymentService paymentService ;
@GetMapping("/hy/ok/{id}")
public String getOk(@PathVariable Integer id){
return paymentService.getOk(id);
}
@GetMapping("/hy/timeout/{id}")
public String getTimeOut(@PathVariable Integer id){
return paymentService.getTimeOut(id);
}
}
PaymentService .java
public interface PaymentService extends IService{ public String getOk(Integer id); public String getTimeOut(Integer id); }
PaymentServiceImpl .java
@Service public class PaymentServiceImpl extends ServiceImplimplements PaymentService { @Override public String getOk(Integer id) { return Thread.currentThread().getName()+"、ok:"+id; } @Override public String getTimeOut(Integer id) { int time = 3000; try { Thread.sleep(time); } catch (InterruptedException e) { e.printStackTrace(); } return Thread.currentThread().getName()+"、ok:"+id + "耗时:"+ time; } }
访问
采坑8:@PathVariable(“id”)使用过程中需带上参数,不然可能报错;
2022-03-12 22:02:17.580 ERROR 24720 --- [ restartedMain] o.s.boot.SpringApplication : Application run failed org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'paymentController': Injection of resource dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'com.payment.FeignService.PaymentFeignService': FactoryBean threw exception on object creation; nested exception is java.lang.IllegalStateException: PathVariable annotation was empty on param 0. at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.postProcessProperties(CommonAnnotationBeanPostProcessor.java:337) ~[spring-context-5.2.2.RELEASE.jar:5.2.2.RELEASE] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1422) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:594) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:517) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE] at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:323) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE] at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE] at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:321) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE] at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE] at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:879) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE] at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:878) ~[spring-context-5.2.2.RELEASE.jar:5.2.2.RELEASE] at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:550) ~[spring-context-5.2.2.RELEASE.jar:5.2.2.RELEASE] at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:141) ~[spring-boot-2.2.2.RELEASE.jar:2.2.2.RELEASE] at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:747) [spring-boot-2.2.2.RELEASE.jar:2.2.2.RELEASE] at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397) [spring-boot-2.2.2.RELEASE.jar:2.2.2.RELEASE] at org.springframework.boot.SpringApplication.run(SpringApplication.java:315) [spring-boot-2.2.2.RELEASE.jar:2.2.2.RELEASE] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1226) [spring-boot-2.2.2.RELEASE.jar:2.2.2.RELEASE] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1215) [spring-boot-2.2.2.RELEASE.jar:2.2.2.RELEASE] at com.payment.Consumer4Application.main(Consumer4Application.java:12) [classes/:na] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_181] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_181] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_181] at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_181] at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49) [spring-boot-devtools-2.2.2.RELEASE.jar:2.2.2.RELEASE]
1.2 订单消费者模块模拟高并发访问(openfeign服务调用);
PaymentController .java
package com.payment.Controller;
import com.commons.Entity.Payment;
import com.commons.Entity.Result;
import com.payment.FeignService.PaymentFeignService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
@RestController
@RequestMapping("/consumer4")
public class PaymentController {
@Resource
private PaymentFeignService paymentFeignService;
@GetMapping("/hy/ok/{id}")
public String getOk(@PathVariable("id") Integer id){
return paymentFeignService.getOk(id);
}
@GetMapping("/hy/timeout/{id}")
public String getTimeOut(@PathVariable("id") Integer id){
return paymentFeignService.getTimeOut(id);
}
}
PaymentFeignService.java
package com.payment.FeignService;
import com.commons.Entity.Payment;
import com.commons.Entity.Result;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@FeignClient(value = "PAYMENT") //值为注册的支付模块微服务application.name
@Component
public interface PaymentFeignService {
@GetMapping("/payment/hy/ok/{id}")
public String getOk(@PathVariable("id") Integer id);
@GetMapping("/payment/hy/timeout/{id}")
public String getTimeOut(@PathVariable("id") Integer id);
}
主程序:@EnableFeignClients //激活
@SpringBootApplication(scanbasePackages = "com.payment")
@EnableFeignClients //激活
public class Consumer4Application {
public static void main(String[] args) {
SpringApplication.run(Consumer4Application.class, args);
}
}
application.yml
采坑9:需要开启超时控制,否则3秒会返回超时异常
2022-03-12 21:56:11.353 ERROR 25492 --- [nio-8085-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is feign.RetryableException: Read timed out executing GET http://PAYMENT/payment/hy/timeout/1] with root cause java.net.SocketTimeoutException: Read timed out at java.net.SocketInputStream.socketRead0(Native Method) ~[na:1.8.0_181] at java.net.SocketInputStream.socketRead(SocketInputStream.java:116) ~[na:1.8.0_181] at java.net.SocketInputStream.read(SocketInputStream.java:171) ~[na:1.8.0_181] at java.net.SocketInputStream.read(SocketInputStream.java:141) ~[na:1.8.0_181] at java.io.BufferedInputStream.fill(BufferedInputStream.java:246) ~[na:1.8.0_181] at java.io.BufferedInputStream.read1(BufferedInputStream.java:286) ~[na:1.8.0_181] at java.io.BufferedInputStream.read(BufferedInputStream.java:345) ~[na:1.8.0_181] at sun.net.www.http.HttpClient.parseHTTPHeader(HttpClient.java:735) ~[na:1.8.0_181] at sun.net.www.http.HttpClient.parseHTTP(HttpClient.java:678) ~[na:1.8.0_181] at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1587) ~[na:1.8.0_181] at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1492) ~[na:1.8.0_181] at java.net.HttpURLConnection.getResponseCode(HttpURLConnection.java:480) ~[na:1.8.0_181] at feign.Client$Default.convertResponse(Client.java:82) ~[feign-core-10.4.0.jar:na] at feign.Client$Default.execute(Client.java:78) ~[feign-core-10.4.0.jar:na] at org.springframework.cloud.openfeign.ribbon.FeignLoadBalancer.execute(FeignLoadBalancer.java:93) ~[spring-cloud-openfeign-core-2.2.1.RELEASE.jar:2.2.1.RELEASE] at org.springframework.cloud.openfeign.ribbon.FeignLoadBalancer.execute(FeignLoadBalancer.java:56) ~[spring-cloud-openfeign-core-2.2.1.RELEASE.jar:2.2.1.RELEASE] at com.netflix.client.AbstractLoadBalancerAwareClient$1.call(AbstractLoadBalancerAwareClient.java:104) ~[ribbon-loadbalancer-2.3.0.jar:2.3.0] at com.netflix.loadbalancer.reactive.LoadBalancerCommand$3$1.call(LoadBalancerCommand.java:303) ~[ribbon-loadbalancer-2.3.0.jar:2.3.0] at com.netflix.loadbalancer.reactive.LoadBalancerCommand$3$1.call(LoadBalancerCommand.java:287) ~[ribbon-loadbalancer-2.3.0.jar:2.3.0] at rx.internal.util.ScalarSynchronousObservable$3.call(ScalarSynchronousObservable.java:231) ~[rxjava-1.3.8.jar:1.3.8] at rx.internal.util.ScalarSynchronousObservable$3.call(ScalarSynchronousObservable.java:228) ~[rxjava-1.3.8.jar:1.3.8]
server:
port: 8085
eureka:
client:
register-with-eureka: false #是否要注册
fetchRegistry: true #是否抓取注册信息
service-url:
# defaultZone: http://localhost:7001/eureka
defaultZone: http://eureka7001:7001/eureka #,http://eureka7002:7002/eureka
spring:
application:
name : consumer8085
datasource:
url: jdbc:mysql://localhost:3306/springboot-mybatisplus?serverTimezone=Asia/Shanghai&useSSL=false&useUnicode=true&characterEncoding=utf8&characterSetResults=utf8
username: root
password: 123456
driver-class-name=com: mysql.cj.jdbc.Driver
#2、mybatis-plus配置
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
global-config :
db-config:
logic-delete-value: 1
logic-not-delete-value: 0
mapper-locations: classpath:mapper
@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;
}
}
访问:http://localhost:9001/hystrix填写被监控方信息
访问监控熔断测试:
监控结果:



