Sentinel 實(shí)戰(zhàn)-控制臺(tái)篇

逅弈 轉(zhuǎn)載請注明原創(chuàng)出處,謝謝!

系列文章

Sentinel 原理-全解析
Sentinel 原理-調(diào)用鏈
Sentinel 原理-滑動(dòng)窗口
Sentinel 原理-實(shí)體類
Sentinel 實(shí)戰(zhàn)-限流篇
Sentinel 實(shí)戰(zhàn)-控制臺(tái)篇
Sentinel 實(shí)戰(zhàn)-規(guī)則持久化
Sentinel 實(shí)戰(zhàn)-集群限流篇

Sentinel 系列教程,現(xiàn)已上傳到 github 和 gitee 中:

sentinel-tutorial.png

通過 Sentinel 的控制臺(tái),我們可以對(duì)規(guī)則進(jìn)行查詢和修改,也可以查看到實(shí)時(shí)監(jiān)控,機(jī)器列表等信息,所以我們需要對(duì) sentinel 的控制臺(tái)做個(gè)完整的了解。

部署控制臺(tái)

首先需要啟動(dòng)控制臺(tái), sentinel 的控制臺(tái)是用 spring boot 寫的一個(gè)web 應(yīng)用,我們有幾種方式來獲取控制臺(tái):

下載可執(zhí)行 jar 包

release 頁面 下載截止目前為止最新版本的控制臺(tái) jar 包,如下圖所示:

sentinel-dashboard-release-jar-1.png

下載源碼構(gòu)建

除了可以下載預(yù)先構(gòu)建好的可執(zhí)行 jar 包之外,我們還可以把控制臺(tái)的工程下載下來自行用源碼構(gòu)建,sentinel 是一個(gè)多 maven 模塊的項(xiàng)目,控制臺(tái)是其中的一個(gè)項(xiàng)目,如下圖所示:

sentinel-dashboard-module-1.png

如上圖所示,我們可以下載完整的 sentinel 的項(xiàng)目,然后構(gòu)建其中的 sentinel-dashboard 模塊,也可以只下載 sentinel-dashboard 模塊然后構(gòu)建。

這里我選擇將完整的 sentinel 工程下載下來,然后構(gòu)建 sentinel-dashboard 模塊,首先在項(xiàng)目根目錄下執(zhí)行:

cd sentinel-dashboard

將會(huì)進(jìn)入 dashboard 模塊,然后在 dashboard 目錄下執(zhí)行:

mvn clean package

maven將會(huì)把 sentinel-dashboard 模塊打包成一個(gè)可執(zhí)行的 fat jar包,如下圖所示:

sentinel-dashboard-module-2.png
sentinel-dashboard-module-3.png

啟動(dòng)控制臺(tái)

構(gòu)建成功后,就可以啟動(dòng)控制臺(tái)了,執(zhí)行以下命令:

java -Dserver.port=8080 \
-Dcsp.sentinel.dashboard.server=localhost:8080 \
-jar target/sentinel-dashboard.jar

其中 -Dserver.port=8080 用于指定 Sentinel 控制臺(tái)端口為 8080

執(zhí)行完之后,你將看到如下信息:

sentinel-dashboard-start-1.png
sentinel-dashboard-start-2.png

當(dāng)看到 Started DashboardApplication in xx seconds 時(shí),說明你的控制臺(tái)已經(jīng)啟動(dòng)成功了,訪問 http://localhost:8080/ 就可以看到控制臺(tái)的樣子了,如下圖所示:

sentinel-dashboard-1.png

可以看到當(dāng)前控制臺(tái)中沒有任何的應(yīng)用,因?yàn)檫€沒有應(yīng)用接入。

接入控制臺(tái)

要想在控制臺(tái)中操作我們的應(yīng)用,除了需要部署一個(gè)控制臺(tái)的服務(wù)外,還需要將我們的應(yīng)用接入到控制臺(tái)中去。

引入 transport 依賴

首先需要在我們使用 sentinel 的服務(wù)中引入 sentinel-transport 的依賴,因?yàn)槲覀兊膽?yīng)用是作為客戶端,通過transport模塊與控制臺(tái)進(jìn)行通訊的,依賴如下所示:

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

版本依然選擇最新的 1.4.0

