大家好,我是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ù)熔斷是一種防止服務(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í)是一種在系統(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ù)限流是一種控制服務(wù)調(diào)用頻率的策略,以保護(hù)系統(tǒng)不被過(guò)量的請(qǐng)求壓垮。
限流可以通過(guò)各種方式實(shí)現(xiàn),例如:
限流可以應(yīng)用于API網(wǎng)關(guān),以控制對(duì)下游服務(wù)的訪問(wèn)頻率,也可以應(yīng)用于服務(wù)內(nèi)部,以控制處理請(qǐng)求的速度。
假設(shè)在一個(gè)高并發(fā)的電商購(gòu)物車服務(wù)案例,實(shí)現(xiàn)服務(wù)熔斷、降級(jí)和限流。我們將使用Spring Boot和Spring Cloud Alibaba Sentinel來(lái)實(shí)現(xiàn)這些功能。
假設(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
在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>
在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);
}
}
在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
在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
}
]
在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();
}
}
}
在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";
}
}
在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;
}
}
確保你已經(jīng)啟動(dòng)了Sentinel Dashboard,可以通過(guò)以下命令啟動(dòng):
java -jar sentinel-dashboard.jar
運(yùn)行ShoppingCartApplication
,然后通過(guò)瀏覽器或Postman測(cè)試API:
http://localhost:8080/addCart?productId=123&quantity=5
addCart
方法的調(diào)用次數(shù)超過(guò)10次時(shí),Sentinel會(huì)觸發(fā)熔斷,直接返回降級(jí)邏輯。addCart
方法的響應(yīng)時(shí)間超過(guò)500ms,或者調(diào)用次數(shù)超過(guò)5次時(shí),Sentinel會(huì)觸發(fā)降級(jí),返回降級(jí)邏輯。addCart
方法的調(diào)用次數(shù)超過(guò)10次時(shí),Sentinel會(huì)觸發(fā)限流,直接拒絕請(qǐng)求。通過(guò)這些配置,我們可以在高并發(fā)場(chǎng)景下保護(hù)我們的服務(wù),避免系統(tǒng)過(guò)載。
這三種策略通常結(jié)合使用,以提高大型分布式系統(tǒng)的穩(wěn)定性和可用性。
更多建議: