源无极

导航

 

 

1、分布式核心知识之熔断、降级讲解
简介:系统负载过高,突发流量或者网络等各种异常情况介绍,常用的解决方案

1、熔断:
保险丝,熔断服务,为了防止整个系统故障,包含子和下游服务

有了熔断之后(将服务停掉了,其他服务不会调用,否则一直等待结果)

下单服务 -》商品服务
-》用户服务 (出现异常-》熔断)

2、降级:
抛弃一些非核心的接口和数据

旅行箱的例子只带核心的物品,抛弃非核心的,等有条件的时候再去携带这些物品


3、熔断和降级互相交集
相同点:
1)从可用性和可靠性触发,为了防止系统崩溃
2)最终让用户体验到的是某些功能暂时不能用

不同点
1)服务熔断一般是下游服务故障导致的,而服务降级一般是从整体系统负荷考虑,由调用方控制

 

2、Netflix开源组件断路器Hystrix介绍
简介:介绍Hystrix基础知识和使用场景

文档地址:
https://github.com/Netflix/Hystrix
https://github.com/Netflix/Hystrix/wiki

1、什么是Hystrix?
1)hystrix对应的中文名字是“豪猪”

2)hystrix 英[hɪst'rɪks] 美[hɪst'rɪks]


2、为什么要用?
      在一个分布式系统里,一个服务依赖多个服务,可能存在某个服务调用失败,
比如超时、异常等,如何能够保证在一个依赖出问题的情况下,不会导致整体服务失败,
通过Hystrix就可以解决

http://cloud.spring.io/spring-cloud-netflix/single/spring-cloud-netflix.html#_circuit_breaker_hystrix_clients

3、提供了熔断、隔离、Fallback、cache、监控等功能


4、熔断后怎么处理?
出现错误之后可以 fallback 错误的处理信息

兜底数据

 

3、Feign结合Hystrix断路器开发实战《上》
简介:讲解SpringCloud整合断路器的使用,用户服务异常情况

1、加入依赖

注意:网上新旧版本问题,所以要以官网为主,不然部分注解会丢失
最新版本 2.0

1 <dependency>
2 <groupId>org.springframework.cloud</groupId>
3 <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
4 </dependency>

 


2、增加注解
启动类里面增加注解
@EnableCircuitBreaker

注解越来越多-》 SpringCloudApplication注解

3、API接口编码实战
熔断-》降级

1)最外层api使用,好比异常处理(网络异常,参数或者内部调用问题)
api方法上增加 @HystrixCommand(fallbackMethod = "saveOrderFail")

order-service的controller方法里面
 1 package com.po.order_service.controller;
 2 
 3 import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
 4 import com.po.order_service.service.ProductOrderService;
 5 import org.springframework.beans.factory.annotation.Autowired;
 6 import org.springframework.web.bind.annotation.RequestMapping;
 7 import org.springframework.web.bind.annotation.RequestParam;
 8 import org.springframework.web.bind.annotation.RestController;
 9 
10 import java.util.HashMap;
11 import java.util.Map;
12 
13 @RestController
14 @RequestMapping("api/vi/order")
15 public class ProductOrderController {
16     @Autowired
17     private ProductOrderService productOrderService;
18     @RequestMapping("save")
19     @HystrixCommand(fallbackMethod = "saveOrderFail")//调用save方法失败则执行saveOrderFail的方法
20     public  Object save(@RequestParam("user_id")int userId,@RequestParam("product_id")int productId){
21         Map<String, Object> data = new HashMap<>();
22         data.put("code",0);
23         data.put("data",productOrderService.save(userId,productId));
24         return data;
25     }
26     //编写fallback方法实现,方法签名一定要和api方法签名一致(注意点!!!)
27     private  Object saveOrderFail(int userId,int productId){
28          Map<String, Object> msg = new HashMap<>();
29          msg.put("code",-1);
30          msg.put("msg","访问人数过多,您被挤出来了,请稍后访问!");
31          return  msg;
32     }
33 
34 }

 


编写fallback方法实现,方法签名一定要和api方法签名一致(注意点!!!)

 这样我们在调用save方法失败的时候,返回msg信息回去

 

访问:

http://localhost:8781/api/vi/order/save?product_id=3&user_id=5

{"code":0,"data":{"id":0,"productName":"\"iPhone6data from port = 8771\"","tradeNo":"b2969831-a249-4407-8626-6b33de4ac34d","price":6999,"createTime":"2018-12-28T13:50:26.434+0000","userId":5,"userName":null}}

 

补充: 修改maven仓库地址

 1 pom.xml中修改
 2 
 3 <repositories>
 4 <repository>
 5 <id>nexus-aliyun</id>
 6 <name>Nexus aliyun</name>
 7 <layout>default</layout>
 8 <url>http://maven.aliyun.com/nexus/content/groups/public</url>
 9 <snapshots>
10 <enabled>false</enabled>
11 </snapshots>
12 <releases>
13 <enabled>true</enabled>
14 </releases>
15 </repository>
16 </repositories>

 


4、Feign结合Hystrix断路器开发实战《下》
简介:讲解SpringCloud整合断路器的使用,用户服务异常情况

先看@FeignClient(name="product-service")

在包import org.springframework.cloud.openfeign.FeignClient;中,

            <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

 

注意:虽然spring-cloud-starter-openfeign依赖下面有hystrix的但是这个不支持@HystrixCommand注解的

1          <dependency>
2             <groupId>io.github.openfeign</groupId>
3             <artifactId>feign-hystrix</artifactId>
4         </dependency>

 


1、feign结合Hystrix

1)开启feign支持hystrix (注意,一定要开启,旧版本默认支持,新版本默认关闭)

 1 server:
 2   port: 8781
 3 
 4 
 5 #指定注册中心地址
 6 eureka:
 7   client:
 8     serviceUrl:
 9       defaultZone: http://localhost:8761/eureka/
10 
11 #服务的名称
12 spring:
13   application:
14     name: order-service
15 
16 #自定义负载均衡策略
17 product-service:
18   ribbon:
19     NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
20 
21 
22 #修改调用超时时间 注意hystrix和client同级
23 feign:
24   hystrix:    
25     enabled: true
26   client:
27     config:
28       default:
29         connectTimeout: 2000
30         readTimeout: 2000

 

2)建自定义的异常包(回滚)fallback 建立ProductClientFallback,该类必须实现ProductClient接口(FeignClient源码有说明)

 1 package com.po.order_service.fallback;
 2 
 3 import com.po.order_service.service.ProductClient;
 4 import org.springframework.stereotype.Component;
 5 /*
 6 针对商品服务,做降级处理
 7  */
 8 @Component
 9 public class ProductClientFallback implements ProductClient {
10 
11     @Override
12     public String findById(int id) {
13         System.out.println("feign调用product-service 的findById出现异常");
14         return null;
15     }
16 }

 

3)FeignClient(name="xxx", fallback=xxx.class ), class需要继承当前FeignClient的类

 

 1 package com.po.order_service.service;
 2 
 3 import com.po.order_service.fallback.ProductClientFallback;
 4 import org.springframework.cloud.openfeign.FeignClient;
 5 import org.springframework.web.bind.annotation.GetMapping;
 6 import org.springframework.web.bind.annotation.RequestParam;
 7 
 8 /*
 9 商品服务客户端
10  */
11 @FeignClient(name="product-service" ,fallback = ProductClientFallback.class)
12 public interface ProductClient {//ProductClientFallback.class就是我们自定义的异常类
13     //注意这里GetMapping的路径和product-service服务里面的findById方法的路径一致,id也是一样的
14     @GetMapping("/api/vi/product/findById")
15     String findById(@RequestParam(value ="id")int id);
16 }

 

 此时假如product-service停止了

则访问时

http://localhost:8781/api/vi/order/save?product_id=2&user_id=5

 

{"msg":"访问人数过多,您被挤出来了,请稍后访问!","code":-1}

 

 控制台

feign调用product-service 的findById出现异常

 说明程序调用到了ProductClientFallback方法

 

5、熔断降级服务异常报警通知实战

 


简介:完善服务熔断处理,报警机制完善

1、加入redis依赖

1 <dependency>
2 <groupId>org.springframework.boot</groupId>
3 <artifactId>spring-boot-starter-data-redis</artifactId>
4 </dependency>

 


2、配置redis链接信息

 1 server:
 2   port: 8781
 3 
 4 
 5 #指定注册中心地址
 6 eureka:
 7   client:
 8     serviceUrl:
 9       defaultZone: http://localhost:8761/eureka/
10 
11 #服务的名称
12 spring:
13   application:
14     name: order-service
15   redis:
16     database: 0
17     host: 127.0.0.1
18     port: 6379
19     timeout: 2000
20 #自定义负载均衡策略
21 product-service:
22   ribbon:
23     NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
24 
25 
26 #修改调用超时时间
27 feign:
28   hystrix:
29     enabled: true
30   client:
31     config:
32       default:
33         connectTimeout: 2000
34         readTimeout: 2000

 

 

3、使用

 1 package com.po.order_service.controller;
 2 
 3 import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
 4 import com.po.order_service.service.ProductOrderService;
 5 import com.sun.org.apache.xml.internal.security.keys.storage.implementations.CertsInFilesystemDirectoryResolver;
 6 import io.netty.util.internal.StringUtil;
 7 import org.apache.commons.lang.StringUtils;
 8 import org.springframework.beans.factory.annotation.Autowired;
 9 import org.springframework.data.redis.core.StringRedisTemplate;
10 import org.springframework.web.bind.annotation.RequestMapping;
11 import org.springframework.web.bind.annotation.RequestParam;
12 import org.springframework.web.bind.annotation.RestController;
13 
14 import javax.servlet.http.HttpServletRequest;
15 import java.util.HashMap;
16 import java.util.Map;
17 import java.util.concurrent.TimeUnit;
18 
19 @RestController
20 @RequestMapping("api/vi/order")
21 public class ProductOrderController {
22     @Autowired
23     private ProductOrderService productOrderService;
24     @Autowired
25     private StringRedisTemplate redisTemplate;
26     @RequestMapping("save")
27     @HystrixCommand(fallbackMethod = "saveOrderFail")//调用save方法失败则执行saveOrderFail的方法
28     public  Object save(@RequestParam("user_id")int userId, @RequestParam("product_id")int productId, HttpServletRequest request){
29         Map<String, Object> data = new HashMap<>();
30         data.put("code",0);
31         data.put("data",productOrderService.save(userId,productId));
32         return data;
33     }
34     //编写fallback方法实现,方法签名一定要和api方法签名一致(注意点!!!)
35     private  Object saveOrderFail(int userId,int productId,HttpServletRequest request){
36         //监控报警
37         String saveOrderKey="save-order";
38         String sendValue = redisTemplate.opsForValue().get(saveOrderKey);
39         final  String ip = request.getRemoteAddr();
40 
41         //发送短信应该是异步的所以应该开启一个线程,就不会阻塞
42         new Thread(()->{
43             if(StringUtils.isBlank(sendValue)){//第二次别的服务调用时sendValue部位空
44                 System.out.println("紧急短信,用户下单失败,请离开查找原因,ip地址是="+ip);
45                 redisTemplate.opsForValue().set(saveOrderKey,"save-order-fail",20, TimeUnit.SECONDS);
46             }else {
47                 System.out.println("已经发送过短信,20秒内不重复发送");
48             }
49 
50         }).start();
51 
52         Map<String, Object> msg = new HashMap<>();
53          msg.put("code",-1);
54          msg.put("msg","访问人数过多,您被挤出来了,请稍后访问!");
55          return  msg;
56     }
57 
58 }

 

知道ip 这样的话我们就知道哪个服务出了问题

当product-service服务停了,我们访问

http://localhost:8781/api/vi/order/save?product_id=2&user_id=5

{"msg":"访问人数过多,您被挤出来了,请稍后访问!","code":-1}

 

看控制台

 

feign调用product-service 的findById出现异常
紧急短信,用户下单失败,请离开查找原因,ip地址是=0:0:0:0:0:0:0:1
feign调用product-service 的findById出现异常
已经发送过短信,20秒内不重复发送
feign调用product-service 的findById出现异常
已经发送过短信,20秒内不重复发送
feign调用product-service 的findById出现异常
已经发送过短信,20秒内不重复发送
2018-12-30 11:54:59.098  INFO 8116 --- [trap-executor-0] c.n.d.s.r.aws.ConfigClusterResolver      : Resolving eureka endpoints via configuration
紧急短信,用户下单失败,请离开查找原因,ip地址是=0:0:0:0:0:0:0:1   //20之后访问,此时sendValue为null,又发送短信
 feign调用product-service 的findById出现异常 

 

选redis的原因当其他服务也会从redis里面拿数据,起到共享的作用,防止多次发送短信

 

6、高级篇幅之深入源码剖析Hystrix降级策略和调整
简介:源码分析Hystrix降级策略和调整

问题:当我们调用product-service服务的findById时候,让它休眠2s

 1 @RequestMapping("findById")
 2     public Product findById(@RequestParam("id") int id){
 3         try {//2s
 4             TimeUnit.SECONDS.sleep(2);
 5         } catch (Exception e) {
 6             e.printStackTrace();
 7         }
 8         Product product = productService.findProduct(id);
 9         Product reslut = new Product();
10         //将product复制到result中
11         BeanUtils.copyProperties(product,reslut);
12         reslut.setName(reslut.getName()+"data from port = "+port);
13         return reslut;
14     }

 

 

