分布式系統(tǒng)流控、熔斷:Sentinel的使用

前言

隨著微服務(wù)的流行,服務(wù)和服務(wù)之間的穩(wěn)定性變得越來越重要。Sentinel 以流量為切入點(diǎn),從流量控制、熔斷降級、系統(tǒng)負(fù)載保護(hù)等多個維度保護(hù)服務(wù)的穩(wěn)定性。

Sentinel 具有以下特征:

  • 豐富的應(yīng)用場景:Sentinel 承接了阿里巴巴近 10 年的雙十一大促流量的核心場景,例如秒殺(即突發(fā)流量控制在系統(tǒng)容量可以承受的范圍)、消息削峰填谷、集群流量控制、實(shí)時熔斷下游不可用應(yīng)用等。

  • 完備的實(shí)時監(jiān)控:Sentinel 同時提供實(shí)時的監(jiān)控功能。您可以在控制臺中看到接入應(yīng)用的單臺機(jī)器秒級數(shù)據(jù),甚至 500 臺以下規(guī)模的集群的匯總運(yùn)行情況。

  • 廣泛的開源生態(tài):Sentinel 提供開箱即用的與其它開源框架/庫的整合模塊,例如與 Spring Cloud、Dubbo、gRPC 的整合。您只需要引入相應(yīng)的依賴并進(jìn)行簡單的配置即可快速地接入 Sentinel。

  • 完善的 SPI 擴(kuò)展點(diǎn):Sentinel 提供簡單易用、完善的 SPI 擴(kuò)展接口。您可以通過實(shí)現(xiàn)擴(kuò)展接口來快速地定制邏輯。例如定制規(guī)則管理、適配動態(tài)數(shù)據(jù)源等。

以上內(nèi)容引自 Sentinel 官方介紹。在本文中,筆者將從實(shí)際應(yīng)用的角度,來學(xué)習(xí)Sentinel的使用。

一、初識Sentinel

首先,我們需要引入Sentinel的依賴。

<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-core</artifactId>
    <version>1.7.2</version>
</dependency>

Sentinel 支持以下幾種規(guī)則:流量控制規(guī)則、熔斷降級規(guī)則、系統(tǒng)保護(hù)規(guī)則、來源訪問控制規(guī)則 和 熱點(diǎn)參數(shù)規(guī)則。

在這里,我們來展示一個流量控制和熔斷降級的示例。

1、流量控制

流量控制,其原理是監(jiān)控應(yīng)用流量的 QPS 或并發(fā)線程數(shù)等指標(biāo),當(dāng)達(dá)到指定的閾值時對流量進(jìn)行控制,以避免被瞬時的流量高峰沖垮,從而保障應(yīng)用的高可用性。

我們以 QPS 為例,先來定義它的規(guī)則,相關(guān)屬性含義見注釋。

/**
 * 加載限流規(guī)則
 * @param resource
 */
public static void loadFlowRules(String resource){
    FlowRule rule = new FlowRule();
    //資源名稱,可以是任意字符串
    rule.setResource(resource);
    //限流閾值
    rule.setCount(5);
    //限流閾值類型,設(shè)置為QPS。即每秒QPS大于5時,觸發(fā)限流
    rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
    //針對的調(diào)用來源
    rule.setLimitApp("default");
    //調(diào)用關(guān)系限流策略,默認(rèn)按照資源本身
    rule.setStrategy(RuleConstant.STRATEGY_DIRECT);
    //限流效果,默認(rèn)直接拒絕
    rule.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_DEFAULT);
    //是否集群限流
    rule.setClusterMode(false);
    FlowRuleManager.loadRules(Collections.singletonList(rule));
}

如上代碼,當(dāng)每秒的請求數(shù)達(dá)到 5 之后,就會直接拒絕當(dāng)前時間窗口的后續(xù)請求。

接下來,我們把需要控制流量的代碼用 Sentinel API SphU.entry("resource") 和 entry.exit() 包圍起來即可。

public static void main(String[] args) throws InterruptedException {
    loadFlowRules("orderService");
    while (!stop){
        count.incrementAndGet();
        Entry entry = null;
        try {
            entry = SphU.entry(resource);
            logger.info("業(yè)務(wù)操作...{}",count.get());
        } catch (BlockException e) {
            logger.error("請求被限流...{}",count.get());
            Thread.sleep(1000);
        } finally {
            if (entry != null) {
                entry.exit();
            }
            if (count.get()>=20){
                stop = true;
            }
        }
    }
}

如上代碼,我們先通過loadFlowRules()方法加載限流規(guī)則。然后將業(yè)務(wù)操作用Sentinel API包圍起來。

我們定義的限流閾值是5,這里一共有20個請求。觸發(fā)限流之后,我們的線程停頓1秒,以便度過當(dāng)前的時間窗口,所以會有3個請求被限流。

運(yùn)行代碼,我們可以得到以下結(jié)果:

14:38:00.463  - 業(yè)務(wù)操作...1
14:38:00.465  - 業(yè)務(wù)操作...2
14:38:00.465  - 業(yè)務(wù)操作...3
14:38:00.465  - 業(yè)務(wù)操作...4
14:38:00.465  - 業(yè)務(wù)操作...5
14:38:00.494  - 請求被限流...6
14:38:01.494  - 業(yè)務(wù)操作...7
14:38:01.494  - 業(yè)務(wù)操作...8
14:38:01.495  - 業(yè)務(wù)操作...9
14:38:01.495  - 業(yè)務(wù)操作...10
14:38:01.495  - 業(yè)務(wù)操作...11
14:38:01.496  - 請求被限流...12
14:38:02.497  - 業(yè)務(wù)操作...13
14:38:02.497  - 業(yè)務(wù)操作...14
14:38:02.497  - 業(yè)務(wù)操作...15
14:38:02.497  - 業(yè)務(wù)操作...16
14:38:02.497  - 業(yè)務(wù)操作...17
14:38:02.497  - 請求被限流...18
14:38:03.498  - 業(yè)務(wù)操作...19
14:38:03.498  - 業(yè)務(wù)操作...20

2、熔斷

除了流量控制以外,對調(diào)用鏈路中不穩(wěn)定的資源進(jìn)行熔斷降級也是保障高可用的重要措施之一。

Sentinel 熔斷降級會在調(diào)用鏈路中某個資源出現(xiàn)不穩(wěn)定狀態(tài)時(例如調(diào)用超時或異常比例升高),對這個資源的調(diào)用進(jìn)行限制,讓請求快速失敗,避免影響到其它的資源而導(dǎo)致級聯(lián)錯誤。

那怎么來衡量資源是否穩(wěn)定呢?

Sentinel提供了三種方式,平均響應(yīng)時間、異常比例和異常數(shù)。

我們拿平均響應(yīng)時間為例,先來定義它的規(guī)則。

/**
 * 1秒內(nèi)的5個請求,平均響應(yīng)時間大于10ms,接下來的3秒內(nèi)都會自動熔斷。
 * @param resourceName
 */
public static void loadDegradeRule(String resourceName){
    List<DegradeRule> rules = new ArrayList<>();
    DegradeRule rule = new DegradeRule();
    //資源名稱
    rule.setResource(resourceName);
    //閾值 - 10ms
    rule.setCount(10);
    //熔斷策略 - RT模式
    rule.setGrade(RuleConstant.DEGRADE_GRADE_RT);
    //時間窗口 - 3s
    rule.setTimeWindow(3);
    //RT模式下,1秒內(nèi)連續(xù)多少個請求的平均RT超出閾值,才可以觸發(fā)熔斷
    rule.setRtSlowRequestAmount(5);
    rules.add(rule);
    DegradeRuleManager.loadRules(rules);
}

如上代碼,我們定義了熔斷的規(guī)則,屬性的含義見注釋內(nèi)容,然后來看測試用例。

public static void main(String[] args)throws InterruptedException {
    loadDegradeRule(resource);
    while (!stop){
        count.incrementAndGet();
        Entry entry = null;
        try {
            entry = SphU.entry(resource);
            logger.info("業(yè)務(wù)操作...{}",count.get());
            Thread.sleep(15);
        } catch (BlockException e) {
            if (e instanceof DegradeException){
                logger.error("觸發(fā)熔斷機(jī)制...{}",count.get());
                Thread.sleep(500);
            }
        } finally {
            if (entry != null) {
                entry.exit();
            }
            if (count.get()>=20){
                stop = true;
            }
        }
    }
    logger.info("----------------------------");
}

在上面的代碼中,我們一共有20個請求。我們讓線程停頓15ms使平均RT超過閾值,也就是超過10ms。

我們定義的規(guī)則里面是1秒內(nèi)連續(xù)5個請求的平均RT超出閾值,就可以觸發(fā)熔斷,所以當(dāng)?shù)?個請求到達(dá)時,就會觸發(fā)熔斷。

熔斷多久呢?就在3秒的時間窗口。

上面的測試代碼中,在觸發(fā)熔斷之后,我們又手動讓線程停頓了 1000ms ,所以每次熔斷的請求會有3個。

是不是這樣,我們運(yùn)行代碼,看下結(jié)果:

10:56:20.022 [main] INFO orderService - 業(yè)務(wù)操作...1
10:56:20.040 [main] INFO orderService - 業(yè)務(wù)操作...2
10:56:20.056 [main] INFO orderService - 業(yè)務(wù)操作...3
10:56:20.072 [main] INFO orderService - 業(yè)務(wù)操作...4
10:56:20.088 [main] INFO orderService - 業(yè)務(wù)操作...5
10:56:20.127 [main] ERROR orderService - 觸發(fā)熔斷機(jī)制...6
10:56:21.128 [main] ERROR orderService - 觸發(fā)熔斷機(jī)制...7
10:56:22.128 [main] ERROR orderService - 觸發(fā)熔斷機(jī)制...8
10:56:23.129 [main] INFO orderService - 業(yè)務(wù)操作...9
10:56:23.145 [main] INFO orderService - 業(yè)務(wù)操作...10
10:56:23.160 [main] INFO orderService - 業(yè)務(wù)操作...11
10:56:23.176 [main] INFO orderService - 業(yè)務(wù)操作...12
10:56:23.192 [main] INFO orderService - 業(yè)務(wù)操作...13
10:56:23.207 [main] ERROR orderService - 觸發(fā)熔斷機(jī)制...14
10:56:24.208 [main] ERROR orderService - 觸發(fā)熔斷機(jī)制...15
10:56:25.208 [main] ERROR orderService - 觸發(fā)熔斷機(jī)制...16
10:56:26.209 [main] INFO orderService - 業(yè)務(wù)操作...17
10:56:26.224 [main] INFO orderService - 業(yè)務(wù)操作...18
10:56:26.240 [main] INFO orderService - 業(yè)務(wù)操作...19
10:56:26.255 [main] INFO orderService - 業(yè)務(wù)操作...20
10:56:26.271 [main] INFO orderService - ----------------------------

至此,我們就可以說,Sentinel 能夠正常工作了。

二、系統(tǒng)集成

上面只是一個很簡單的Demo示例,如果我們希望在我們的SpringBoot項(xiàng)目中使用Sentinel,還需要一些工作。

1、Sentinel 控制臺

Sentinel 提供一個輕量級的開源控制臺,它是使用SpringBoot開發(fā)的。

它提供機(jī)器發(fā)現(xiàn)以及健康情況管理、監(jiān)控(單機(jī)和集群),規(guī)則管理和推送的功能。

所以,我們先把這個控制臺運(yùn)行起來。

第一步,需要在https://github.com/alibaba/Sentinel/releases這個地址,下載最新版本的控制臺 jar 包。

第二步,使用命令啟動控制臺程序,其中 -Dserver.port=9080 用于指定 Sentinel 控制臺端口。

java -Dserver.port=9080 -Dcsp.sentinel.dashboard.server=localhost:9080 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard.jar

第三步,我們的業(yè)務(wù)系統(tǒng)引入 Transport 模塊來與 Sentinel 控制臺進(jìn)行通信。

<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-transport-simple-http</artifactId>
    <version>1.7.2</version>
</dependency>

第四步,在我們的業(yè)務(wù)系統(tǒng)中,設(shè)置JVM啟動參數(shù),用來指明Sentinel控制臺的地址。

-Dcsp.sentinel.dashboard.server=127.0.0.1:9080

最后,啟動我們的業(yè)務(wù)系統(tǒng),然后打開Sentinel控制臺,如果可以看到機(jī)器列表就可以了。


image

2、定義規(guī)則

在定義規(guī)則之前,我們需要規(guī)劃好資源范圍。

什么意思呢?比如我們拿一個訂單業(yè)務(wù)來說,是不是所有的訂單操作都算一個資源?還是拆分開來看,創(chuàng)建訂單算一個資源,訂單查詢算另外一個資源。

所以,我們可以先把希望流控的資源名稱定義出來。

public final class ResourceConstants {
    public static final String ORDER_SERVICE = OrderService.class.getName();
    public static final String ORDER_SERVICE_ORDERS = ORDER_SERVICE+".orders";
    public static final String ORDER_SERVICE_CREATE = ORDER_SERVICE+".create";
}

由于是一個SpringBoot項(xiàng)目,我們可以在系統(tǒng)啟動的時候,來加載流控規(guī)則。

@Component
public class ApplicationStartup implements ApplicationListener<ContextRefreshedEvent> {
    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        initFlowRule(ResourceConstants.ORDER_SERVICE,5);
        initFlowRule(ResourceConstants.ORDER_SERVICE_ORDERS,5);
    }
    public void initFlowRule(String resourceName,int count) {
        FlowRule flowRule = new FlowRule(resourceName)
                .setCount(count)
                .setGrade(RuleConstant.FLOW_GRADE_QPS);
        List<FlowRule> list = new ArrayList<>();
        list.add(flowRule);
        FlowRuleManager.loadRules(list);
    }
}

然后,我們在Controller加入Sentinel的代碼,來達(dá)到流控的效果。

@RequestMapping("/getOrders")
public ResponseEntity getOrders(){
    Entry entry = null;
    try {
        entry = SphU.entry(ResourceConstants.ORDER_SERVICE_ORDERS);
        return ResponseEntity.ok(orderService.orders());
    } catch (BlockException e) {
        logger.error("請求被限流...{}",e.getRule().getResource());
        return ResponseEntity.badRequest().body(e.getRule());
    } finally {
        if (entry != null) {
            entry.exit();
        }
    }
}

現(xiàn)在,我們拿JMeter來測試一下,啟動10個線程來請求這個接口。只會通過5個請求,拒絕5個請求。

image

至此,我們已經(jīng)可以在SpringBoot項(xiàng)目中簡單使用Sentinel了,不過此時還有兩個很明顯的問題。

  • 在每個需要流控的地方,通過API硬編碼,侵入性太強(qiáng)而且也不方便;
  • 流控規(guī)則只保留在內(nèi)存中,系統(tǒng)重啟就沒了,沒有持久化規(guī)則數(shù)據(jù)。

接下來,我們來解決上述的兩個問題。

三、框架適配

得益于廣泛的開源生態(tài),Sentinel 提供開箱即用的與其它開源框架/庫的整合模塊。我們只需要引入相應(yīng)的依賴并進(jìn)行簡單的配置即可快速地接入 Sentinel。

我們希望可以對 Web 請求進(jìn)行流量控制,那么需要引入Sentinel 提供與 Servlet 的整合。

<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-web-servlet</artifactId>
    <version>1.7.2</version>
</dependency>

1、Filter配置

因?yàn)槭荢pringBoot應(yīng)用,我們通過Configuration進(jìn)行配置。

@Configuration
public class SentinelFilterConfig {
    @Bean
    public FilterRegistrationBean sentinelFilterRegistration() {
        FilterRegistrationBean<Filter> registration = new FilterRegistrationBean<>();
        registration.setFilter(new CommonFilter());
        registration.addUrlPatterns("/*");
        registration.setName("sentinelFilter");
        registration.setOrder(1);
        return registration;
    }
}

在我們自己的業(yè)務(wù)代碼中,就可以免去Sentinel API部分了。

@RequestMapping("/getOrders")
public ResponseEntity getOrders(){
    return ResponseEntity.ok(orderService.orders());
}

在流控規(guī)則不變的情況下,我們拿JMeter啟動10個線程來請求這個接口。同樣的只會通過5個請求,拒絕5個請求。

2、UrlBlockHandler

默認(rèn)情況下,當(dāng)請求被限流時會返回默認(rèn)的提示頁面。

我們可以在代碼中調(diào)用WebServletConfig.setBlockPage(blockPage) 方法設(shè)定自定義的跳轉(zhuǎn) URL,當(dāng)請求被限流時會自動跳轉(zhuǎn)至設(shè)定好的 URL。

如果不打算讓它跳轉(zhuǎn)頁面,我們也可以實(shí)現(xiàn) UrlBlockHandler 接口并編寫定制化的限流處理邏輯。

比如像下面這樣,限流或熔斷之后,會向客戶端返回一個異常的HTTP狀態(tài)碼和提示信息。

public class SentinelUrlBlockHandler implements UrlBlockHandler {

    public static final String flowMsg = "觸發(fā)流控機(jī)制~";
    public static final String degradeMsg = "觸發(fā)熔斷機(jī)制~";
    Logger logger = LoggerFactory.getLogger(this.getClass());

    @Override
    public void blocked(HttpServletRequest request, HttpServletResponse response, BlockException ex){
        logger.error("熔斷限流...{}",ex.getRule());
        response.setCharacterEncoding("UTF-8");
        response.setStatus(HttpStatus.BAD_REQUEST.value());
        PrintWriter out = response.getWriter();
        if (ex instanceof FlowException){
            out.print(flowMsg);
        }else if (ex instanceof DegradeException){
            out.print(degradeMsg);
        }
        out.flush();
        out.close();
    }
}

然后將其注冊至 WebCallbackManager 中。

WebCallbackManager.setUrlBlockHandler(new SentinelUrlBlockHandler());

3、UrlCleaner

Sentinel Web Filter 會將每個到來的不同的 URL 都作為不同的資源處理。

比如訂單業(yè)務(wù)中的,創(chuàng)建訂單、訂單查詢、訂單刪除等等,因?yàn)閁RL的不同,都會被當(dāng)作不同的資源。