配置應(yīng)用啟動(dòng)參數(shù)

引入了依賴之后,接著就是在我們的應(yīng)用中配置 JVM 啟動(dòng)參數(shù),如下所示:

-Dproject.name=xxx -Dcsp.sentinel.dashboard.server=consoleIp:port

其中的consoleIp和port對(duì)應(yīng)的就是我們部署的 sentinel dashboard 的ip和port,我這里對(duì)應(yīng)的是 127.0.0.1 和 8080,按照實(shí)際情況來配置 dashboard 的ip和port就好了,如下圖所示:

sentinel-connection-properties.png

從圖中可以看到我設(shè)置的客戶端的應(yīng)用名為:lememo,當(dāng)客戶端連接上控制臺(tái)后,會(huì)顯示該應(yīng)用名。

PS:需要注意的是,除了可通過 JVM -D 參數(shù)指定之外,也可通過 properties 文件指定,配置文件的路徑為 ${user_home}/logs/csp/${project.name}.properties。

配置文件中參數(shù)的key和類型如下所示:

sentinel-dashboard-properties.png

優(yōu)先級(jí)順序:JVM -D 參數(shù)的優(yōu)先級(jí)最高,若 properties 文件和 JVM 參數(shù)中有相同項(xiàng)的配置,以 JVM -D 參數(shù)配置的為準(zhǔn)。

觸發(fā)客戶端連接控制臺(tái)

客戶端配置好了與控制臺(tái)的連接參數(shù)之后,并不會(huì)主動(dòng)連接上控制臺(tái),需要觸發(fā)一次客戶端的規(guī)則才會(huì)開始進(jìn)行初始化,并向控制臺(tái)發(fā)送心跳和客戶端規(guī)則等信息。

客戶端與控制臺(tái)的連接初始化是在 Env 的類中觸發(fā)的,即下面代碼中的 InitExecutor.doInit();

public class Env {
    public static final NodeBuilder nodeBuilder = new DefaultNodeBuilder();
    public static final Sph sph = new CtSph();

    static {
        // If init fails, the process will exit.
        InitExecutor.doInit();
    }
}

埋點(diǎn)

上篇文章中我們創(chuàng)建了一個(gè) UserService 來做驗(yàn)證,正常時(shí)會(huì)返回一個(gè)用戶對(duì)象,被限流時(shí)返回一個(gè)null,但是這樣不太直觀,本篇文章我換一個(gè)更簡單和直觀的驗(yàn)證方式,代碼如下所示:

@GetMapping("/testSentinel")
public @ResponseBody
String testSentinel() {
    String resourceName = "testSentinel";
    Entry entry = null;
    String retVal;
    try{
        entry = SphU.entry(resourceName,EntryType.IN);
        retVal = "passed";
    }catch(BlockException e){
        retVal = "blocked";
    }finally {
        if(entry!=null){
            entry.exit();
        }
    }
    return retVal;
}

PS:這里有個(gè)需要注意的知識(shí)點(diǎn),就是 SphU.entry 方法的第二個(gè)參數(shù) EntryType 說的是這次請求的流量類型,共有兩種類型:IN 和 OUT 。

IN:是指進(jìn)入我們系統(tǒng)的入口流量,比如 http 請求或者是其他的 rpc 之類的請求。

OUT:是指我們系統(tǒng)調(diào)用其他第三方服務(wù)的出口流量。

入口、出口流量只有在配置了系統(tǒng)規(guī)則時(shí)才有效。

設(shè)置 Type 為 IN 是為了統(tǒng)計(jì)整個(gè)系統(tǒng)的流量水平,防止系統(tǒng)被打垮,用以自我保護(hù)的一種方式。

設(shè)置 Type 為 OUT 一方面是為了保護(hù)第三方系統(tǒng),比如我們系統(tǒng)依賴了一個(gè)生成訂單號(hào)的接口,而這個(gè)接口是核心服務(wù),如果我們的服務(wù)是非核心應(yīng)用的話需要對(duì)他進(jìn)行限流保護(hù);另一方面也可以保護(hù)自己的系統(tǒng),假設(shè)我們的服務(wù)是核心應(yīng)用,而依賴的第三方應(yīng)用老是超時(shí),那這時(shí)可以通過設(shè)置依賴的服務(wù)的 rt 來進(jìn)行降級(jí),這樣就不至于讓第三方服務(wù)把我們的系統(tǒng)拖垮。

