Thrift之TProtocol類體系原理及源碼詳細解析之其他協議類和總結

我的新浪微博:http://weibo.com/freshairbrucewoo

歡迎大家相互交流,共同提高技術。


第六節 其他協議類

主要的協議類基本上已經介紹完畢了,當然如果你有更好的實現和思路也可以實現自己的協議類,只要按照我前面介紹的類層次結構繼承就可以了。除了前面幾節介紹的協議類,Thrift還實現了一些自己內部使用的協議類,例如TDebugProtocol類,採用開發人員可讀的文本協議,有助於調試,又例如TProtocolTap類,它可以使用兩種協議類進行兩次協議轉換。放一個竊聽裝置在協議對象,任何讀取這個類都是通過一個封閉的協議對象的,但也反映爲寫第二個協議對象,還有一個就是用於異常的協議類了。

到此爲止,Thrift實現的協議類基本上介紹完畢了,從這些協議類的特徵來看:

(1)都是實現了對外提供的統一接口,所以每一個協議類可以隨時的單獨使用,可以很方便的用一個協議類替換另一個協議類,對於實現都是完全獨立的,協議類直接沒有任何關係(繼承除外);

(2)爲了擴展更多的協議類提供了良好的設計方式。

第七節 總結

(1)關於定義idl的一些總結,儘量避免定義過於複雜的數據結構。

從上面的協議分析來看,複合數據類型的存在着一個遞歸包含的關係。不過thrift在生成封/解包的代碼裏,並沒有出現遞歸調用來封/解包,而是採用了循環嵌套循環的方式來生成代碼,這種做法避免了頻繁遞歸調用封/解包函數,可提高封/解包的效率。同時帶來的問題就是生成的代碼量的急劇膨脹。

雖然沒有遞歸調用來封/解包如果定義太過於複雜的數據結構也會隨之產生多重循環,看下面的例子。假設定義以下一個數據結構:

map< string, list< set<string> > >thrift將會產生類似於以下的循環來進行封/解包:

foreach (key in map)

{

foreach ( set in map[key] )

{

foreach (string in set )

encode()/decode();   

}

}

假設map,list,set的元素各有100個,這將是一個嚴重影響性能的地方,應該避免。

(2)建議使用了unsigned long long的字段使用string類型,而不是u64類型,因爲目前的thrift不支持(不過好像最新版本是支持了的)。

(3)在網絡IO層一個潛在的瓶頸

由於thriftbinaryprotocol協議的包頭沒有任何的字節描述了整個網絡包的長度的信息。所以thriftbinaryprotocol協議在解包的時候是每次都只能採用從socket讀取一個變量的類型接着讀取變量的值出來這樣的解釋方式。

這種解包的方式可能引起的潛在問題:當請求的client數量非常多,交互的數據量也非常多(這裏可能是交互了很多字段,或者使用了太多複合數據類型)時,tcp/ip協議棧的緩衝區可能會被塞滿了還沒有被處理的數據,就會嚴重影響服務質量。至於爲何不提供某些字節來標識整個數據包的長度,是因爲thriftbinaryprotocol協議需要支持複雜數據類型,像set,list,map,而這些複合數據類型的大小是難以確定的。爲了支持標識整個數據包長度,封包前需要知道set,list,map的總體大小,那麼就需要遍歷set,list,map的大小,這是相當不划算,會增加運算邏輯,而且還會導致協議變得很複雜。

(4)如何做到兼容舊接口

當我們的server更新接口的同時,還需要保證舊client能夠和新server交互,那麼在定義IDL時就需要特別注意。假設,我們定義以下一個這個一個結構體來交互用戶信息。

struct user

{

1:username string,

2:password string,

3:sex i16, 

}

當我們需求變更時,假設以下兩種情況:

a)需要新增字段, age來表示年齡

struct user

{

1:username string,

2:password string,

3:sex i16, 

4:age i32,

}

注意,原來字段的序號標識一定不能被改變,1:username string, 不能改成 5:username string。此時,如果server是新的,client是舊的,並不影響client的工作,clientserver那邊收到的包裏包含了age的信息,只是沒有decode出來而已。

b)刪除字段sex,新增字段age

struct user

{

1:username string,

2:password string,

//3:sex i16, 

4:age i32, (注意,爲了保證a)所定義的client能夠和b)server交互,這裏的字段序號必須定義爲4)

}

此時,如果server是新的,clienta)所生成的也並不影響和b)server交互,因爲clientserver那邊收到的包雖然沒有包含sex的信息,但是client並不會崩潰,只是缺少了sex的信息。因此,我們需求變更時,儘量保存舊的字段不要刪除,做到只增不減的方式來兼容舊接口。這裏字段序號是唯一標識字段的關鍵。

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