Spring Cloud 熔断降级

1、 什么是熔断

一般是某个服务故障或者是异常引起的,类似现实世界中的‘保险丝’,当某个异常条件被触发,直接熔断整个服务,而不是一直等到此服务超时,为了防止防止整个系统的故障,而采用了一些保护措施。过载保护。
比如A服务的X功能依赖B服务的某个接口,当B服务接口响应很慢时,A服务X功能的响应也会被拖慢,进一步导致了A服务的线程都卡在了X功能上,A服务的其它功能也会卡主或拖慢。此时就需要熔断机制,即A服务不在请求B这个接口,而可以直接进行降级处理。

2、 什么是降级

服务器当压力剧增的时候,根据当前业务情况及流量,对一些服务和页面进行有策略的降级。以此缓解服务器资源的的压力,以保证核心业务的正常运行,同时也保持了客户和大部分客户的得到正确的相应。

3、熔断和降级异同

相同点:
1.从可用性和可靠性触发,为了防止系统崩溃
2.最终让用户体验到的是某些功能暂时不能用
不同点:
1.服务熔断一般是下游服务故障导致的,而服务降级一般是从整体系统负荷考虑,由调用方控制。

4、Netflix开源组件断路器Hystrix

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

为什么用Hystrix

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

Hystrix是如何实现它的目标的

(1)通过HystrixCommand或者HystrixObservableCommand来封装对外部依赖的访问请求,这个访问请求一般会运行在独立的线程中,资源隔离
(2)对于超出我们设定阈值的服务调用,直接进行超时,不允许其耗费过长时间阻塞住。这个超时时间默认是99.5%的访问时间,但是一般我们可以自己设置一下
(3)为每一个依赖服务维护一个独立的线程池,或者是semaphore,当线程池已满时,直接拒绝对这个服务的调用
(4)对依赖服务的调用的成功次数,失败次数,拒绝次数,超时次数,进行统计
(5)如果对一个依赖服务的调用失败次数超过了一定的阈值,自动进行熔断,在一定时间内对该服务的调用直接降级,一段时间后再自动尝试恢复
(6)当一个服务调用出现失败,被拒绝,超时,短路等异常情况时,自动调用fallback降级机制
(7)对属性和配置的修改提供近实时的支持

5、Hystrix实战

使用到的组件包括:Eureka、Feign包括以下三个项目:
(1)Eureka-server: 注册中心
(2)product-service :商品微服务
(3)order-service: 订单微服务
前面文章已经搭建过 这里不做赘述 这里只写order-service微服务
pom.xml 添加依赖

  <!--hystrix依赖 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>

application.yml

server:
  port: 8781

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

#服务的名称
spring:
  application:
    name: order-service
    
#开启feign支持hystrix  (注意,一定要开启,旧版本默认支持,新版本默认关闭)
# #修改调用超时时间(默认是1秒就算超时)
feign:
  hystrix:
    enabled: true
  client:
    config:
      default:
        connectTimeout: 2000
        readTimeout: 2000
#hystrix超时时间调整(默认是一秒)
hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 2000

SpringBoot启动类

@SpringBootApplication
@EnableFeignClients
//添加熔断降级注解
@EnableCircuitBreaker
public class OrderServiceApplication {

    public static void main(String[] args) {
        SpringApplication.run(OrderApplication.class, args);
    }

}

ProductClient

/**
 * 商品服务客户端
 * name = "product-service"是你调用服务端名称
 * fallback = ProductClientFallback.class,后面是你自定义的降级处理类,降级类一定要实现ProductClient
 */
@FeignClient(name = "product-service",fallback = ProductClientFallback.class)
public interface ProductClient {

    //这样组合就相当于http://product-service/api/v1/product/find
    @GetMapping("/api/v1/product/find")
    String findById(@RequestParam(value = "id") int id);

}

ProductClientFallback降级处理类

/**
 * 针对商品服务,错降级处理
 */
@Component
public class ProductClientFallback implements ProductClient {

    @Override
    public String findById(int id) {

        System.out.println("ProductClientFallback中的降级方法");

        //这对gai该接口进行一些逻辑降级处理........
        return null;
    }
}

OrderController类
注意:fallbackMethod = "saveOrderFail"中的saveOrderFail方法中的参数类型,个数,顺序要和save一模一样,否则会报找不到saveOrderFail方法。

@RestController
@RequestMapping("api/v1/order")
public class OrderController {

    @Autowired
    private ProductOrderService productOrderService;

    @RequestMapping("save")
    //当调用微服务出现异常会降级到saveOrderFail方法中
    @HystrixCommand(fallbackMethod = "saveOrderFail")
    public Object save(@RequestParam("user_id")int userId, @RequestParam("product_id") int productId){

        return productOrderService.save(userId, productId);
    }

    //注意,方法签名一定要要和api方法一致
    private Object saveOrderFail(int userId, int productId){

        System.out.println("controller中的降级方法");

        Map<String, Object> msg = new HashMap<>();
        msg.put("code", -1);
        msg.put("msg", "抢购人数太多,您被挤出来了,稍等重试");
        return msg;
    }
}

测试

正常情况时如图:
订单服务调用商品服务正常

异常情况

此刻商品微服务停掉:只启动订单微服务,这时去调用商品服务当然会出现超时异常情况在调接口,发现已经成功到降级方法里
在看controller中的降级方法和ProductClientFallback降级方法的实现先后顺序,它们的顺序是不固定的,具体要看哪个线程先获得cpu执行权

6、结合redis模拟熔断降级服务异常报警通知实战

主要是完善服务熔断处理,报警机制完善结合redis进行模拟短信通知用户下单失败。
pom.xml

  <!--springboot整合redis-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

application.yml

#redis
spring:
  application:
    name: order-service
  redis:
    database: 0
    host: 127.0.0.1
    port: 6379
    timeout: 2000

OrderController类
主要看降级方法的不同

@RestController
@RequestMapping("api/v1/order")
public class OrderController {

    @Autowired
    private ProductOrderService productOrderService;

    //添加bean
    @Autowired
    private StringRedisTemplate redisTemplate;

    @RequestMapping("save")
    //当调用微服务出现异常会降级到saveOrderFail方法中
    @HystrixCommand(fallbackMethod = "saveOrderFail")
    public Object save(@RequestParam("user_id")int userId, @RequestParam("product_id") int productId,HttpServletRequest request){

        return productOrderService.save(userId, productId);
    }

    //注意,方法签名一定要要和api方法一致
    private Object saveOrderFail(int userId, int productId, HttpServletRequest request){
        
        //监控报警
        String saveOrderKye = "save-order";
        //有数据代表20秒内已经发过
        String sendValue = redisTemplate.opsForValue().get(saveOrderKye);
        final String ip = request.getRemoteAddr();

        //新启动一个线程进行业务逻辑处理
        new Thread( ()->{
            if (StringUtils.isBlank(sendValue)) {
                System.out.println("紧急短信,用户下单失败,请离开查找原因,ip地址是="+ip);
                //发送一个http请求,调用短信服务 TODO
                redisTemplate.opsForValue().set(saveOrderKye, "save-order-fail", 20, TimeUnit.SECONDS);

            }else{
                System.out.println("已经发送过短信,20秒内不重复发送");
            }
        }).start();

        Map<String, Object> msg = new HashMap<>();
        msg.put("code", -1);
        msg.put("msg", "抢购人数太多,您被挤出来了,稍等重试");
        return msg;
    }

}

测试

当20秒内连续发请求会提醒已发短信。

7、 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、访问入口

    http://localhost:8781/hystrix
    Hystrix Dashboard输入: http://localhost:8781/actuator/hystrix.stream 
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,657评论 6 505
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,889评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,057评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,509评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,562评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,443评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,251评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,129评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,561评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,779评论 3 335
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,902评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,621评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,220评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,838评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,971评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,025评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,843评论 2 354

推荐阅读更多精彩内容