Thrift問題集合,打算用Thrift作為生產工具的先看看這個


1.因為本文會不斷更新,所以建議大家去博客看最新版。本文出自cnBlogs的xxxteam,那些無節操的轉載,請注明。

 

2.Thrift的定位

    Thrift僅僅是一個方便的、高性能的通信中間件,它並不是真正意義上的web Server 或 web service server,因為它沒有面對復雜網絡環境的功能與能力,所以,它只能在系統內部的高速的、優良的網絡環境下使用。

    用大白話說,那就是,不要把Thrift當IIS或apache來放在公網直接給用戶提供服務,因為它面對7 * 24的不間斷服務來書,並不穩定。在0.9.0版本,我這邊的thrift服務,用戶1w多一點點,平均好幾秒才1次請求,thrift C# server 已經是平均1個小時崩潰一次。還有幾位朋友的情況,崩潰的更厲害。

 

3.Thrift是RPC,不是具有雙向通信能力的socket-tcp長連接。

    這一點是針對新手來說的。socket-tcp長連接,在連接建立后,雙方都可以向另一方發信息,並且連接可以保持很久。但Thrift不同,雖然Thrift也基於tcp,不過在應用層,它僅僅是一個rpc,遵守rpc模型。rpc模型的運作方式與http很像:客戶端向服務端發起連接並請求數據 -> 服務端返回數據 -> 連接斷開。因此,rpc模型僅僅只適合 一次性的、單向的通信。需要多次的(持久的)、雙向通信的朋友,還是老老實實的用socket-tcp把。

    但是,這里提出一個問題。首先,tcp並不是真正的長連接。因為,要保持連接,需要從一端向另一端,不斷地發送詢問數據包。tcp協議自動做了這件事,不過它的時間太長了,幾個小時才發送一次。也就是說,如果使用tcp連接上去后,對方在幾分鍾內就異常掉線,並且這段時間內沒有顯式的數據傳輸,那么tcp有可能在最壞情況下,幾個小時后才發現對方掉線。因此,真正的長連接,是需要自己手工去發心跳包的。多久發一次?半秒?一秒?10秒?這些需要由自己控制。到這一步,問題就簡單明了了:使用輪詢機制,不斷詢問服務器有無數據。有就取下來。這個流程實際上是模擬了心跳包的機制,並且這個流程是高可控的,因此推薦這個做法。並且,使用tcp長連接的,基本上是想用這種方式來逃避nat造成的單向連接問題。所以這種方案就更合適了。

 

4.Thrift非常不穩定

    截止到目前,Thrift的版本才是0.9.1,而且開發進度緩慢,幾乎一年才更新0.1個版本。由於thrift這個項目非常大,涉及語言非常多,因此它本身的復雜度就非常高,已經遠遠超出apace的其他項目。其次,因為thrift是開源的,開源具有無責任性,以及不負責任性,同時,apache這個機構本身的人手不足,水平不夠,導致Thrift內部漏洞百出,各種不穩定現象。雖然Thrift非常方便,但鑒於它的不穩定,本人給兩個建議:

    4.1 僅僅把Thrift用於允許丟失數據,允許較長宕機時間(至少10秒鍾以上)的非核心業務。

    4.2 使用了Thrift的朋友,一定要在運行Thrift的服務器上,為它做一個看門狗服務。看門狗是一種產品類型,它的作用是監控主體程序,如果主體程序發生故障,則看門狗會殺死該程序,然后重啟這個程序。流程也很簡單:

        4.2.1 循環開始位置:

        4.2.2 開門狗訪問ThriftServer的某個服務

        4.2.3 如果訪問成功,則休息 N 秒,然后回到循環開始位置,繼續執行循環。這個N與業務性能、允許宕機時間有關。建議設置為5~10秒。不要太長,也不要太短。

                如果訪問不成功,

                     如果不成功次數 <= M 次,則不成功次數++,然后休息 K 秒,最后回到循環開始位置,繼續執行循環。M和K值,與業務性能、允許宕機時間有關。建議設置M為3次,K為1秒。

                     否則,殺死ThriftServer進程,1秒后重啟它,然后把 不成功次數設置為1, 回到循環開始位置 繼續執行循環。

 

5.Thrift的默認js封裝,用的是 同步 的遠程調用方法。如果該方法的訪問時間較長,則網頁界面會一直卡住,直到js超時,或成功返回結果。

    只有使用ajax,才能做到異步訪問,可惜thrift沒用ajax。不過,thrift有異步關鍵詞,大家可以去試試。

 

6.Thrift在0.9.0的AS3有Bug。在使用比較復雜的數據結構時發現,如果第一個字段為i32,則該字段可能因為AS3里的read方法的靜態定義錯誤,導致無法獲取第一個i32字段的值。通過把第一個字段作為廢棄字段,可以解決這個問題,但這種解決方案顯然是不科學的、蛋疼的、無節操的。

 

7.Thrift的C#的http client,是沒有自動回收功能(gc)的。因此,在使用了一定的次數后,比如100次,要手動把transport給close(),然后dispose(),最后,把所有變量重新new一遍。如果不這樣做,可以發現,每次client訪問后,內存會增加一點,並且這些內存一直不會被釋放,直到因內存不夠(64bit app)或溢出(32bit app),造成程序崩潰。

 

8.Thrift的C# HTTP Server在被client js訪問時,非常慢。經過測試,發現是因為Server收到client的請求,對client進行回應是,數據傳輸是按最基本通信單位,一個單位一個單位地傳輸,也就是說再大的數據量,它也是幾個kb幾個kb地傳,這種傳輸方法不慢才怪。【TTransport.cs】:

1 public virtual void Write(byte[] buf)
2 {
3     Write (buf, 0, buf.Length);
4 }

 

或者是它的子過程【TStreamTransport.cs】:

1 public override void Write(byte[] buf, int off, int len)
2 {
3     if (outputStream == null)
4     {
5         throw new TTransportException(TTransportException.ExceptionType.NotOpen, "Cannot write to null outputstream");
6     }
7     
8     outputStream.Write(buf, off, len);
9 }

 

這里沒有緩沖,導致數據邊制造邊Write,性能低。

 

9.有其他問題,歡迎加入QQ群23152359。里面有很多研究thrift的大牛。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM