Sentinel 實戰-控制檯篇

逅弈 轉載請註明原創出處,謝謝!java

系列文章

Sentinel 原理-全解析node

Sentinel 原理-調用鏈git

Sentinel 原理-滑動窗口github

Sentinel 原理-實體類web

Sentinel 實戰-限流篇spring

Sentinel 實戰-規則持久化瀏覽器

經過 Sentinel 的控制檯,咱們能夠對規則進行查詢和修改,也能夠查看到實時監控,機器列表等信息,因此咱們須要對 sentinel 的控制檯作個完整的瞭解。bash

部署控制檯

首先須要啓動控制檯, sentinel 的控制檯是用 spring boot 寫的一個web 應用,咱們有幾種方式來獲取控制檯:app

下載可執行 jar 包

release 頁面 下載截止目前爲止最新版本的控制檯 jar 包,以下圖所示:curl

sentinel-dashboard-release-jar-1.png

下載源碼構建

除了能夠下載預先構建好的可執行 jar 包以外,咱們還能夠把控制檯的工程下載下來自行用源碼構建,sentinel 是一個多 maven 模塊的項目,控制檯是其中的一個項目,以下圖所示:

sentinel-dashboard-module-1.png

如上圖所示,咱們能夠下載完整的 sentinel 的項目,而後構建其中的 sentinel-dashboard 模塊,也能夠只下載 sentinel-dashboard 模塊而後構建。

這裏我選擇將完整的 sentinel 工程下載下來,而後構建 sentinel-dashboard 模塊,首先在項目根目錄下執行:

cd sentinel-dashboard
複製代碼

將會進入 dashboard 模塊,而後在 dashboard 目錄下執行:

mvn clean package
複製代碼

maven將會把 sentinel-dashboard 模塊打包成一個可執行的 fat jar包,以下圖所示:

sentinel-dashboard-module-2.png

sentinel-dashboard-module-3.png

啓動控制檯

構建成功後,就能夠啓動控制檯了,執行如下命令:

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

其中 -Dserver.port=8080 用於指定 Sentinel 控制檯端口爲 8080

執行完以後,你將看到以下信息:

sentinel-dashboard-start-1.png

sentinel-dashboard-start-2.png

當看到 Started DashboardApplication in xx seconds 時,說明你的控制檯已經啓動成功了,訪問 http://localhost:8080/ 就能夠看到控制檯的樣子了,以下圖所示:

sentinel-dashboard-1.png

能夠看到當前控制檯中沒有任何的應用,由於尚未應用接入。

接入控制檯

要想在控制檯中操做咱們的應用,除了須要部署一個控制檯的服務外,還須要將咱們的應用接入到控制檯中去。

引入 transport 依賴

首先須要在咱們使用 sentinel 的服務中引入 sentinel-transport 的依賴,由於咱們的應用是做爲客戶端,經過transport模塊與控制檯進行通信的,依賴以下所示:

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

版本依然選擇最新的 1.4.0

配置應用啓動參數

引入了依賴以後,接着就是在咱們的應用中配置 JVM 啓動參數,以下所示:

-Dproject.name=xxx -Dcsp.sentinel.dashboard.server=consoleIp:port
複製代碼

其中的consoleIp和port對應的就是咱們部署的 sentinel dashboard 的ip和port,我這裏對應的是 127.0.0.1 和 8080,按照實際狀況來配置 dashboard 的ip和port就行了,以下圖所示:

sentinel-connection-properties.png

從圖中能夠看到我設置的客戶端的應用名爲:lememo,當客戶端鏈接上控制檯後,會顯示該應用名。

PS:須要注意的是,除了可經過 JVM -D 參數指定以外,也可經過 properties 文件指定,配置文件的路徑爲 ${user_home}/logs/csp/${project.name}.properties

配置文件中參數的key和類型以下所示:

sentinel-dashboard-properties.png

優先級順序:JVM -D 參數的優先級最高,若 properties 文件和 JVM 參數中有相同項的配置,以 JVM -D 參數配置的爲準。

觸發客戶端鏈接控制檯

客戶端配置好了與控制檯的鏈接參數以後,並不會主動鏈接上控制檯,須要觸發一次客戶端的規則纔會開始進行初始化,並向控制檯發送心跳和客戶端規則等信息。

客戶端與控制檯的鏈接初始化是在 Env 的類中觸發的,即下面代碼中的 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();
    }
}
複製代碼

埋點

上篇文章中咱們建立了一個 UserService 來作驗證,正常時會返回一個用戶對象,被限流時返回一個null,可是這樣不太直觀,本篇文章我換一個更簡單和直觀的驗證方式,代碼以下所示:

@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:這裏有個須要注意的知識點,就是 SphU.entry 方法的第二個參數 EntryType 說的是此次請求的流量類型,共有兩種類型:IN 和 OUT 。

IN:是指進入咱們系統的入口流量,好比 http 請求或者是其餘的 rpc 之類的請求。

OUT:是指咱們系統調用其餘第三方服務的出口流量。

入口、出口流量只有在配置了系統規則時纔有效。

設置 Type 爲 IN 是爲了統計整個系統的流量水平,防止系統被打垮,用以自我保護的一種方式。

