引子
分布式系統調用的三態
在傳統的單機系統中,調用一個函數,要么返回成功,要么返回失敗。這就是兩態系統(2-state system)。
在分布式系統中,由於系統是分布在不同機器上的。還可能有一種狀態叫:超時。成功、失敗和超時是分布式系統調用的三態。
為什么要超時處理
對於超時這種狀態,長時間等待會影響用戶體驗,並發量大時還可能會因為線程池耗盡而不能響應其他請求。如果這個服務的調用方也是一個服務,那就有可能產生級聯反應,導致其他服務不可用,最終產生雪崩效應。
超時處理的手段
超時處理的兩個要點:判斷什么時候超時和超時后怎么處理。
判斷什么時候超時在無基礎數據時可通過經驗估算一個相對合理值。在服務上線后可依賴統計進行設置,比如設置99%的請求響應時間為超時時間。還可以通過人工智能進行調參來設置。
超時后一般采用快速失敗,如果不是核心服務,可直接超時返回失敗。如果是核心服務,可以設置相應的重試次數。
HTTP請求超時處理
HTTP請求一般會對兩個階段做超時處理:建立連接階段、數據通信階段。在apache的HttpClient實現中,添加了獲取連接池階段。
獲取連接池階段
因為建立連接需要IO、網絡帶寬等開銷,需要池化處理,如果超過了連接池的最大值,則需要等待其他連接執行完釋放資源。超時時間一般設置為1s之內。
建立建立階段
HTTP請求需要“三次握手”,第一次握手客戶端發送一個報文到服務器表示想和服務端建立連接。第二次握手是服務端接收到客戶端的請求,返回帶有同步和相應標記的客戶端報文,詢問客戶端是否准備好。第三次握手是客戶端再次響應服務端表示已經准備好。超時時間一般設置為1s到5s。
數據通信階段
與目標url建立連接后,等待數據報文傳輸的時間。這個階段又叫做socket通信階段。這個階段可能有兩種類型的事件:讀取和寫入。超時時間一般設1s到5s。
在以上三個階段的任何一個階段發生超時則立即終止等待返回失敗,http請求一般會設置超時后有三次重試。為了進一步理解,可以借助HttpClient的調用代碼來感受一下其使用
HttpParams httpParams = new BasicHttpParams();
// 獲取連接的最大等待時間1s,對應獲取連接池階段
ConnManagerParams.setTimeout(httpParams, 1000);
// 連接超時時間5s,對應建立建立階段
HttpConnectionParams.setConnectionTimeout(httpParams, 5000);
// socket超時時間5s,對應數據通信階段
HttpConnectionParams.setSoTimeout(httpParams, 5000);
最近因為OkHttpClient比HttpClient更簡單易用,使用的人多起來。借助OkHttpClient的調用代碼來感受一下其使用
OkHttpClient.Builder httpClientBuilder = new OkHttpClient.Builder();
// 連接超時時間5s,對應建立建立階段
httpClientBuilder.connectTimeout(config.getConnectionTimeout(), TimeUnit.MILLISECONDS);
// 讀取超時時間5s,對應數據通信階段(將socket細分為讀取和寫入兩種類型)
httpClientBuilder.readTimeout(config.getReadTimeout(), TimeUnit.MILLISECONDS);
// 寫入超時時間5s,對應數據通信階段(將socket細分為讀取和寫入兩種類型)
httpClientBuilder.writeTimeout(config.getReadTimeout(), TimeUnit.MILLISECONDS);
讀取和寫入都是socket階段的一個證據是如果發生超時,曝出的異常是SocketTimeoutException
Mysql連接超時處理
客戶端和Mysql連接也分為建立連接和數據通信兩個階段。目前mysql常用的版本是5.6和5.7。
和超時處理相關的參數匯總如下
參數名稱 | 參數說明 | 缺省值 | 最低版本要求 |
connectTimeout |
和數據庫服務器簡歷socket連接時的超時
單位:毫秒。0表示永不超時
|
0 | 3.0.1 |
socketTimeout |
socket操作(讀寫)超時
單位:毫秒。0表示永不超時
|
0 | 3.0.1 |
autoReconnect | 當數據庫連接異常中斷時是否自動重連 | false | 1.1 |
maxReconnects | autoReconnect=true時,重試連接的次數 | 3 | 1.1 |
failOverReadOnly | 自動重連成功后,連接是否設置為只讀 | true | 3.0.12 |
autoReconnectForPools | 是否使用針對數據庫連接池的重連策略 | False | 3.1.3 |
總結
慢就是錯
關於作者
一線開發十二年,有日本東京和美國硅谷研發經驗。有百余項技術發明專利,目前任美團點評技術專家。有自己的技術公眾號「編程一生」。如果您在閱讀文章時有什么疑問或者發現文章的錯誤,歡迎在公眾號里給我留言。