Posted on 2009-09-27 23:29
dennis 閱讀(3389)
評論(6) 編輯 收藏 所屬分類:
java 、
my open-source
泰山在線的周利朋友對xmemcached做了很多測試,他發(fā)現(xiàn)了一個比較嚴重的BUG,在linux平臺的重連機制有時候會失效。表現(xiàn)的現(xiàn)象是這樣,正常連接上memcached之后,kill掉其中的一臺memcched server,xmemcached會開始自動重連這臺server直到連接成功,然而事情沒有像預(yù)想的那樣,現(xiàn)象是有時候可以重連成功,有時候卻沒有,如果設(shè)置了connectionPoolSize,有時候建立的連接數(shù)達到connectionPoolSize,有時候卻沒有。他還向我描述了那時候的netstat觀察到的網(wǎng)絡(luò)情況,有比較多CLOSE_WAIT存在,這個顯然是由于memcached主動斷開,xmemcached被動進入CLOSE_WAIT,但是沒有發(fā)送FIN的情況,如果有發(fā)送FIN那應(yīng)該進入LAST_ACK而不是停留在CLOSE_WAIT。因此反應(yīng)的第一個問題是xmemcached沒有在接到memcached斷開之后主動關(guān)閉socket發(fā)送FIN。檢查代碼發(fā)現(xiàn)其實是有這個邏輯,但是nio的channel關(guān)閉有個隱蔽的問題,就是在SelectionKey.cancel之后還需要調(diào)用select才能真正地關(guān)閉socket,這里會有個延遲,另外,為了防止CLOSE_WAIT現(xiàn)象的再次發(fā)生,設(shè)置SO_LINGER選項強制關(guān)閉也是必須的。做了這兩個修改后,build了一個臨時版本請周利朋友幫忙測試,重連失敗的情況有所減輕,但是仍然會發(fā)生。因此根本的問題不在于CLOSE_WAIT的處理上,通過檢查代碼發(fā)現(xiàn)了下面這段代碼:
if(!future.isDone()&&!future.get(DEFAULT_CONNECTION_TIMEOUT,TimeUnit.MILLISECONDS){


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