1、通過jenkins的kubctl向Rancher釋出鏡像時。第一步在Rancher容器内設定健康檢查。通過K8S健康檢查,以雙服務node為例:能達到先啟動一個新服務,再停掉第一個舊服務;然後會自動啟動第二個新服務,再停掉一個舊服務。
具體健康檢查如下:
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiI2EzX4xSZz91ZsAzNfRHLGZkRGZkRfJ3bs92YsAjMfVmepNHLop0MiJXNXlVQClGVF5UMR9Fd4VGdsATNfd3bkFGazxSUhxGatJGbwhFT1Y0Mk9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnLxkDN3QmY1QWZklzMmRGO4QDNwQTZ4YDNmJjM0MjZ5IzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
2、設定健康檢查以後,我們再發版過程中,通過jmeter實時對服務進行測試,發現有失敗的服務。其中有一些服務報timeout。我們想到ribbon的重試機制。但是發現timeout在單服務逾時時間内就直接報錯了。由此推測重試沒生效。
經過修改gateway的配置檔案:retryable要設定為true, MaxAutoRetriesNextServer為重試次數。
zuul:
retryable: true
ribbon-isolation-strategy: thread
thread-pool:
use-separate-thread-pools: true
ribbon:
okhttp:
enabled: true
MaxTotalConnections: 500
MaxConnectionsPerHost: 2000
#Http請求中的socketTimeout
ReadTimeout: 3000
#Http請求中的connectTimeout
ConnectTimeout: 3000
# 切換執行個體的重試次數
MaxAutoRetriesNextServer: 1
# 對目前執行個體的重試次數
MaxAutoRetries: 0
同時,gateway代碼中要引入包:
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
</dependency>
3、經過設定ribbon重試。發現沒有再出現timeout的錯誤。但是依然在版本切換中有一些服務在70~80ms就報錯。報錯展現微服務的代碼層面。我們懷疑是注冊中心沒有實時重新整理的原因。于是我們在k8s的鈎子prestop中主動調微服務api,向registry發起服務下線的請求。
4、服務在強停止之前,會先向注冊中心發起下線請求。然後讓服務在停服之前先sleep 10秒。通過測試發現,服務下線前,注冊中心确實down了對應的微服務,但是jmeter測試仍然有報錯。我們猜想registry可能有緩存。
5、于是我們禁用了registry的緩存。
6、同時,我們調整了gateway拉取registry路由清單的時長為5s,預設是30s。
7、此刻再用jmeter調用。發現不再出現服務失敗的情況。且能實作優雅停服發版。
8、為什麼仍然會有偶發的調用失敗?
首先,k8s停node時,由于微服務上報心跳時間是5s,雖然registry設定了過期時間是5s,但是cache的存在,導緻注冊中心并沒有實時重新整理。依然有新的請求調動過來。
9、為什麼要主動上報registry?
如果不在k8s中實時的curl api通知registry下線服務。在k8s sleep的10秒鐘内,微服務心跳每5秒自動上報的狀态仍然是up。
10、那為什麼k8s通知了registry下線服務後仍然要sleep 10秒呢?
(1)我們要給gateway拉取registry的間隔5秒留時間。(注意:gateway預設不是5秒)
(3)如果剛好4.99秒時,有請求過來,gateway沒重新整理,依然調用到了舊微服務上,此時需要給該請求在舊服務上留有執行時間。我們的單請求的執行時間都在毫秒級,隻要大于5秒,時間依情況而定。