Spring Cloud 核心組件——熔斷降級


今天先來說說“服務熔斷”和“服務降級”。

服務熔斷:在股票市場,熔斷這個詞大家都不陌生,是指當股指波幅達到某個點后,交易所為控制風險采取的暫停交易措施。相應的,服務熔斷一般是指軟件系統中,由於某些原因使得服務出現了過載現象,為防止造成整個系統故障,從而采用的一種保護措施,所以很多地方把熔斷亦稱為過載保護。

服務降級:大家都見過女生旅行吧,大號的旅行箱是必備物,平常走走近處綽綽有余,但一旦出個遠門,再大的箱子都白搭了,怎么辦呢?常見的情景就是把物品拿出來分分堆,比了又比,最后一些非必需品的就忍痛放下了,等到下次箱子夠用了,再帶上用一用。而服務降級,就是這么回事,整體資源快不夠了,忍痛將某些服務先關掉,待渡過難關,再開啟回來。

所以從上述分析來看,兩者其實從有些角度看是有一定的類似性的:

1)目的很一致,都是從可用性可靠性着想,為防止系統的整體緩慢甚至崩潰,采用的技術手段;

2)最終表現類似,對於兩者來說,最終讓用戶體驗到的是某些功能暫時不可達或不可用;

3)粒度一般都是服務級別,當然,業界也有不少更細粒度的做法,比如做到數據持久層(允許查詢,不允許增刪改);

4)自治性要求很高,熔斷模式一般都是服務基於策略的自動觸發,降級雖說可人工干預,但在微服務架構下,完全靠人顯然不可能,開關預置、配置中心都是必要手段;

而兩者的區別也是明顯的:

1)觸發原因不太一樣,服務熔斷一般是某個服務(下游服務)故障引起,而服務降級一般是從整體負荷考慮;

2)管理目標的層次不太一樣,熔斷其實是一個框架級的處理,每個微服務都需要(無層級之分),而降級一般需要對業務有層級之分(比如降級一般是從最外圍服務開始)

3)實現方式不太一樣

參考文章:https://blog.csdn.net/guwei9111986/article/details/51649240

 

下面介紹 Hystrix:

在分布式環境中,許多服務依賴項中的一些必然會失敗。Hystrix 是一個庫,通過添加延遲容忍和容錯邏輯,幫助你控制這些分布式服務之間的交互。Hystrix 通過隔離服務之間的訪問點、停止級聯失敗和提供回退選項來實現這一點,所有這些都可以提高系統的整體彈性。

Hystrix 提供了熔斷、隔離、Fallback、Cache、監控等功能。出現錯誤之后可以 fallback 錯誤的處理信息,返回一些兜底數據等等。

https://www.cnblogs.com/cjsblog/p/9391819.html

 

本文的示例承接上一篇文章:https://www.cnblogs.com/jwen1994/p/11408511.html

1. Feign 結合 Hystrix 斷路器開發

第一步:加入依賴

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

注意新舊版本問題,所以要以官網為主,不然部分注解會丟失

第二步:啟動類里面增加注解 @EnableCircuitBreaker

@SpringBootApplication
@EnableFeignClients
@EnableCircuitBreaker public class OrderServiceApplication {

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

    @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

我們也可以使用 SpringCloudApplication 注解,它包含了很多 Spring Cloud 相關的注解

第三步:最外層 api 使用

api 方法上增加 @HystrixCommand(fallbackMethod = "saveOrderFail")。好比異常處理(網絡異常,參數或者內部調用問題)

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

    @Autowired
    private ProductOrderService productOrderService;

    @RequestMapping("save")
    @HystrixCommand(fallbackMethod = "saveOrderFail") public Object save(@RequestParam("user_id")int userId, @RequestParam("product_id") int productId){

        Map<String, Object> data = new HashMap<>();
        data.put("code", 0);
        data.put("data", productOrderService.save(userId, productId));
        return  data;
    }

    //注意,方法簽名一定要要和api方法一致
    private Object saveOrderFail(int userId, int productId){
        Map<String, Object> msg = new HashMap<>();
        msg.put("code", -1);
        msg.put("msg", "搶購人數太多,您被擠出來了,稍等重試");
        return msg;
    }
}