如果我們希望將這些操作都?xì)w到訂單資源下/order/*,就需要實(shí)現(xiàn) UrlCleaner 接口清洗一下資源。

比如像下面這樣,將資源歸類。比如/order/getOrders和/order/createOrder,都會變成/order/*。

public class SentinelUrlClean implements UrlCleaner {
    @Override
    public String clean(String originUrl) {
        if (originUrl == null || originUrl.isEmpty()) {
            return originUrl;
        }
        int lastSlashIndex = originUrl.lastIndexOf("/");
        if (lastSlashIndex >= 0) {
            originUrl = originUrl.substring(0, lastSlashIndex) + "/*";
        }
        return originUrl;
    }
}

然后將其注冊至 WebCallbackManager 中。

WebCallbackManager.setUrlCleaner(new SentinelUrlClean());

當(dāng)時,更絕對一些,如果整個系統(tǒng)都采用一個資源,那么這里只返回一個固定的url也可以。

四、最佳實(shí)踐

上面我們說到,現(xiàn)在的Sentinel規(guī)則數(shù)據(jù)都只保留在內(nèi)存中,沒辦法做到集中管理和推送規(guī)則,不具備生產(chǎn)環(huán)境可用性。

規(guī)則管理及推送,一般有三種方式。

  • 原始模式

將規(guī)則推送至客戶端并直接更新到內(nèi)存中。重啟即消失,不建議在生產(chǎn)環(huán)境中使用。

  • Pull 模式

客戶端主動向某個規(guī)則管理中心定期輪詢拉取規(guī)則,這個規(guī)則中心可以是 RDBMS、文件 等。不保證實(shí)時性,拉取過于頻繁可能會導(dǎo)致性能問題。

  • Push 模式

規(guī)則中心統(tǒng)一推送,客戶端通過注冊監(jiān)聽器的方式時刻監(jiān)聽變化,比如使用 Nacos、Zookeeper 等配置中心,有更好的實(shí)時性和一致性。生產(chǎn)環(huán)境下一般采用 push 模式的數(shù)據(jù)源。

生產(chǎn)環(huán)境下一般更常用的是 push 模式的數(shù)據(jù)源。對于 push 模式的數(shù)據(jù)源,如遠(yuǎn)程配置中心(ZooKeeper, Nacos, Apollo等等),推送的操作不應(yīng)由 Sentinel 客戶端進(jìn)行,而應(yīng)該經(jīng)控制臺統(tǒng)一進(jìn)行管理,直接進(jìn)行推送,數(shù)據(jù)源僅負(fù)責(zé)獲取配置中心推送的配置并更新到本地。因此推送規(guī)則正確做法應(yīng)該是 ** 配置中心控制臺/Sentinel 控制臺 → 配置中心 → Sentinel 數(shù)據(jù)源 → Sentinel **,而不是經(jīng) Sentinel 數(shù)據(jù)源推送至配置中心。

接下來我們來實(shí)現(xiàn)由Nacos配置中心統(tǒng)一管理數(shù)據(jù)。

1、啟動Nacos

關(guān)于Nacos本文不再多說,下載一個啟動就好了。

2、引入依賴

NacosDataSource,官方已經(jīng)提供了,我們引入相關(guān)依賴即可。

<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-datasource-extension</artifactId>
    <version>1.7.2</version>
</dependency>
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-datasource-nacos</artifactId>
    <version>1.7.2</version>
</dependency>

3、從數(shù)據(jù)源中讀取規(guī)則數(shù)據(jù)

在初始化NacosDataSource的時候,我們要指定Nacos的服務(wù)地址,groupId和dataId。

然后根據(jù)這些信息連接Nacos,去讀取里面的數(shù)據(jù)。并且注冊監(jiān)聽器,在Nacos配置中心的規(guī)則數(shù)據(jù)發(fā)生變化后,通知到客戶端。

說起來可能比較復(fù)雜,但是作為客戶端使用的話,其實(shí)比較簡單。我們搞一個類,去連接它就可以了。

@Component
public class DataSourceRuleManager {

    private static final String remoteAddress = "localhost:8848";
    private static final String groupId = "sentinel.group";
    private static final String flowDataId = "flow.rule";

    @PostConstruct
    public void loadFlowRules() {
        FlowConverter converter = new FlowConverter();
        //連接Nacos,讀取配置信息并通過converter將內(nèi)容轉(zhuǎn)換為對象
        ReadableDataSource<String, List<FlowRule>> flowRuleDataSource =
                new NacosDataSource<>(remoteAddress,groupId,flowDataId,converter);
        FlowRuleManager.register2Property(flowRuleDataSource.getProperty());
    }
    //轉(zhuǎn)換器 從Nacos配置中心讀取到的數(shù)據(jù)轉(zhuǎn)換為對象
    public class FlowConverter implements Converter {
        @Override
        public Object convert(Object source) {
            return JSON.parseArray(source.toString(),FlowRule.class);
        }
    }
}

配置完之后,我們就可以啟動業(yè)務(wù)系統(tǒng)了。

4、從Nacos配置中心添加規(guī)則數(shù)據(jù)

現(xiàn)在就可以通過Nacos控制臺,向配置中心添加規(guī)則數(shù)據(jù)了。

有一點(diǎn)需要注意的是,由于我們的轉(zhuǎn)換器是通過JSON解析FlowRule類型的數(shù)組對象,所以配置內(nèi)容里面的格式和屬性名稱要對應(yīng)起來,否則解析會失敗。


image

通過擴(kuò)展讀數(shù)據(jù)源的方式,當(dāng)我們在Nacos配置中心發(fā)布新的內(nèi)容后,相應(yīng)的我們業(yè)務(wù)系統(tǒng)里面的規(guī)則也會更新,Sentinel控制臺里面的規(guī)則也一樣會同步更新,就實(shí)現(xiàn)了規(guī)則中心統(tǒng)一推送和持久化。

還有一種方式是直接通過 Sentinel 控制臺 → 配置中心,這樣的話需要修改dashboard的實(shí)現(xiàn),過程雖然不難但比較復(fù)雜,由于篇幅有限,本文就不再贅述。感興趣的朋友可以留言交流~

總結(jié)

本文簡單介紹了分布式系統(tǒng)熔斷、限流組件Sentinel的使用。為了達(dá)到生產(chǎn)環(huán)境的基本可用,包含了 Sentinel 與 Servlet 的整合和規(guī)則中心統(tǒng)一推送和持久化。

本文只是Sentinel生態(tài)中的一小部分,更多內(nèi)容如多種策略的流控和熔斷機(jī)制、黑白名單控制、框架適配、實(shí)現(xiàn)原理等內(nèi)容,有時間后續(xù)分享~

原創(chuàng)不易,客官們點(diǎn)個贊再走嘛,這將是筆者持續(xù)寫作的動力~

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容