下圖描述了流量的類型和系統(tǒng)之間的關(guān)系:

sentinel-entry-type.png

連接控制臺(tái)

應(yīng)用接入 transport 模塊之后,我們主動(dòng)來訪問一次 /testSentinel 接口,順利的話,客戶端會(huì)主動(dòng)連接上控制臺(tái),并將自己的ip等信息發(fā)送給控制臺(tái),并且會(huì)與控制臺(tái)維持一個(gè)心跳。

現(xiàn)在我們在來訪問下控制臺(tái),看到客戶端已經(jīng)連接上來了,如下圖所示:

sentinel-dashboard-2.png

客戶端連接上dashboard之后,我們就可以為我們定義的資源配置規(guī)則了,有兩種方式可以配置規(guī)則:

  • 在【流控規(guī)則】頁面中新增
  • 在【簇點(diǎn)鏈路】中添加

我們可以在【流控規(guī)則】頁面中新增,點(diǎn)擊【流控規(guī)則】進(jìn)入頁面,如下圖所示:

sentinel-add-flow-rule-1.png

在彈出框中,填寫資源名和單機(jī)閾值,其他的屬性保持默認(rèn)設(shè)置即可,如下圖所示:

sentinel-add-flow-rule-2.png

點(diǎn)擊【新增】后,規(guī)則即生效了。

第二種方式就是在【簇點(diǎn)鏈路】的頁面中找到我們埋點(diǎn)的資源名,然后直接對(duì)該資源進(jìn)行增加流控規(guī)則的操作,如下圖所示:

sentinel-add-flow-rule-3.png

上圖中右側(cè)的【+流控】的按鈕點(diǎn)擊后,彈出框與直接新增規(guī)則是一樣的,只是會(huì)自動(dòng)將資源名填充進(jìn)去,省去了我們設(shè)置的這一步。

驗(yàn)證效果

規(guī)則創(chuàng)建完成之后,我們就可以在【流控規(guī)則】頁面查詢到了,如下圖所示:

sentinel-flow-rule-list.png

接著我們就可以來驗(yàn)證效果了,讓我們在瀏覽器中快速的刷新來請求 /testSentinel 這個(gè)接口,不出意外,應(yīng)該會(huì)看到如下圖所示的情況:

sentinel-flow-rule-effect-1.png

說明我們設(shè)置的流控規(guī)則生效了,請求被 block 了。

現(xiàn)在我們再到控制臺(tái)的【實(shí)時(shí)監(jiān)控】頁面查詢下,剛剛我們的一頓瘋狂請求應(yīng)該有很多都被 block 了,通過的 qps 應(yīng)該維持在2以下,如下圖所示:

sentinel-flow-rule-effect-2.png

原理

我們知道 sentinel 的核心就是圍繞著幾件事:資源的定義,規(guī)則的配置,代碼中埋點(diǎn)。

而且這些事在 sentinel-core 中都有能力實(shí)現(xiàn),也對(duì)外暴露了相應(yīng)的 http 接口方便我們查看 sentinel 中的相關(guān)數(shù)據(jù)。

CommandCenter

sentinel-core 在第一次規(guī)則被觸發(fā)的時(shí)候,啟動(dòng)了一個(gè) CommandCenter,也就是我們引入的 sentinel-transport-simple-http 依賴中被引入的實(shí)現(xiàn)類:SimpleHttpCommandCenter。

這個(gè) SimpleHttpCommandCenter 類中啟動(dòng)了兩個(gè)線程池:主線程池和業(yè)務(wù)線程池。

主線程池啟動(dòng)了一個(gè) ServerSocket 來監(jiān)聽默認(rèn)的 8719 端口,如果端口被占用,會(huì)自動(dòng)嘗試獲取下一個(gè)端口,嘗試3次。

業(yè)務(wù)線程池主要是用來處理 ServerSocket 接收到的數(shù)據(jù)。

將不重要的代碼省略掉之后,具體的代碼如下所示:

public class SimpleHttpCommandCenter implements CommandCenter {
    // 省略初始化
    private ExecutorService executor;
    private ExecutorService bizExecutor;