注意:編寫 fallback 方法實現,方法簽名一定要和 api 方法簽名一致

第四步:進行測試,我們使用一個會出錯的請求,它會返回 saveOrderFail 的返回值

 

2. 我們調用服務時,如果服務出錯,我們希望可以進行一些處理

 第一步:開啟 Feign 支持 Hystrix (注意,一定要開啟,舊版本默認支持,新版本默認關閉)

feign:
  hystrix:
    enabled: true

第二步:FeignClient(name="xxx", fallback=xxx.class ),class 需要繼承當前 FeignClient 的類

@FeignClient(name = "product-service", fallback = ProductClientFallback.class)
public interface ProductClient {
    @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("feign 調用product-service findbyid 異常");
        return null;
    }
}

 

3. 進一步完善異常報警通知

我們可以試着加入 Redis 來實現一個異常報警

第一步:加入 Redis 依賴

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

第二步:配置 Redis 鏈接信息

spring:
  redis:
    database: 0
    host: 127.0.0.1
    port: 6379
    timeout: 2000

第三步:修改代碼

@RestController
@RequestMapping("api/v1/order")
public class OrderController {
    @Autowired
    private ProductOrderService productOrderService;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @RequestMapping("save")
    @HystrixCommand(fallbackMethod = "saveOrderFail")
    public Object save(@RequestParam("user_id")int userId, @RequestParam("product_id") int productId, HttpServletRequest request){

        Map<String, Object> data = new HashMap<>();
        data.put("code", 0);
        data.put("data", productOrderService.save(userId, productId));
        return  data;
    }

    //注意,方法簽名一定要要和api方法一致
    private Object saveOrderFail(int userId, int productId, HttpServletRequest request){
        //監控報警
        String saveOrderKye = "save-order";

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

 

4. Hystrix 降級策略和調整

1)查看默認講解策略 HystrixCommandProperties

這個文件里可以看到所有默認的策略

2)execution.isolation.strategy 隔離策略

Hystrix 有兩種隔離策略:THREAD 線程池隔離 (默認)、SEMAPHORE 信號量。信號量適用於接口並發量高的情況,如每秒數千次調用的情況,導致的線程開銷過高,通常只適用於非網絡調用,執行速度快

3)execution.isolation.thread.timeoutInMilliseconds 超時時間

Hystrix 默認超時時間為1000毫秒

4)execution.timeout.enabled 是否開啟超時限制 (一定不要禁用)

Hystrix 默認是開啟超時限制的

5)execution.isolation.semaphore.maxConcurrentRequests 隔離策略為 信號量的時候,如果達到最大並發數時,后續請求會被拒絕,默認是10

#把hystrix超時時間禁用
#hystrix:
#  command:
#    default:
#      execution:
#        timeout:
#          enabled: false

#execution.isolation.thread.timeoutInMilliseconds=4000

#設置超時時間
hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 4000

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

5. 斷路器 Dashboard 監控儀表盤

生產環境幾乎不用,只要做好異常告警就可以

第一步:加入依賴

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

第二步:啟動類增加注解 @EnableHystrixDashboard

第三步:配置文件增加 endpoint

#暴露全部的監控信息
management:
  endpoints:
    web:
      exposure:
        include: "*"

第四步:訪問入口

1)訪問:http://localhost:8781/hystrix

2)Hystrix Dashboard 輸入: http://localhost:8781/actuator/hystrix.stream

參考資料:https://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#boot-features-security-actuator

 

 

補充: 如果從 Maven 中心倉庫下載太慢,可是修改 Maven 倉庫地址,使用其他 Maven 倉庫。為了使用阿里雲的倉庫,我們在 pom.xml 中修改

<repositories>
  <repository>
    <id>nexus-aliyun</id>
    <name>Nexus aliyun</name>
    <layout>default</layout>
    <url>http://maven.aliyun.com/nexus/content/groups/public</url>
    <snapshots>
      <enabled>false</enabled>
    </snapshots>
    <releases>
      <enabled>true</enabled>
    </releases>
  </repository>
</repositories>

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM