微服務(wù)架構(gòu)中的穩(wěn)定性保障:服務(wù)熔斷、降級(jí)和限流策略詳解

2024-12-27 14:14 更新

大家好,我是V哥,國(guó)足0-7不敵日本,創(chuàng)下12年來(lái)最大慘敗,真的好久不看球賽了,我關(guān)心的是,作為國(guó)內(nèi)唯一一家轉(zhuǎn)播平臺(tái)愛(ài)奇藝體育昨天崩了,官方道歉文中解釋由于瞬時(shí)流量過(guò)大導(dǎo)致,這讓我想起服務(wù)熔斷、降級(jí)和限流是微服務(wù)架構(gòu)中用于提高系統(tǒng)穩(wěn)定性和可用性的三種關(guān)鍵策略。

介紹

服務(wù)熔斷(Circuit Breaker)

服務(wù)熔斷是一種防止服務(wù)故障蔓延的機(jī)制。它的概念來(lái)源于電力系統(tǒng)中的熔斷器,當(dāng)電流超過(guò)電路的承載能力時(shí),熔斷器會(huì)自動(dòng)斷開(kāi)電路,以防止火災(zāi)等嚴(yán)重事故的發(fā)生。

在軟件架構(gòu)中,熔斷器模式通常用于處理服務(wù)調(diào)用鏈中的遠(yuǎn)程服務(wù)調(diào)用。當(dāng)某個(gè)服務(wù)調(diào)用失敗的次數(shù)超過(guò)預(yù)設(shè)閾值時(shí),熔斷器會(huì)“斷開(kāi)”,暫時(shí)停止對(duì)該服務(wù)的調(diào)用。這樣,系統(tǒng)可以快速失敗,避免長(zhǎng)時(shí)間的等待或大量的錯(cuò)誤,從而保持系統(tǒng)的穩(wěn)定性。在熔斷期間,通常會(huì)提供一個(gè)備用的行為或返回一個(gè)友好的錯(cuò)誤信息。

服務(wù)降級(jí)(Service Degradation)

服務(wù)降級(jí)是一種在系統(tǒng)負(fù)載過(guò)高或某些服務(wù)不可用時(shí),臨時(shí)關(guān)閉一些功能或降低服務(wù)標(biāo)準(zhǔn)的策略,以保證核心業(yè)務(wù)的正常運(yùn)行。

在一個(gè)電商平臺(tái)中,當(dāng)遇到流量高峰時(shí),可能會(huì)暫時(shí)關(guān)閉一些非核心功能,如商品推薦、優(yōu)惠券發(fā)放等,以減輕服務(wù)器壓力?;蛘?,當(dāng)支付服務(wù)不可用時(shí),系統(tǒng)可能會(huì)允許用戶將商品加入購(gòu)物車,但暫時(shí)無(wú)法完成購(gòu)買。

服務(wù)降級(jí)的目的是犧牲一部分用戶體驗(yàn),以確保系統(tǒng)不會(huì)因?yàn)檫^(guò)載而完全崩潰。

服務(wù)限流(Rate Limiting)

服務(wù)限流是一種控制服務(wù)調(diào)用頻率的策略,以保護(hù)系統(tǒng)不被過(guò)量的請(qǐng)求壓垮。

限流可以通過(guò)各種方式實(shí)現(xiàn),例如:

  • 令牌桶:按照固定速率向桶中添加令牌,每次請(qǐng)求需要消耗一個(gè)令牌。
  • 漏桶:請(qǐng)求以固定速率從桶中流出,如果流出速度跟不上請(qǐng)求速度,多余的請(qǐng)求會(huì)被拒絕。
  • 固定窗口計(jì)數(shù)器:在固定時(shí)間窗口內(nèi)計(jì)數(shù)請(qǐng)求次數(shù),超過(guò)限制則拒絕服務(wù)。

限流可以應(yīng)用于API網(wǎng)關(guān),以控制對(duì)下游服務(wù)的訪問(wèn)頻率,也可以應(yīng)用于服務(wù)內(nèi)部,以控制處理請(qǐng)求的速度。

高并發(fā)的電商購(gòu)物車服務(wù)案例

假設(shè)在一個(gè)高并發(fā)的電商購(gòu)物車服務(wù)案例,實(shí)現(xiàn)服務(wù)熔斷、降級(jí)和限流。我們將使用Spring Boot和Spring Cloud Alibaba Sentinel來(lái)實(shí)現(xiàn)這些功能。

1. 項(xiàng)目結(jié)構(gòu)

假設(shè)我們的項(xiàng)目結(jié)構(gòu)如下:

shopping-cart-service
├── pom.xml
├── src
│   ├── main
│   │   ├── java
│   │   │   └── com
│   │   │       └── example
│   │   │           └── shoppingcart
│   │   │               ├── ShoppingCartApplication.java
│   │   │               ├── controller
│   │   │               │   └── ShoppingCartController.java
│   │   │               ├── service
│   │   │               │   └── ShoppingCartService.java
│   │   │               └── config
│   │   │                   └── SentinelConfig.java
│   │   └── resources
│   │       ├── application.yml
│   │       └── flow-rules.json
└── .gitignore

2. 添加依賴

pom.xml中添加Spring Boot和Spring Cloud Alibaba Sentinel依賴:

<dependencies>
    <!-- Spring Boot Starter Web -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!-- Spring Cloud Alibaba Sentinel -->
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
    </dependency>
    <!-- Spring Boot Starter Actuator -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
</dependencies>


<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>Hoxton.SR9</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-alibaba-dependencies</artifactId>
            <version>2.2.5.RELEASE</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>

3. 應(yīng)用主類

ShoppingCartApplication.java中創(chuàng)建Spring Boot應(yīng)用:

