Thrift採坑記錄——Client多線程

一、Thrift 採坑

  1. Thrift 的Server/Client有個較爲嚴重的bug(https://issues.apache.org/jira/browse/THRIFT-601 ),隨機向thrift sever的監聽端口發些數據,可能會導致Server OutOfMemory,細細看看代碼,這個bug有點土。

  2. Thrift Client線程不安全,多線程下使用可能導致Server和客戶端程序崩潰。Client的每次調用遠程方法其實是有多次Socket寫操作,因此每個線程中使用的Client要保證獨立,如果多個線程混用同一個Client(其實是用同一個Socket),可能會導致傳輸的字節順序混亂,使得Server OutOfMemory(參考1)

  3. Thrift定義數據結構時,儘量避免用map, 或者set。在cpp下, map被對應爲std::map(rb tree)和std::set,thrift生成的類不會重載”<”,因此需要手動修改生成類,否則link沒法通過。較爲麻煩。

  4. 如果Client端基於效率考慮,要緩存Socket,需要重新實現其TTransport類,以支持 Socket緩存池。當然,這個實現其實跟thrift沒多大關係,算是2次開發。但一般都要這麼做的吧?

  5. 如果Client基於效率考慮,緩存了Socket,那麼thrift Server端的模式選擇就較爲重要了。如果使用同步的TThreadPoolServer,那麼無可避免的,客戶端緩存1個Socket,Server端就會有一個線程一直處於Server狀態,等待peek這個Socket上的數據。這個線程就不能用於其它請求了。所以,及時清理Client端的Socket及控制Socket池的大小是非常必要的。

  6. 聽同事說CPP Thrift Server的Epoll NonBlocking模式有效率問題。其實,併發要求不高的Server用LT模式的EPoll其實很方便的,當然,這個要自己給Thrfit Server做patch了,不過也不麻煩。開發起來也是很方便的。我想給我們的Server加個EPOLLONESHOT的同步EPoll實現。

  7. CPP下的 TThreadPoolServer和TThreadServer由一個有趣的問題,如果有客戶端維護長連接,那麼對這個Server實例做析構的時候會堵塞(前面說過了,在peek中…)。

  8. 用valgrind看,thrift cpp似乎有一些內存問題。沒細看。

  9. 無論是Java,還是CPP,Server端都無法通過合法的方式獲取Client的ip, port。可以通過編寫ThriftServerEventHandler可以處理這件事情。如果想要獲取Client ip, port的話,可以看看這個東西。

二、關於socket和多線程

https://www.zhihu.com/question/56899596
上面的鏈接討論了 多線程下socket的設計方案

結合項目的使用,由於服務器採取的是單線程同步模式,因此必然客戶端所有的socket都是基於tcp( TSocket
)
而對於 TCP,通常多線程讀寫同一個 socket 是錯誤的設計,因爲多線程讀寫同一個socket極容易造成socket數據混亂,就算進行加鎖讀寫,但是發生 short write,你是不是要一直等到整條消息發送完才解鎖(無論阻塞IO還是非阻塞IO),如果這樣,你的臨界區長度由對方什麼時候接收數據來決定,一個慢的 peer 就把你的程序搞死了。

所以現在將Thrift的client改成多socket模式,即每一個線程都new一個client(即一個socket),這樣就不會出現併發問題了。

發佈了78 篇原創文章 · 獲贊 10 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章