大家好,我是V哥,國足0-7不敵日本,創下12年來最大慘敗,真的好久不看球賽了,我關心的是,作為國內唯一一家轉播平台愛奇藝體育昨天崩了,官方道歉文中解釋由於瞬時流量過大導致,這讓我想起服務熔斷、降級和限流是微服務架構中用於提高系統穩定性和可用性的三種關鍵策略。
介紹
服務熔斷(Circuit Breaker)
服務熔斷是一種防止服務故障蔓延的機制。它的概念來源於電力系統中的熔斷器,當電流超過電路的承載能力時,熔斷器會自動斷開電路,以防止火災等嚴重事故的發生。
在軟件架構中,熔斷器模式通常用於處理服務調用鏈中的遠程服務調用。當某個服務調用失敗的次數超過預設閾值時,熔斷器會“斷開”,暫時停止對該服務的調用。這樣,系統可以快速失敗,避免長時間的等待或大量的錯誤,從而保持系統的穩定性。在熔斷期間,通常會提供一個備用的行為或返回一個友好的錯誤信息。
服務降級(Service Degradation)
服務降級是一種在系統負載過高或某些服務不可用時,臨時關閉一些功能或降低服務標準的策略,以保證核心業務的正常運行。
在一個電商平台中,當遇到流量高峯時,可能會暫時關閉一些非核心功能,如商品推薦、優惠券發放等,以減輕服務器壓力。或者,當支付服務不可用時,系統可能會允許用户將商品加入購物車,但暫時無法完成購買。
服務降級的目的是犧牲一部分用户體驗,以確保系統不會因為過載而完全崩潰。
服務限流(Rate Limiting)
服務限流是一種控制服務調用頻率的策略,以保護系統不被過量的請求壓垮。
限流可以通過各種方式實現,例如:
- 令牌桶:按照固定速率向桶中添加令牌,每次請求需要消耗一個令牌。
- 漏桶:請求以固定速率從桶中流出,如果流出速度跟不上請求速度,多餘的請求會被拒絕。
- 固定窗口計數器:在固定時間窗口內計數請求次數,超過限制則拒絕服務。
限流可以應用於API網關,以控制對下游服務的訪問頻率,也可以應用於服務內部,以控制處理請求的速度。
高併發的電商購物車服務案例
假設在一個高併發的電商購物車服務案例,實現服務熔斷、降級和限流。我們將使用Spring Boot和Spring Cloud Alibaba Sentinel來實現這些功能。
1. 項目結構
假設我們的項目結構如下:
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. 應用主類
在ShoppingCartApplication.java中創建Spring Boot應用:
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. 熔斷、降級和限流規則
在flow-rules.json中配置熔斷、降級和限流規則:
[
{
"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中創建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. 服務
在ShoppingCartService.java中實現業務邏輯:
package com.example.shoppingcart.service;
public class ShoppingCartService {
public String addCart(String productId, int quantity) {
// 模擬業務邏輯
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規則:
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); // 響應時間模式
rule.setCount(500); // 響應時間閾值
rule.setTimeWindow(10); // 時間窗口
rule.setMinRequestAmount(5); // 最小請求量
rules.add(rule);
return rules;
}
}
9. 啓動Sentinel Dashboard
確保你已經啓動了Sentinel Dashboard,可以通過以下命令啓動:
java -jar sentinel-dashboard.jar
10. 運行應用
運行ShoppingCartApplication,然後通過瀏覽器或Postman測試API:
http://localhost:8080/addCart?productId=123&quantity=5
解釋一下
- 熔斷:當
addCart方法的調用次數超過10次時,Sentinel會觸發熔斷,直接返回降級邏輯。 - 降級:當
addCart方法的響應時間超過500ms,或者調用次數超過5次時,Sentinel會觸發降級,返回降級邏輯。 - 限流:當
addCart方法的調用次數超過10次時,Sentinel會觸發限流,直接拒絕請求。
通過這些配置,我們可以在高併發場景下保護我們的服務,避免系統過載。
最後
- 熔斷:當服務不可用時,快速失敗,避免系統過載。
- 降級:在系統壓力較大時,暫時關閉或降低非核心服務的質量,保證核心服務的可用性。
- 限流:控制請求的速率,防止系統因請求過多而崩潰。
這三種策略通常結合使用,以提高大型分佈式系統的穩定性和可用性。