zoukankan      html  css  js  c++  java
  • SpringCloud之Hystrix断路器(六)

    雪崩效应
    在微服务架构中,一个请求需要调用多个服务是非常常见的。如客户端访问A服务,而A服务需要调用B
    服务,B服务需要调用C服务,由于网络原因或者自身的原因,如果B服务或者C服务不能及时响应,A服
    务将处于阻塞状态,直到B服务C服务响应。此时若有大量的请求涌入,容器的线程资源会被消耗完毕,
    导致服务瘫痪。服务与服务之间的依赖性,故障会传播,造成连锁反应,会对整个微服务系统造成灾难
    性的严重后果,这就是服务故障的“雪崩”效应。

    雪崩是系统中的蝴蝶效应导致其发生的原因多种多样,有不合理的容量设计,或者是高并发下某一个方
    法响应变慢,亦或是某台机器的资源耗尽。从源头上我们无法完全杜绝雪崩源头的发生,但是雪崩的根
    本原因来源于服务之间的强依赖,所以我们可以提前评估,做好熔断,隔离,限流。

    服务隔离
    顾名思义,它是指将系统按照一定的原则划分为若干个服务模块,各个模块之间相对独立,无强依赖。
    当有故障发生时,能将问题和影响隔离在某个模块内部,而不扩散风险,不波及其它模块,不影响整体
    的系统服务。

    熔断降级
    熔断这一概念来源于电子工程中的断路器(Circuit Breaker)。在互联网系统中,当下游服务因访问压
    力过大而响应变慢或失败,上游服务为了保护系统整体的可用性,可以暂时切断对下游服务的调用。这
    种牺牲局部,保全整体的措施就叫做熔断。

    所谓降级,就是当某个服务熔断之后,服务器将不再被调用,此时客户端可以自己准备一个本地的
    fallback回调,返回一个缺省值。 也可以理解为兜底

     服务限流

    限流可以认为服务降级的一种,限流就是限制系统的输入和输出流量已达到保护系统的目的。一般来说
    系统的吞吐量是可以被测算的,为了保证系统的稳固运行,一旦达到的需要限制的阈值,就需要限制流
    量并采取少量措施以完成限制流量的目的。比方:推迟解决,拒绝解决,或者者部分拒绝解决等等。

    Hystrix介绍

    Hystrix 是由Netflix开源的一个延迟和容错库,用于隔离访问远程系统、服务或者第三方库,防止级联失
    败,从而提升系统的可用性与容错性。Hystrix主要通过以下几点实现延迟和容错。
    包裹请求:使用 HystrixCommand包裹对依赖的调用逻辑,每个命令在独立线程中执行。这使用
    了设计模式中的“命令模式”。
    跳闸机制:当某服务的错误率超过一定的阈值时, Hystrix可以自动或手动跳闸,停止请求该服务一段时间。
    资源隔离: Hystrix为每个依赖都维护了一个小型的线程池(或者信号量)。如果该线程池已满,
    发往该依赖的请求就被立即拒绝,而不是排队等待,从而加速失败判定。
    监控: Hystrix可以近乎实时地监控运行指标和配置的变化,例如成功、失败、超时、以及被拒绝的请求等。
    回退机制:当请求失败、超时、被拒绝,或当断路器打开时,执行回退逻辑。回退逻辑由开发人员
    自行提供,例如返回一个缺省值。
    自我修复:断路器打开一段时间后,会自动进入 “半开”状态。

    整合Hystrix

    • order-service

      • pom.xml

      •       <dependency>
                    <groupId>org.springframework.cloud</groupId>
                    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
                </dependency>
      • web层

         1 @RestController
         2 @RequestMapping("/api/v1/order")
         3 public class OrderController {
         4  5  6     @Autowired(required = false)
         7     private ProductOrderServiceImpl productOrderService;
         8  9 10     @RequestMapping("/save")
        11     @HystrixCommand(fallbackMethod="saveOrderFail")
        12     public Object save(@RequestParam("user_id")int userId, @RequestParam("product_id") int productId){
        13 14         Map<String, Object> data = new HashMap<>();
        15         data.put("code", 0);
        16         data.put("data", productOrderService.save(userId, productId));
        17         return  data;
        18     }
        19 20     //注意,方法签名一定要要和api方法一致
        21     public Object saveOrderFail(int userId,int productId){
        22 23         Map<String, Object> msg = new HashMap<>();
        24         msg.put("code", -1);
        25         msg.put("msg", "抢购人数太多,您被挤出来了,稍等重试");
        26         return msg;
        27     }
        28 29 30 }
      • application.yml

         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 hystrix:
        18   command:
        19     default:
        20       execution:
        21         isolation:
        22           thread:
        23              timeoutInMilliseconds: 7000
        24 ribbon:
        25 ##指的是建立连接所用的时间,适用于网络状况正常的情况下,两端连接所用的时间。
        26   ReadTimeout: 3000
        27 ##指的是建立连接后从服务器读取到可用资源所用的时间。
        28   ConnectTimeout: 3000
        29 30 #自定义负载均衡策略
        31 #product-service:
        32 #  ribbon:
        33 #    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
    • product-service

      • service层

         1 package com.topcheer.producerservice.controller;
         2  3 import com.topcheer.producerservice.domain.Product;
         4 import com.topcheer.producerservice.service.ProductService;
         5 import org.springframework.beans.BeanUtils;
         6 import org.springframework.beans.factory.annotation.Autowired;
         7 import org.springframework.beans.factory.annotation.Value;
         8 import org.springframework.web.bind.annotation.*;
         9 10 import java.util.concurrent.TimeUnit;
        11 12 @RestController
        13 @RequestMapping("/api/v1/product")
        14 public class ProductController {
        15 16 17 18     @Value("${server.port}")
        19     private String port;
        20 21     @Autowired
        22     private ProductService productService;
        23 24     /**
        25      * 获取所有商品列表
        26      * @return
        27      */
        28     @RequestMapping("list")
        29     public Object list(){
        30         return productService.listProduct();
        31     }
        32 33 34     /**
        35      * 根据id查找商品详情
        36      * @param id
        37      * @return
        38      */
        39     @RequestMapping("find")
        40     public Object findById(int id){
        41 42         try {
        43             TimeUnit.SECONDS.sleep(2);
        44         } catch (InterruptedException e) {
        45             e.printStackTrace();
        46         }
        47         Product product = productService.findById(id);
        48 49         Product result = new Product();
        50         BeanUtils.copyProperties(product,result);
        51         result.setName( result.getName() + " data from port="+port );
        52         return result;
        53     }
        54 55 }
        启动类也要添加注解
      • SpringBootApplication
        @EntityScan("com.topcheer.order.entity")
        @EnableFeignClients
        @EnableHystrix
        public class OrderApplication {
        
            /**
             * 使用spring提供的RestTemplate发送http请求到商品服务
             *      1.创建RestTemplate对象交给容器管理
             *      2.在使用的时候,调用其方法完成操作 (getXX,postxxx)
             * * @LoadBalanced : 是ribbon提供的负载均衡的注解
             */
            @LoadBalanced
            @Bean
            public RestTemplate restTemplate() {
                return new RestTemplate();
            }
        
            public static void main(String[] args) {
                SpringApplication.run(OrderApplication.class,args);
            }
        }

         注:也可以卸载整个类上,代表整个类都会走这个异常

                

    • 结果:

      当前面的ribbon配置3秒的时候,可以直接返回结果。

      当前面的ribbon配置2秒的时候,会被HystrixCommand里面的异常方法捕获到。

  • 相关阅读:
    《python核心编程第二版》第8章习题
    《python核心编程第二版》第7章习题
    虚拟Ip技术如何实现备机容灾
    LeetCode算法编程连载之五
    GIT使用入门篇(管理自已的代码)
    LeetCode算法编程之连载四(二分法)
    LeetCode算法编程之连载三
    LeetCode算法编程之连载二
    LeetCode算法编程之连载一
    Python 使用flush函数将缓冲区数据立即写磁盘
  • 原文地址:https://www.cnblogs.com/dalianpai/p/11705194.html
Copyright © 2011-2022 走看看