阿裏雲OCS超時問題的分析與解決
之前有用戶聯係我們阿裏雲,反映在使用OCS時會出現超時錯誤,希望我們阿裏雲技術團隊能夠幫忙解決。通常用戶會將熱點數據存放到OCS中,用以提高用戶的業務處理響應速度,因此超時問題對於OCS來講非常敏感,這引起了阿裏雲OCS團隊的重視,隨即開始了調查分析。
對於一個網絡服務,通常導致超時的原因包括:網絡抖動、CPU某個核心負載過高、內存不足導致的頻繁swap、網卡負載過高、協議BUG導致的回包有誤。通過分析,我們發現了客戶端自身存在的某些問題導致OCS超時;除此之外,進一步的分析表明在某些特殊情況下OCS自身的一些問題也會導致超時。下麵我們來看看阿裏雲OCS團隊的工程師們是怎麼樣分析並解決這些超時問題的。
在進入技術細節分析之前,先簡單介紹一下阿裏雲OCS的大致工作機製:基於Memcached協議的用戶請求從阿裏雲ECS服務器上發出,通過阿裏雲SLB(負載均衡)連到阿裏雲OCS的前端proxy,再連接後端底層的服務器集群進行最終處理。
對於超時問題,我們最先考慮問題可能在於客戶端到SLB,SLB到proxy之間的網絡及協議問題。為了直觀分析排查問題,在考慮proxy承受能力之後,我們建議用戶不經過阿裏雲SLB直接連我們的proxy,這樣可以直接在服務器抓包了解異常情況時的報文交互,同時也排除了SLB可能出問題的幹擾。
在用戶將自己的服務器切到我們的proxy上後,我們對每個客戶端抓包,其中一台的報文如下:
我們看到截圖片段中有兩個客戶端給proxy的回報,超過了200ms,這說明客戶端負載有問題,經過與用戶確認這一情況得到了證實。由此我們知道:某些情況下使用OCS出現超時是用戶客戶端負載問題導致,隻要合理配置客戶端就能解決此類問題。
接下來我們進一步調查發現,另外還有一些超時是因為阿裏雲OCS自身的原因導致的。阿裏雲OCS對於存儲數據的大小是有限製的,即Value最大為1MB。若超出此限製,客戶端會收到“Value too large”的錯誤信息。某些OCS超時錯誤恰恰是這個尺寸大小導致的。上文提到OCS的處理流程是proxy調用底層後端服務,我們分析OCS代碼發現底層後端代碼中對報文Value長度的限製是 1000 * 1000字節,而proxy層根據memcached協議是1024 * 1024字節。這種不一致導致當客戶端發送的Value長度處於1000 * 1000 ~ 1024 * 1024字節的臨界區間時, set\replace\add操作沒有任何信息返回,即沒有response;而客戶端會一直等待這個response,直到拋出超時異常。雖然是個看起來很初級的BUG,但由於它僅在某些特殊情況下出現,所以定位它還是花了一點時間。找到了這個問題,解決起來就容易了。
解決了上述客戶端負載和尺寸檢測BUG的問題,仍有另外的用戶給我們報告OCS超時問題。莫非還有其他的原因?
對於新出現的這些超時情況,我們還是采取在客戶端抓包的辦法,看到的數據如下:
從圖中可以得知,客戶端10.162.108.239到OCS服務器端10.160.124.220的連接在18:06分開始休眠到18:41被喚醒,發起一次Get請求;之後客戶端經曆多次重試後,TCP才知道連接已斷。這期間客戶端未從服務器端收到任何報文。
上文提到過,用戶的請求要通過阿裏雲SLB(負載均衡)連到阿裏雲OCS的多台proxy,再連接後端底層的服務器集群。所以我們考慮是否存在SLB導致超時問題的可能性。
經過與阿裏雲SLB部門的同學溝通得知,SLB會斷開15分鍾未活躍的連接,且不會給客戶端和服務器發任何FIN或RST報文。這樣就可能出現一個問題,即客戶端和服務器都認為連接正常。然而當客戶端應用層發起一個請求時,該請求被交至TCP層,而TCP層不知道此時鏈接已經斷開,於是重發該請求數次,直到應用層的超時時間到,就返回Timeout。在某些極端情況下,如果應用層沒有設過期或者過期時間非常長,就會一直等到TCP層超時才會返回。
在得知了SLB的這個情況後,為了繞開這個問題,我們在OCS服務器上設置了TCP層的keepAlive包。將/proc/sys/net/ipv4/tcp_keepalive_time由默認的7200s改為450s一次。接著我們做測試,客戶端連接到OCS服務器上,然後抓包如下:
圖中顯示在20:58分時,服務端TCP層觸發keepalive包,但始終不能發出去。即客戶端依然收不到任何信息。在客戶端同時抓包,抓不到任何來自服務器11211端口的KeepAlive報文。接下來我們查看客戶端的netstat狀態如下:
即客戶端依然認為自己還處於連接狀態,因為沒有收到服務器的任何消息。如果此時用戶發起請求,仍然會得到最初用戶反饋的現象,即繼續重傳直至超時。
看來這個問題還沒有解決。我們繼續分析,考慮到一個可能性:我們阿裏雲OCS的客戶端都是跑在阿裏雲ECS上,會不會這裏有什麼情況?
於是我們與阿裏雲ECS團隊的同學溝通了解到:ECS上開啟了netfilter,其中一條過濾規則是對於空閑時間大於180s的連接,netfilter會將它從established表中剔除,且不會通知客戶端服務器,當客戶端或者服務端還在該鏈接上麵發送報文時,NODE將不再轉發。
至此情況大致明朗了:因為是通過ECS和SLB建立的連接,而ECS和SLB對於連接空閑時間都有各自不同的限製,所以可能出現OCS服務器與客戶端之間的KeepAlive包丟失,從而導致超時情況的發生。於是我們把OCS服務器的KeepAlive改為90s,繞過SLB、ECS,啟動應用再重新測試,問題解決。
表麵上看起來同樣都是OCS超時的問題,其真正的原因卻是各不相同。我們在這裏描述起來看似很輕鬆,但是在實際工作中能夠迅速及時的解決這些問題卻絕非易事。有的很容易就被發現解決,有的原因找起來卻是破費腦筋。通過我們阿裏雲工程師們的努力,能夠讓用戶更好的使用阿裏雲服務,這是我們工作最大的樂趣和價值所在。
最後更新:2017-04-03 08:26:14