1)此时通过order-service服务调用findById方法

http://localhost:8781/api/vi/order/save?product_id=2&user_id=5

 

2)控制台,由于我们处理了异常这是我们看到的情况,实际这个异常就是超时

feign调用product-service 的findById出现异常
2018-12-30 13:24:07.361  INFO 8472 --- [ HystrixTimer-1] io.lettuce.core.EpollProvider            : Starting without optional epoll library
2018-12-30 13:24:07.363  INFO 8472 --- [ HystrixTimer-1] io.lettuce.core.KqueueProvider           : Starting without optional kqueue library
紧急短信,用户下单失败,请离开查找原因,ip地址是=0:0:0:0:0:0:0:1

 

3)我们修改feign的异常超时时间为4s

1 feign:
2   hystrix:
3     enabled: true
4   client:
5     config:
6       default:
7         connectTimeout: 4000
8         readTimeout: 4000

 

4)再访问,还是同样的问题实际上这里还有一个超时没有配就是Hystrix的超时没有配置

方法一:不建议实际开中超时肯定是设置的

1 #把hystrix超时时间禁用
2 hystrix:
3   command:
4     default:
5       execution:
6         timeout:
7           enabled: false

 

 

http://localhost:8781/api/vi/order/save?product_id=2&user_id=5


{"code":0,"data":{"id":0,"productName":"\"iPhone7data from port = 8771\"","tradeNo":"e5717768-eb75-421e-8229-46637020acc2","price":7999,"createTime":"2018-12-30T05:39:03.618+0000","userId":5,"userName":null}}

 

方法二:超时时间调整(推荐)

hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 4000

 

1、查看默认讲解策略 HystrixCommandProperties(搜索HystrixCommand类》》右边列表HystrixCommandProperties

1)execution.isolation.strategy 隔离策略
THREAD 线程池隔离 (默认)

防止某一个服务过多占用服务器的线程,导致其他服务处于等待最后整个服务雪崩的。(Hystrix的作用)
SEMAPHORE 信号量
信号量适用于接口并发量高的情况,如每秒数千次调用的情况,导致的线程开销过高,通常只适用于非网络调用,执行速度快

2)execution.isolation.thread.timeoutInMillisecondsHystrixCommandProperties源码

超时时间
默认 1000毫秒

3)execution.timeout.enabled 是否开启超时限制 (一定不要禁用)


4)execution.isolation.semaphore.maxConcurrentRequests 隔离策略为 信号量的时候,如果达到最大并发数时,后续请求会被拒绝,默认是10


官方文档:
https://github.com/Netflix/Hystrix/wiki/Configuration#execution.isolation.strategy

 

7、断路器Dashboard监控仪表盘实战(开发中用的少
简介:讲解断路器Dashboard基础使用和查看
1、加入依赖

<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>

 

2、启动类增加注解
@EnableHystrixDashboard


3、配置文件增加endpoint

management:
  endpoints:
    web:
      exposure:
        include: "*"

 


4、访问入口

访问前将超时改一下

server:
  port: 8781


#指定注册中心地址
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/

#服务的名称
spring:
  application:
    name: order-service
  redis:
    database: 0
    host: 127.0.0.1
    port: 6379
    timeout: 2000
#自定义负载均衡策略
product-service:
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule


#修改调用超时时间
feign:
  hystrix:
    enabled: true
  client:
    config:
      default:
        connectTimeout: 2000
        readTimeout: 1000


#把hystrix超时时间禁用
#hystrix:
#  command:
 #   default:
  #    execution:
   #     timeout:
  #        enabled: false

#properties的格式
#execution.isolation.thread.timeoutInMilliseconds=4000

#设置超时时间yml格式
hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 1000

management:
  endpoints:
    web:
      exposure:
        include: "*"

  

控制台:

Proxy opening connection to: http://localhost:8781/actuator/hystrix.stream


参考资料
默认开启监控配置
https://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#boot-features-security-actuator

配置文件类:
spring-configuration-metadata.json

 

8、断路器监控仪表参数讲解和模拟熔断
简介:讲解 断路器监控仪表盘参数和模拟熔断

浏览器输入:

http://localhost:8781/hystrix

Hystrix Dashboard输入: http://localhost:8781/actuator/hystrix.stream

监控仪表参数页面

 

 

1、sse server-send-event推送到前端

资料:https://github.com/Netflix/Hystrix/wiki/Dashboard

 

posted on 2019-01-01 15:38  源无极  阅读(231)  评论(0编辑  收藏  举报