hystrix問題 小總結 及 網絡相關知識點

1.關於網絡,在分佈式系統中,底層的網絡通訊皆爲 asynchronous communication,需要 看 操作系統 & unix 網絡編程 

書籍 Richard Stevens 的 “UNIX® Network Programming Volume 1, Third Edition: The Sockets Networking ”,

6.2節“I/O Models ”

spark 2.0 通信層不適用 akka 轉爲 netty,

tomcat 爲什麼不用 Netty作成 non-blocking event-driven 容器。想像tomcat沒有servlet規範就知道了。servlet規範 解耦了 處理請求的類 以及 處理業務的類,通過servlet接口以及servlet容器把兩者分工明確。也就是 connector和 container,推薦書籍 how tomcat works,這本後續章節沒細看,再深入一下container部分講解會更佳。

說個問題:hystrix熔斷功能,tomcat-1執行 hystrixCommand.initilizeContext()後,在hystrix-smsv1-1線程調用restTemplate調第三方服務,熔斷超時時間爲 3秒,調用第三方服務偶爾會超3秒導致走熔斷邏輯,也就是 hystrix-timer-1線程執行 fallback方法去調 另一個降級的服務,但在第四秒或者第八秒(因爲生產日誌出現的這兩個時間間隔)結果返回了,那麼本次調用的最終返回結果是熔斷線程hystirx-timer-1的結果,但是還是會走完hystrix-smsv1-1 process的邏輯代碼,此時,hystrix-smsv1-1在執行 hystirxVariable的時候出現了 HystrixCommand.initializeContext() should executed before invoke hystrixVariable.get() 的報錯,按道理之前tomcat-1 中 已經初始化了上下文,並傳遞給了hystrix-smsv1-1(我debug過)

在線程切換中會不會就是導致了hystrix那個bug,問題的關鍵 到底這個線程是什麼時候生成的?如何調度的?這個需要研究一下 Rxjava的理解以及使用。導致了走了熔斷後, 原線程返回結果在同名線程接受時,報錯爲 HystrixCommand.initializeContext() should executed before invoke hystrixVariable.get()的異常信息。這裏的報錯應該是出在 Rxjava框架在 監聽時,切換線程的時間消耗導致了 原線程的銷燬或者作了操作,沒有 了上下文,到底這裏的上下文是哪種原因(1.原線程死了,2.原線程沒死,上下文沒了)此處作記錄,等解決了這個問題後,貼出答覆。

================================================================================================

以下內容編輯於 2019.11.18 16:36

問題已經定位,並且解決。

問題的原因在於hystrix調用超時走了fallback以後,fallback的方法在10ms以內將結果返回給了client,導致這個請求的上下文全部清除,再過1秒,第三方的結果返回了,然後從阻塞的地方繼續執行,則 HystrixRequestVariableDefault.get()-> HystrixRequestContext.getContextForCurrentThread() 時,就返回 上下文沒有初始化的異常報錯。所以將 HystrixRequestVariableDefault.get()提前就可以完美解決這個兼容正常走和超時走 這兩種情況。ok這裏拓展下熔斷的基本流程,或者官方文檔

1.正常請求訪問調用 @HystrixCommand註解修飾的方法

2.出現 timeout/exception/自定義的異常結果 時,走熔斷,藉助 RxJava.jar可以打斷點 在 兩個地方

 第一個地方 com.netflix.hystrix.HystrixCommand
protected final Observable<R> getExecutionObservable() {
        return Observable.defer(new Func0<Observable<R>>() {
            public Observable<R> call() {
                try {
                    return Observable.just(HystrixCommand.this.run());
                } catch (Throwable var2) {
                    return Observable.error(var2);
                }
            }
        }).doOnSubscribe(new Action0() {
            public void call() {
                // add break point here,u can pass this point after waiting for 3-4 seconds
                HystrixCommand.this.executionThread.set(Thread.currentThread());
            }
        });
    }

     第二個地方 com.netflix.hystrix.HystrixCommand

protected final Observable<R> getFallbackObservable() {
        return Observable.defer(new Func0<Observable<R>>() {
            public Observable<R> call() {
                try {
            // add break point here, u can pass this point after waiting for 3-4 seconds
                    return Observable.just(HystrixCommand.this.getFallback());
                } catch (Throwable var2) {
                    return Observable.error(var2);
                }
            }
        });
    }

這兩個地方打斷點之後,走到第一個斷點 你 停 2-3秒執行,在第二個斷點等 2-3秒執行,就會出現那個問題。但是那個問題的最本質原因是fallback結果返回了導致上下文清空。

3.在1分鐘內出現兩次異常時,直接走熔斷,不走原來的方法。

4.再過30秒,出現會嘗試放開部分請求去訪問第三方地址 ,如果還是失敗則還是走fallback。

5.直到訪問第三方地址正常之後,才關閉 circurt broker.

附帶上 我之前梳理的 報錯的流程:

1. client請求 gateway/sms/v2 接口 tomcat線程池 按照serlvet規範 分配一個線程 tomcat-1處理該 request,在 filter 初始化了HystrixRequestContext
2. 進入hystrixCommand註解修飾的方法,hystrix線程池 分配線程id爲 sms-v2-1 的線程處理,調用 第三方服務,此時超時3秒,走熔斷邏輯
3. 由於走熔斷邏輯 hystrix-core.jar 依賴 RxJava.jar的觀察者模式以及異步特性,此時 創建線程id爲 hystrix-timer-1的線程走 fallback方法調我測的hbase服務,由於hbase服務的響應只需 300ms左右,整個觀察鏈將這個結果返回給 client。此時整個觀察鏈結束,銷燬父子線程的上下文。
4. 又過了1秒 返回結果到時已經沒有上下文了,雖然接收的線程id是同一個,但是這只是在併發量不大,沒有競爭條件時 OS 線程調度算法 擇 最近使用的一個線程去處理這個結果罷了。

 

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