试想一下,你的32核,128G的机器,假设最大能抗住2000qps,这个时候内存也是飙升的。如果QPS或者TPS在大一些会发生什么,会产生OOM这种ERROR,服务直接挂掉。
于是你的客服不断收到电话投诉,那是多刺激。售后催你们的技术赶紧把有问题的业务处理下,一大堆由于服务挂掉的东西需要,回退,该状态等等等,让后GG了。
在传统的设计上,熔断或者限流设计为两种。 一种是调用方发现服务方达到最大极限了,此时不再去调用,直接给用户返回友好提示,比如网络飞了,当前网络过多请稍后重试,等提示,那就表示,被调用方达到极限了,给出的保护提示。 还有一种就是,被调用放达到极限,返回给调用方,但这样会多出很多无效请求到服务方。
接下来上案例,用我曾经做过的订单系统为例吧。
先要准备个订单调用方:OrderFeignMain80,
配置文件:
server.port=8080 spring.application.name=cloud-consumer-feign #向注册中心注册自己 eureka.client.register-with-eureka=true #是否从eureka抓取自己,并不需要检索服务,单节点无所谓,集群必须设置true,才能使用ribbon负载均衡 eureka.client.fetch-registry=true #eureka.client.service-url.defaultZone=http://localhost:7001/eureka #集群模板 这里修改了C:\Windows\System32\drivers\etc\hosts 人为添加了域名 eureka7001.com eureka.client.service-url.defaultZone=http://eureka7001:7001/eureka,http://eureka7002:7002/eureka eureka.instance.instance-id=cloud-consumer-feign #显示IP地址 eureka.instance.prefer-ip-address=true # ribbon的可配置部分 #处理请求的超时时间,默认为1秒 ribbon.ReadTimeout=5000 #连接建立的超时时长,默认1秒 ribbon.ConnectTimeout=5000 #ribbon.MaxAutoRetries=1 //同一台实例的最大重试次数,但是不包括首次调用,默认为1次 #ribbon.MaxAutoRetriesNextServer=0 //重试负载均衡其他实例的最大重试次数,不包括首次调用,默认为0次 #ribbon.OkToRetryOnAllOperations=false //是否对所有操作都重试,默认false ## Feign的可配置部分 #feign.hystrix.enabled=false //Feign是否启用断路器,默认为false #feign.client.config.default.connectTimeout=10000 //Feign的连接建立超时时间,默认为10秒 #feign.client.config.default.readTimeout=60000 //Feign的请求处理超时时间,默认为60 #feign.client.config.default.retryer=feign.Retryer.Default //Feign使用默认的超时配置,在该类源码中可见,默认单次请求最大时长1秒,重试5次 logging.level.com.wangbiao.springcloud.config.FeignConfig=debug
使用OpenFegin开启用层服务调用
@EnableFeignClients() @SpringBootApplication @EnableHystrix public class OrderFeignMain80 { public static void main(String[] args) { SpringApplication.run(OrderFeignMain80.class,args); } }
Controller和普通的没什么区别
@RestController @RequestMapping("/payment") @Slf4j public class PaymentController { @Value("${server.port}") private String port; @Resource PaymentFeginService paymentFeginService; @GetMapping("/selectOne/{id}") public CommonResult selectOne(@PathVariable(name = "id") Integer id) { CommonResult payment = this.paymentFeginService.selectOne(id); if (payment != null) { System.out.println("111111111111"); return new CommonResult(200, "找到了port:" + port, payment); } return new CommonResult(404, "找不到port:" + port, null); } //Hystrim >test @GetMapping("/timeOut/{id}") @HystrixCommand(fallbackMethod = "payTimeOut", commandProperties = {@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1500")}) public String paymentTimeOut(@PathVariable("id") Integer id) { return paymentFeginService.paymentTimeOut(id); } public String payTimeOut(Integer id) { log.info("客户端调用超时打印:{}", id); return "客户端超时:" + Thread.currentThread().getName() + ":超时了:" + id; } @GetMapping("/timeOut") public CommonResult timeOut() { CommonResult payment = this.paymentFeginService.timeOut(); return new CommonResult(404, "找不到port:" + port, payment); } }
服务调用层:这里要关注下
@FeignClient(value = "cloud-payment-server") 这里面是备用方的服务名称,我们采用的就是微服务
@Component @FeignClient(value = "cloud-payment-server") public interface PaymentFeginService { @GetMapping("/payment/selectOne/{id}") CommonResult selectOne(@PathVariable(name = "id") Integer id); @GetMapping("/payment/timeOut") CommonResult timeOut(); @GetMapping("/payment/timeOut/{id}") String paymentTimeOut(@PathVariable("id") Integer id); }
被调用方,也及时上面的那个cloud-payment-server
@SpringBootApplication @EnableEurekaClient @EnableCircuitBreaker public class PaymentHystrixMain8001 { public static void main(String[] args) { SpringApplication.run(PaymentHystrixMain8001.class, args); } @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; } }
Controller:
@RestController @RequestMapping("/payment") @Slf4j public class PaymentController { @Resource private PaymentService paymentService; @Value("${server.port}") private String port; @GetMapping("/getHystrix/{id}") public String payment_ok(@PathVariable("id") Integer id) { String result = paymentService.paymentOk(id); log.info(">>>>>>>>>>>>{}", result); return result; } @GetMapping("/timeOut/{id}") public String paymentTimeOut(@PathVariable("id") Integer id) { String result = paymentService.paymentTimeOut(id); log.info("<<<<<<<<{}", result); return result; } @GetMapping("/selectOne/{id}") public CommonResult selectOne(@PathVariable(name = "id") Integer id){ return new CommonResult(100,"测试dashboard"); } //服务熔断 @HystrixCommand(fallbackMethod ="paymentCircuitBreakFallback",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")//失败率达到多少后跳闸 }) @GetMapping("/circuit/{id}") public String paymentCircuitBreaker(@PathVariable("id")Integer id){ if(id<0){ throw new RuntimeException("******id不能为负数"); } String sss= UUID.randomUUID().toString(); return Thread.currentThread().getName()+"调用成功:"+sss; } @GetMapping("/timeOut") public CommonResult timeOut(){ return new CommonResult(100,"timeOut"); } /** * 熔断 服务不可用时,返回给调用放的信息 * @param id * @return */ public String paymentCircuitBreakFallback(@PathVariable("id")Integer id){ return "ID不能是负数,请稍后再试,呜呜呜"+id; } @GetMapping("/payment/lb") public String lb() { return port; } }
Service:
@Slf4j @Service public class PaymentService { public String paymentOk(Integer id) { return "线程池:" + Thread.currentThread().getName() + ":id:" + id; } @HystrixCommand(fallbackMethod = "payTimeOutHandler", commandProperties = { @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000")})//设置3s超时后触发payTimeOutHandler给调用方 public String paymentTimeOut(Integer id) { int num = 6000; try { Thread.sleep(num); } catch (InterruptedException e) { e.printStackTrace(); } return "线程池:" + Thread.currentThread().getName() + ":id:" + id; } //服务端降级 public String payTimeOut(Integer id) { return "线程池:" + Thread.currentThread().getName() + ":超时了:" + id; } //服务端降级 public String payTimeOutHandler(Integer id) { int a = 10 / 0; return "线程池:" + Thread.currentThread().getName() + ":报错" + id; } }
配置文件:
server.port=8001 #向注册中心注册自己 spring.application.name=cloud-payment-server eureka.client.register-with-eureka=true #自己就是注册中心,并不需要检索服务,单节点无所谓,集群必须设置true,才能使用ribbon负载均衡 eureka.client.fetch-registry=true #注入eureka使用的唯一服务名字(unid) eureka.instance.instance-id=hystrim8001 #显示IP地址 eureka.instance.prefer-ip-address=true #默认实例每30秒发送一次心跳 #eureka.instance.lease-renewal-interval-in-seconds=1 #注册中心,默认90s内加收到心跳认为服务正常。大于90s认为超时 #eureka.instance.lease-expiration-duration-in-seconds=2 #单机版 #eureka.client.service-url.defaultZone=http://eureka7001:7001/eureka #集群模板 #这里修改了C:\Windows\System32\drivers\etc\hosts 人为添加了域名 eureka7002 eureka.client.service-url.defaultZone=http://eureka7001:7001/eureka,http://eureka7002:7002/eureka #熔断连接时间 #hystrix.config.stream.maxConcurrentConnections=500 #hystrix.dashboard.proxyStreamAllowList=http://localhost:8001 management.endpoints.web.exposure.include=*
标签:String,Hystrix,payment,eureka,port,熔断,使用,id,public From: https://www.cnblogs.com/wangbiaohistory/p/18654040