package com.example.shoppingcart;


import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;


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

4. 配置文件

application.yml中配置Sentinel Dashboard地址:

server:
  port: 8080


spring:
  application:
    name: shopping-cart-service


spring:
  cloud:
    sentinel:
      transport:
        dashboard: localhost:8080
      datasource:
        ds1:
          type: file
          data-id: ${spring.application.name}-flow-rules
          rule-type: flow
          url: file:///path/to/your/flow-rules.json

5. 熔斷、降級(jí)和限流規(guī)則

flow-rules.json中配置熔斷、降級(jí)和限流規(guī)則:

[
  {
    "resource": "addCart",
    "limitApp": "default",
    "grade": 1,
    "strategy": 0,
    "controlBehavior": 0,
    "threshold": 10,
    "action": 1
  },
  {
    "resource": "addCart",
    "limitApp": "default",
    "grade": 0,
    "strategy": 0,
    "controlBehavior": 1,
    "threshold": 5,
    "action": 1
  },
  {
    "resource": "addCart",
    "limitApp": "default",
    "grade": 0,
    "strategy": 0,
    "controlBehavior": 0,
    "threshold": 20,
    "action": 2
  }
]

6. 控制器

ShoppingCartController.java中創(chuàng)建REST API:

package com.example.shoppingcart.controller;


import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.example.shoppingcart.service.ShoppingCartService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;


@RestController
public class ShoppingCartController {


    @Autowired
    private ShoppingCartService shoppingCartService;


    @GetMapping("/addCart")
    public String addCart(@RequestParam String productId, @RequestParam int quantity) {
        try (Entry entry = SphU.entry("addCart")) {
            return shoppingCartService.addCart(productId, quantity);
        } catch (BlockException ex) {
            return shoppingCartService.fallback();
        }
    }
}

7. 服務(wù)

ShoppingCartService.java中實(shí)現(xiàn)業(yè)務(wù)邏輯:

package com.example.shoppingcart.service;


public class ShoppingCartService {


    public String addCart(String productId, int quantity) {
        // 模擬業(yè)務(wù)邏輯
        if (quantity > 10) {
            throw new RuntimeException("Quantity too large");
        }
        return "Added " + quantity + " of " + productId + " to cart";
    }


    public String fallback() {
        return "Cart service is temporarily unavailable";
    }
}

8. 配置類

SentinelConfig.java中配置Sentinel規(guī)則:

package com.example.shoppingcart.config;


import com.alibaba.csp.sentinel.init.InitConfig;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;


import java.util.ArrayList;
import java.util.List;


@Configuration
public class SentinelConfig {


    @Bean
    public InitConfig initConfig() {
        InitConfig initConfig = new InitConfig();
        initConfig.setDataSource("file", "classpath:flow-rules.json");
        return initConfig;
    }


    @Bean
    public List<FlowRule> flowRules() {
        List<FlowRule> rules = new ArrayList<>();
        FlowRule rule = new FlowRule("addCart");
        rule.setCount(10); // 限流閾值
        rule.setGrade(RuleConstant.FLOW_GRADE_QPS); // QPS模式
        rule.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_DEFAULT); // 直接拒絕
        rules.add(rule);
        return rules;
    }


    @Bean
    public List<DegradeRule> degradeRules() {
        List<DegradeRule> rules = new ArrayList<>();
        DegradeRule rule = new DegradeRule("addCart");
        rule.setGrade(RuleConstant.DEGRADE_GRADE_RT); // 響應(yīng)時(shí)間模式
        rule.setCount(500); // 響應(yīng)時(shí)間閾值
        rule.setTimeWindow(10); // 時(shí)間窗口
        rule.setMinRequestAmount(5); // 最小請(qǐng)求量
        rules.add(rule);
        return rules;
    }
}

9. 啟動(dòng)Sentinel Dashboard

確保你已經(jīng)啟動(dòng)了Sentinel Dashboard,可以通過(guò)以下命令啟動(dòng):

java -jar sentinel-dashboard.jar

10. 運(yùn)行應(yīng)用

運(yùn)行ShoppingCartApplication,然后通過(guò)瀏覽器或Postman測(cè)試API:

http://localhost:8080/addCart?productId=123&quantity=5

解釋一下

  1. 熔斷:當(dāng)addCart方法的調(diào)用次數(shù)超過(guò)10次時(shí),Sentinel會(huì)觸發(fā)熔斷,直接返回降級(jí)邏輯。
  2. 降級(jí):當(dāng)addCart方法的響應(yīng)時(shí)間超過(guò)500ms,或者調(diào)用次數(shù)超過(guò)5次時(shí),Sentinel會(huì)觸發(fā)降級(jí),返回降級(jí)邏輯。
  3. 限流:當(dāng)addCart方法的調(diào)用次數(shù)超過(guò)10次時(shí),Sentinel會(huì)觸發(fā)限流,直接拒絕請(qǐng)求。

通過(guò)這些配置,我們可以在高并發(fā)場(chǎng)景下保護(hù)我們的服務(wù),避免系統(tǒng)過(guò)載。

最后

  • 熔斷:當(dāng)服務(wù)不可用時(shí),快速失敗,避免系統(tǒng)過(guò)載。
  • 降級(jí):在系統(tǒng)壓力較大時(shí),暫時(shí)關(guān)閉或降低非核心服務(wù)的質(zhì)量,保證核心服務(wù)的可用性。
  • 限流:控制請(qǐng)求的速率,防止系統(tǒng)因請(qǐng)求過(guò)多而崩潰。

這三種策略通常結(jié)合使用,以提高大型分布式系統(tǒng)的穩(wěn)定性和可用性。

以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)