我的新浪微博: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層一個潛在的瓶頸
由於thrift的binaryprotocol協議的包頭沒有任何的字節描述了整個網絡包的長度的信息。所以thrift的binaryprotocol協議在解包的時候是每次都只能採用從socket讀取一個變量的類型接着讀取變量的值出來這樣的解釋方式。
這種解包的方式可能引起的潛在問題:當請求的client數量非常多,交互的數據量也非常多(這裏可能是交互了很多字段,或者使用了太多複合數據類型)時,tcp/ip協議棧的緩衝區可能會被塞滿了還沒有被處理的數據,就會嚴重影響服務質量。至於爲何不提供某些字節來標識整個數據包的長度,是因爲thrift的binaryprotocol協議需要支持複雜數據類型,像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的工作,client從server那邊收到的包裏包含了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是新的,client是a)所生成的也並不影響和b)的server交互,因爲client從server那邊收到的包雖然沒有包含sex的信息,但是client並不會崩潰,只是缺少了sex的信息。因此,我們需求變更時,儘量保存舊的字段不要刪除,做到只增不減的方式來兼容舊接口。這裏字段序號是唯一標識字段的關鍵。