Turbine學習筆記

Turbine學習筆記

Turbine原理

Hystrix/stream

在微服務架構中,Hystrix提供的是一種熔斷機制,當分佈式系統中的一個服務出現問題時,Hystrix保證該系統不產生雪崩效應,而能繼續服務。Hystrix爲每一個依賴服務維護一個線程池(或者信號量),當線程池佔滿,該依賴服務將會立即拒絕服務而不是排隊等待。每個依賴服務都被隔離開來,Hystrix 會嚴格控制其對資源的佔用,並在任何失效發生時,執行失敗回退邏輯。簡單來說,Hystrix通過觀察者模式對服務狀態進行監聽,並將監聽信息存儲在Hystrix/stream中,或者更確切的說,對於每一個服務的Hystrix/stream,Hystrix會不斷去監聽該服務,並將監聽信息保存下來。具體原理與實現方式在此不做考慮。具體信息如下:

在這裏插入圖片描述

Hystrix Dashboard

Hystrix Dashboard簡單來說,就是將Hystrix/stream中的信息以儀表盤的信息展示出來,如下:

在這裏插入圖片描述

Turbine概述

Turbine真正做的,就是將每一個(指定)服務的 Hystrix/stream中的狀態信息取出,並集中處理(計算與展示),應該說,它是具有自己獨立的調度的,服務(實例)發現,服務連接,數據聚合,數據輸出,共四個過程。

在這裏插入圖片描述

如上圖:Turbine首先通過***InstanceDiscovery*** 模塊獲取所有的實例信息(定期更新獲取),ConnectionManager***負責連接到實例,連接上實例後,便會有源源不斷的數據流發送給聚合器***Aggregator,之後,再傳送給需要的地方。

Turbine流程

啓動

turbine啓動的時候會調用TurbineInitinit()方法進行初始化

public static void init() {
        /*省略其他·代碼*/
        //調用start()方式,初始化實例發現
        InstanceObservable.getInstance().start(PluginsFactory.getInstanceDiscovery());
    }
public void start(InstanceDiscovery iDiscovery) {
        /*省略其他·代碼*/
        //每隔pollDelayMillis通過producer去拉取一次主機的信息
        timer.schedule(producer, 0, pollDelayMillis.get());
    }
private final TimerTask producer = new TimerTask() {
        @Override
        public void run() {
                /*省略其他·代碼*/
                for(InstanceObserver watcher: observers.values()) {
                    if(currentState.get().hostsUp.size() > 0) {
                        try {
                            //通知InstanceObserver主機是UP狀態
                            //watcher是個InstanceObserver接口的實例化對象
                            watcher.hostsUp(currentState.get().hostsUp);
                        } 
                    }
                }
        }
    };

實際上,Turbine啓動過程中,會啓用以上方法,將所有是UP狀態的實例信息都記錄並交給***ConnectionManager***,由它負責連接實例。

數據聚合

數據聚合主要包含3個部分:

  • TurbineDataMonitor:數據監聽,從實例處獲取指標
  • TurbineDataDispatcher:派發器,將數據聚合後輸出到客戶端或者下游的數據監聽
  • TurbineDataHandler:數據處理

InstanceMonitor實例監聽類中的startMonitor()方法如下:

public void startMonitor() throws Exception {
    /*省略其他·代碼*/
            @Override
            public Void call() throws Exception {
                try {
                    //初始化
                    init();
                    monitorState.set(State.Running);
                    while(monitorState.get() == State.Running) {
                        //實現
                        doWork();
                    }
                }
        });
    }

其中***init()***方法如下:

private void init() throws Exception {
     /*省略其他代碼*/
        HttpGet httpget = new HttpGet(url);
    }

***url***如下:

private InstanceMonitor(/*省略構造函數參數*/) {
    /*省略其他·代碼*/
        this.url = urlClosure.getUrlPath(host);
    }

追本溯源:

/**
         * Replaces any {placeholder} attributes in a url suffix using instance attributes
         *
         * e.x. :{server-port}/hystrix.stream -> :8080/hystrix.stream
         *
         * @param host instance
         * @param url suffix
         * @return replaced url suffix
         */
        private String processAttributeReplacements(Instance host, String url) {
            for (Map.Entry<String, String> attribute : host.getAttributes().entrySet()) {
                String placeholder = "{"+attribute.getKey()+"}";
                if (url.contains(placeholder)) {
                    url = url.replace(placeholder, attribute.getValue());
                }
            }
            return url;
        }

由此可見,init()方法正在的目的是根據實例的指標地址 hystrix.stream(hystrix/stream) 去獲取指標信息。

而在***dowork*** 方法中:

private void doWork() throws Exception {
        /*省略其他·代碼*/
        //向派發器中發送數據
        boolean continueRunning = dispatcher.pushData(getStatsInstance(), list);
    }

數據派發

TurbineDataDispatcher 中,有方法叫做 pushData() 如下:

public boolean pushData(final Instance host, final Collection<K> statsData) {
    /*省略其他·代碼*/
        for (final HandlerQueueTuple<K> tuple : eventHandlers.values()) {
            //HandlerQueueTuple管道中添加數據
            tuple.pushData(statsData);
        }
      return true;
    }

HandlerQueueTuple 管道中的方法 pushData() 方法如下:

public void pushData(K data) {
        /*省略其他·代碼*/
        //往隊列中寫數據
        boolean success = queue.writeEvent(data);
    }

將數據寫進 HandlerQueueTuple 管道中後,需要將他們讀取到客戶端,該部分在方法 dowork() 中實現:

public void doWork() throws Exception {
    /*省略其他·代碼*/
            do {
                //從隊列中讀取事件
                K data = queue.readEvent();
                if (data == null) {
                    numMisses++;
                    if (numMisses > 100) {
                        Thread.sleep(100);
                        numMisses = 0; // reset count so we can try polling again.
                    }
                } else {
                    statsData.add(data);
                    numMisses = 0;
                    stopPolling = true;
                }
            }
            while(!stopPolling);

            try {
                //通過事件處理器將數據輸出到客戶端
                eventHandler.handleData(statsData);
            } catch (Exception e) {
                if(eventHandler.getCriteria().isCritical()) {
                    logger.warn("Could not publish event to event handler for " + eventHandler.getName(), e);
                }
            }
        }
public void handleData(Collection<T> data) {
     /*省略其他·代碼*/
        //寫到stream中
        writeToStream(data);
    }

writeToStream() 方法最終將指標數據響應給瀏覽器。

Turbine使用

添加依賴

<dependency> 
    <groupId>org.springframework.cloud</groupId> 
    <artifactId>spring-cloud-starter-turbine</artifactId> 
</dependency> 
<dependency> 
    <groupId>org.springframework.cloud</groupId> 
    <artifactId>spring-cloud-starter-eureka</artifactId> 
</dependency> 
<dependency> 
    <groupId>org.springframework.boot</groupId> 
    <artifactId>spring-boot-starter-actuator</artifactId> 
</dependency>

配置信息

spring.application.name=hystrix-dashboard-turbine
server.port=8009
turbine.appConfig=hello-service,server-feign,service-ribbon#turbine監控的服務名稱,可以多個
turbine.aggregator.clusterConfig= default 
turbine.clusterNameExpression= new String("default")
eureka.client.service-url.defaultZone=http://localhost:8081/eureka

在服務啓動類上添加如下註解開啓 Turbine:

@SpringBootApplication
@EnableHystrixDashboard
@EnableTurbine

將相應服務啓動,並輸入網址 http://localhost:8009/turbine/stream ,將出現如下界面:

信息查看

在這裏插入圖片描述

說明turbine/stream的本質是獲取多個服務的hystrix/stream

我們打開Dashboard,並在地址欄裏輸入 http://localhost:8009/turbine/stream ,並使用Apache的ab壓力測試工具測試:

在這裏插入圖片描述

結果如上,Hystrix Dashboard Wiki上詳細說明了圖上每個指標的含義,如下圖:

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章