    @Override
    public void start() throws Exception {

        Runnable serverInitTask = new Runnable() {
            int port;
            {
                try {
                    port = Integer.parseInt(TransportConfig.getPort());
                } catch (Exception e) {
                    port = DEFAULT_PORT;
                }
            }

            @Override
            public void run() {
                // 獲取可用的端口用以創(chuàng)建一個(gè)ServerSocket
                ServerSocket serverSocket = getServerSocketFromBasePort(port);
                if (serverSocket != null) {
                    // 在主線程中啟動(dòng)ServerThread用以接收socket請求
                    executor.submit(new ServerThread(serverSocket));
                    // 省略部分代碼
                } else {
                    CommandCenterLog.info("[CommandCenter] chooses port fail, http command center will not work");
                }
                executor.shutdown();
            }
        };
        new Thread(serverInitTask).start();
    }

    class ServerThread extends Thread {
        private ServerSocket serverSocket;

        ServerThread(ServerSocket s) {
            this.serverSocket = s;
        }

        @Override
        public void run() {
            while (true) {
                Socket socket = null;
                try {
                    socket = this.serverSocket.accept();
                    setSocketSoTimeout(socket);
                    // 將接收到的socket封裝到HttpEventTask中由業(yè)務(wù)線程去處理
                    HttpEventTask eventTask = new HttpEventTask(socket);
                    bizExecutor.submit(eventTask);
                } catch (Exception e) {
                    // 省略部分代碼
                }
            }
        }
    }
}

具體的情況如下圖所示:

command-center.png

HTTP接口

SimpleHttpCommandCenter 啟動(dòng)了一個(gè) ServerSocket 來監(jiān)聽8719端口,也對(duì)外提供了一些 http 接口用以操作 sentinel-core 中的數(shù)據(jù),包括查詢|更改規(guī)則,查詢節(jié)點(diǎn)狀態(tài)等。

PS:控制臺(tái)也是通過這些接口與 sentinel-core 進(jìn)行數(shù)據(jù)交互的!

提供這些服務(wù)的是一些 CommandHandler 的實(shí)現(xiàn)類,每個(gè)類提供了一種能力,這些類是在 sentinel-transport-common 依賴中提供的,如下圖所示:

command-handler.png

查詢規(guī)則

運(yùn)行下面命令,則會(huì)返回現(xiàn)有生效的規(guī)則:

curl http://localhost:8719/getRules?type=<XXXX>

其中,type有以下取值:

  • flow 以 JSON 格式返回現(xiàn)有的限流規(guī)則;
  • degrade 則返回現(xiàn)有生效的降級(jí)規(guī)則列表;
  • system 則返回系統(tǒng)保護(hù)規(guī)則。

更改規(guī)則

同時(shí)也可以通過下面命令來修改已有規(guī)則:

curl http://localhost:8719/setRules?type=<XXXX>&data=<DATA>

其中,type 可以輸入 flowdegrade 等方式來制定更改的規(guī)則種類,data 則是對(duì)應(yīng)的 JSON 格式的規(guī)則。

其他的接口不再一一詳細(xì)舉例了,有需要的大家可以自行查看源碼了解。

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

相關(guān)閱讀更多精彩內(nèi)容

  • 1.概述 Sentinel(哨崗、哨兵)是Redis高可用性的解決方案:由一個(gè)或多個(gè)Sentinel實(shí)例組成的Se...
    孤塵F閱讀 905評(píng)論 0 0
  • 今天我讀完了一本暢銷小說,它的名字叫《一個(gè)叫歐維的男人決定去死》。讀暢銷小說的感覺是這樣的,讀的過程很順暢,某些段...
    墨上秋閱讀 384評(píng)論 0 1
  • 在一般的餐館從事服務(wù)員工資都不是很高,有時(shí)候客人多了做不好還會(huì)被罵。每個(gè)月原本就不多的薪水,如果遇上一個(gè)黑心的老板...
    言炎之談閱讀 403評(píng)論 0 0
  • 學(xué)習(xí)地址 Git設(shè)計(jì)優(yōu)秀之處 跟蹤管理修改,而非文件 丟棄修改的內(nèi)容 改亂了工作區(qū)的文件,要直接丟棄$ git c...
    fangmusan閱讀 271評(píng)論 0 0

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