XMemcached的一個嚴重BUG
Posted on 2009-09-27 23:29 dennis 閱讀(3394) 評論(6) 編輯 收藏 所屬分類: java 、my open-source 泰山在線的周利朋友對xmemcached做了很多測試,他發現了一個比較嚴重的BUG,在linux平臺的重連機制有時候會失效。表現的現象是這樣,正常連接上memcached之后,kill掉其中的一臺memcched server,xmemcached會開始自動重連這臺server直到連接成功,然而事情沒有像預想的那樣,現象是有時候可以重連成功,有時候卻沒有,如果設置了connectionPoolSize,有時候建立的連接數達到connectionPoolSize,有時候卻沒有。他還向我描述了那時候的netstat觀察到的網絡情況,有比較多CLOSE_WAIT存在,這個顯然是由于memcached主動斷開,xmemcached被動進入CLOSE_WAIT,但是沒有發送FIN的情況,如果有發送FIN那應該進入LAST_ACK而不是停留在CLOSE_WAIT。因此反應的第一個問題是xmemcached沒有在接到memcached斷開之后主動關閉socket發送FIN。檢查代碼發現其實是有這個邏輯,但是nio的channel關閉有個隱蔽的問題,就是在SelectionKey.cancel之后還需要調用select才能真正地關閉socket,這里會有個延遲,另外,為了防止CLOSE_WAIT現象的再次發生,設置SO_LINGER選項強制關閉也是必須的。做了這兩個修改后,build了一個臨時版本請周利朋友幫忙測試,重連失敗的情況有所減輕,但是仍然會發生。因此根本的問題不在于CLOSE_WAIT的處理上,通過檢查代碼發現了下面這段代碼:
可能你已經發現問題在哪。這段代碼的意圖是通過future.get阻塞等待連接成功或者失敗,如果失敗做一些處理,如果成功將connected設置為true。這里判斷失敗有兩個條件,future.isDone為false,并且future.get也返回false才認為失敗,問題恰恰出在這里,因為future.isDone可能在連接的失敗的情況下返回true,而這段邏輯將這種情況誤判為連接成功,導致重試的請求被取消。修改很簡單,將future.isDone這個條件去掉即可。
回想起來,我也忘了當初為什么加上這個條件,這里感謝下周利的幫助,并且向使用xmemcached的朋友們提個醒。這個問題在win32平臺上不會出現(比較詭異,估計跟并發有關),在linux平臺出現的幾率比較大,預計在10月份發布的1.2.0-stable中修正,這個stable版主要工作是修復BUG。歡迎更多朋友反饋問題和BUG,我將及時修復和反饋。
if(!future.isDone()&&!future.get(DEFAULT_CONNECTION_TIMEOUT,TimeUnit.MILLISECONDS){


}else{
connected=true;
}


}else{
connected=true;
}
可能你已經發現問題在哪。這段代碼的意圖是通過future.get阻塞等待連接成功或者失敗,如果失敗做一些處理,如果成功將connected設置為true。這里判斷失敗有兩個條件,future.isDone為false,并且future.get也返回false才認為失敗,問題恰恰出在這里,因為future.isDone可能在連接的失敗的情況下返回true,而這段邏輯將這種情況誤判為連接成功,導致重試的請求被取消。修改很簡單,將future.isDone這個條件去掉即可。
回想起來,我也忘了當初為什么加上這個條件,這里感謝下周利的幫助,并且向使用xmemcached的朋友們提個醒。這個問題在win32平臺上不會出現(比較詭異,估計跟并發有關),在linux平臺出現的幾率比較大,預計在10月份發布的1.2.0-stable中修正,這個stable版主要工作是修復BUG。歡迎更多朋友反饋問題和BUG,我將及時修復和反饋。