設置 Type 爲 OUT 一方面是爲了保護第三方系統,好比咱們系統依賴了一個生成訂單號的接口,而這個接口是核心服務,若是咱們的服務是非核心應用的話須要對他進行限流保護;另外一方面也能夠保護本身的系統,假設咱們的服務是核心應用,而依賴的第三方應用總是超時,那這時能夠經過設置依賴的服務的 rt 來進行降級,這樣就不至於讓第三方服務把咱們的系統拖垮。

下圖描述了流量的類型和系統之間的關係:

sentinel-entry-type.png

鏈接控制檯

應用接入 transport 模塊以後,咱們主動來訪問一次 /testSentinel 接口,順利的話,客戶端會主動鏈接上控制檯,並將本身的ip等信息發送給控制檯,而且會與控制檯維持一個心跳。

如今咱們在來訪問下控制檯,看到客戶端已經鏈接上來了,以下圖所示:

sentinel-dashboard-2.png

客戶端鏈接上dashboard以後,咱們就能夠爲咱們定義的資源配置規則了,有兩種方式能夠配置規則:

  • 在【流控規則】頁面中新增
  • 在【簇點鏈路】中添加

咱們能夠在【流控規則】頁面中新增,點擊【流控規則】進入頁面,以下圖所示:

sentinel-add-flow-rule-1.png

在彈出框中,填寫資源名和單機閾值,其餘的屬性保持默認設置便可,以下圖所示:

sentinel-add-flow-rule-2.png

點擊【新增】後,規則即生效了。

第二種方式就是在【簇點鏈路】的頁面中找到咱們埋點的資源名,而後直接對該資源進行增長流控規則的操做,以下圖所示:

sentinel-add-flow-rule-3.png

上圖中右側的【+流控】的按鈕點擊後,彈出框與直接新增規則是同樣的,只是會自動將資源名填充進去,省去了咱們設置的這一步。

驗證效果

規則建立完成以後,咱們就能夠在【流控規則】頁面查詢到了,以下圖所示:

sentinel-flow-rule-list.png

接着咱們就能夠來驗證效果了,讓咱們在瀏覽器中快速的刷新來請求 /testSentinel 這個接口,不出意外,應該會看到以下圖所示的狀況:

sentinel-flow-rule-effect-1.png

說明咱們設置的流控規則生效了,請求被 block 了。

如今咱們再到控制檯的【實時監控】頁面查詢下,剛剛咱們的一頓瘋狂請求應該有不少都被 block 了,經過的 qps 應該維持在2如下,以下圖所示:

sentinel-flow-rule-effect-2.png

原理

咱們知道 sentinel 的核心就是圍繞着幾件事:資源的定義,規則的配置,代碼中埋點。

並且這些事在 sentinel-core 中都有能力實現,也對外暴露了相應的 http 接口方便咱們查看 sentinel 中的相關數據。

CommandCenter

sentinel-core 在第一次規則被觸發的時候,啓動了一個 CommandCenter,也就是咱們引入的 sentinel-transport-simple-http 依賴中被引入的實現類:SimpleHttpCommandCenter。

這個 SimpleHttpCommandCenter 類中啓動了兩個線程池:主線程池和業務線程池。

主線程池啓動了一個 ServerSocket 來監聽默認的 8719 端口,若是端口被佔用,會自動嘗試獲取下一個端口,嘗試3次。

業務線程池主要是用來處理 ServerSocket 接收到的數據。

將不重要的代碼省略掉以後,具體的代碼以下所示:

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() {
	        	// 獲取可用的端口用以建立一個ServerSocket
	            ServerSocket serverSocket = getServerSocketFromBasePort(port);
	            if (serverSocket != null) {
	            	// 在主線程中啓動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中由業務線程去處理
                    HttpEventTask eventTask = new HttpEventTask(socket);
                    bizExecutor.submit(eventTask);
                } catch (Exception e) {
                    // 省略部分代碼
                }
            }
        }
    }
}
複製代碼

具體的狀況以下圖所示:

command-center.png

HTTP接口

SimpleHttpCommandCenter 啓動了一個 ServerSocket 來監聽8719端口,也對外提供了一些 http 接口用以操做 sentinel-core 中的數據,包括查詢|更改規則,查詢節點狀態等。

PS:控制檯也是經過這些接口與 sentinel-core 進行數據交互的!

提供這些服務的是一些 CommandHandler 的實現類,每一個類提供了一種能力,這些類是在 sentinel-transport-common 依賴中提供的,以下圖所示:

command-handler.png

查詢規則

運行下面命令,則會返回現有生效的規則:

curl http://localhost:8719/getRules?type=<XXXX>
複製代碼

其中,type有如下取值:

  • flow 以 JSON 格式返回現有的限流規則;
  • degrade 則返回現有生效的降級規則列表;
  • system 則返回系統保護規則。

更改規則

同時也能夠經過下面命令來修改已有規則:

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

其中,type 能夠輸入 flowdegrade 等方式來制定更改的規則種類,data 則是對應的 JSON 格式的規則。

其餘的接口再也不一一詳細舉例了,有須要的你們能夠自行查看源碼瞭解。

更多原創好文,請關注「逅弈逐碼」

更多原創好文,請關注公衆號「逅弈逐碼」

相關文章
相關標籤/搜索