SpringCloud服務的平滑上下線
吐槽:
以前都是手擼RPC,最近接觸 SpringCloud ,深感痛心。主要有以下幾點:
1)程式碼量巨大,找BUG時間長,超級複雜的設計
2)版本管理混亂,經常出現莫名其妙的配置錯誤(所以2.0是打死不敢上生產啊)
3)Netflix公司的有些程式碼,實在是讓人費解,根本就不考慮擴充套件性
4)生態鏈龐大,學習成本大
建議準備上微服務的同學,固定下一個版本,不要隨意更新或降級。拿tomcat的 basedir 來說, 1.5.8 到 1.5.13 到 1.5.16 版本是換來換去,不小心點會出事故的。
server: port: 21004 context-path: / tomcat: basedir: file:.
如上, basedir 先是從 . 換到 file:. ,又從 file:. 換成 . ,連相容程式碼都木有。有木有想打死工程師?
前言
今天主要談的話題,是 平滑的上下線功能 。所謂平滑,指的是發版無感知,不至於等到夜深人靜的時候偷偷去搞。某些請求時間可以長點,但不能失敗,尤其是對支付來說,想花錢花不出去是很讓人苦惱的;花了錢買不到東西是很讓人惱火的。整體來說,SpringCloud功能齊全,經過一段時間的踩坑後使用起來還是非常舒服的。
我們的微服務,大體整合了以下內容。
嗯,一個龐大的生態
問題
那麼問題來了,SpringCloud到註冊中心的註冊是透過 Rest 介面呼叫的。它不能像 ZooKeeper那樣,有問題節點反饋及時生效。也不能像 Redis 那麼快的去輪訓,太嬌貴怕輪壞了。如下圖:
有三個要求:
1)ServiceA下線一臺例項後,Zuul閘道器的呼叫不能失敗
2)ServiceB下線一臺例項後,ServiceA的Feign呼叫不能失敗
3)服務上線下線,Eureka服務能夠快速感知
說白了就一件事,怎樣儘量縮短服務下線後Zuul和其他被依賴服務的發現時間,並在這段時間內保證請求不失敗。
解決時間問題
影響因子
1) Eureka的兩層快取問題 (這是什麼鬼
EurekaServer預設有兩個快取,一個是ReadWriteMap,另一個是ReadOnlyMap。有服務提供者註冊服務或者維持心跳時時,會修改ReadWriteMap。當有服務呼叫者查詢服務例項列表時,預設會從ReadOnlyMap讀取(這個在原生Eureka可以配置,SpringCloud Eureka中不能配置,一定會啟用ReadOnlyMap讀取),這樣可以減少ReadWriteMap讀寫鎖的爭用,增大吞吐量。EurekaServer定時把資料從ReadWriteMap更新到ReadOnlyMap中
2) 心跳時間
服務提供者註冊服務後,會定時心跳。這個根據服務提供者的Eureka配置中的服務重新整理時間決定。還有個配置是服務過期時間,這個配置在服務提供者配置但是在EurekaServer使用了,但是預設配置EurekaServer不會啟用這個欄位。需要配置好EurekaServer的掃描失效時間,才會啟用EurekaServer的主動失效機制。在這個機制啟用下:每個服務提供者會傳送自己服務過期時間上去,EurekaServer會定時檢查每個服務過期時間和上次心跳時間,如果在過期時間內沒有收到過任何一次心跳,同時沒有處於保護模式下,則會將這個例項從ReadWriteMap中去掉
3)呼叫者服務從Eureka拉列表的輪訓間隔
4) Ribbon快取
解決方式
1) 禁用Eureka的ReadOnlyMap快取 (Eureka端)
eureka.server.use-read-only-response-cache: false
2) 啟用主動失效,並且每次主動失效檢測間隔為3s (Eureka端)
eureka.server.eviction-interval-timer-in-ms: 3000
像 eureka.server.responseCacheUpdateInvervalMs 和 eureka.server.responseCacheAutoExpirationInSeconds 在啟用了主動失效後其實沒什麼用了。預設的180s真夠把人給急瘋的。
3) 服務過期時間 (服務提供方)
eureka.instance.lease-expiration-duration-in-seconds: 15
超過這個時間沒有接收到心跳EurekaServer就會將這個例項剔除。EurekaServer一定要設定eureka.server.eviction-interval-timer-in-ms否則這個配置無效,這個配置一般為服務重新整理時間配置的三倍。預設90s!
4) 服務重新整理時間配置,每隔這個時間會主動心跳一次 (服務提供方)
eureka.instance.lease-renewal-interval-in-seconds: 5
預設30s
5) 拉服務列表時間間隔 (客戶端)
eureka.client.registryFetchIntervalSeconds: 5
預設30s
6) ribbon重新整理時間 (客戶端)
ribbon.ServerListRefreshInterval: 5000
ribbon竟然也有快取,預設30s
這些超時時間相互影響,竟然三個地方都需要配置,一不小心就會出現服務不下線,服務不上線的囧境。不得不說SpringCloud的這套預設引數簡直就是在搞笑。
重試
那麼一臺伺服器下線,最長的不可用時間是多少呢?(即請求會落到下線的伺服器上,請求失敗)。趕的巧的話,這個基本時間就是 eureka.client.registryFetchIntervalSeconds+ribbon.ServerListRefreshInterval ,大約是 8 秒的時間。如果算上服務端主動失效的時間,這個時間會增加到 11秒 。
如果你只有兩個例項,極端情況下服務上線的發現時間也需要11秒,那就是22秒的時間。
理想情況下,在這11秒之間,請求是失敗的。加入你的QPS是1000,部署了四個節點,那麼在11秒中失敗的請求數量會是 1000 / 4 * 11 = 2750 ,這是不可接受的。所以我們要引入重試機制。
SpringCloud引入重試還是比較簡單的。但不是配置一下就可以的,既然用了重試,那麼就還需要控制超時。可以按照以下的步驟:
1) 引入pom (千萬別忘了哦)
<dependency> <groupId>org.springframework.retry</groupId> <artifactId>spring-retry</artifactId> </dependency>
2) 加入配置
ribbon.OkToRetryOnAllOperations:true #(是否所有操作都重試,若false則僅get請求重試) ribbon.MaxAutoRetriesNextServer:3 #(重試負載均衡其他例項最大重試次數,不含首次例項) ribbon.MaxAutoRetries:1 #(同一例項最大重試次數,不含首次呼叫) ribbon.ReadTimeout:30000 ribbon.ConnectTimeout:3000 ribbon.retryableStatusCodes:404,500,503 #(那些狀態進行重試) spring.cloud.loadbalancer.retry.enable:true # (重試開關)
釋出系統
OK,機制已經解釋清楚,但是實踐起來還是很繁雜的,讓人焦躁。比如有一個服務有兩個例項,我要一臺一臺的去釋出,在釋出第二臺之前,起碼要等上11秒。如果手速太快,那就是災難。所以一個配套的釋出系統是必要的。
首先可以透過rest請求去請求Eureka,主動去隔離一臺例項,多了這一步,可以減少至少3秒服務不可用的時間(還是比較划算的)。
然後透過打包工具打包,推包。依次上線替換。
市面上沒有這樣的持續整合哦你工具,那麼釋出系統就需要定製,這也是一部分工作量。
到此,僅僅是解決了SpringCloud微服務平滑上下線的功能,至於灰度,又是另外一個話題了。有條件的公司選擇自研還是很明智的,不至於將功能拉低到如此的水平。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31545684/viewspace-2215300/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- SpringCloud服務安全連線SpringGCCloud
- SpringCloud之服務呼叫SpringGCCloud
- SpringCloud之服務註冊SpringGCCloud
- 設計思路-服務和庫平滑遷移
- SpringCloud(二)Eureka服務的搭建與使用SpringGCCloud
- springcloud(三):服務提供與呼叫SpringGCCloud
- springcloud服務閘道器-gatewaySpringGCCloudGateway
- SpringCloud+Hystrix服務容錯SpringGCCloud
- springcloud服務端配置檔案SpringGCCloud服務端
- Ctx:模組化服務上下文框架框架
- 【SpringCloud】(二):服務發現和服務註冊SpringGCCloud
- SpringCloud服務的註冊與發現(Eureka)SpringGCCloud
- SpringCloud進行nacos的服務註冊和服務管理案例SpringGCCloud
- 《springcloud 四》服務保護機制SpringGCCloud
- SpringCloud-服務間通訊方式SpringGCCloud
- 構建SpringCloud閘道器服務SpringGCCloud
- springcloud(十):服務閘道器zuulSpringGCCloudZuul
- 自己編寫平滑加權輪詢演算法,實現反向代理叢集服務的平滑分配演算法
- Spring Cloud的應用程式—上下文服務SpringCloud
- 微服務SpringCloud之服務註冊與發現微服務SpringGCCloud
- SpringCloud使用Consul時,服務登出的操作方式SpringGCCloud
- SpringCloud系列使用Eureka進行服務治理SpringGCCloud
- SpringCloud-Hystrix 服務降級、熔斷SpringGCCloud
- SpringCloud(二):服務呼叫與負載均衡SpringGCCloud負載
- 三. SpringCloud服務註冊與發現SpringGCCloud
- 五. SpringCloud服務降級與熔斷SpringGCCloud
- SpringCloud-使用Feign呼叫服務介面SpringGCCloud
- SpringCloud服務消費者-openFeign元件SpringGCCloud元件
- SpringCloud 9.OpenFeign服務介面呼叫SpringGCCloud
- springcloud之服務註冊與發現SpringGCCloud
- 【SpringCloud】(五):服務註冊到Eureka ServerSpringGCCloudServer
- 《springcloud 一》搭建註冊中心,服務提供者,服務消費者SpringGCCloud
- SpringCloud構建微服務架構-Hystrix服務降級SpringGCCloud微服務架構
- 業務建模:上下文(場景)還是服務?
- SSH服務連線
- 用無上下文的Go語言實現HTTP服務GoHTTP
- springCloud學習筆記2(服務發現)SpringGCCloud筆記
- SpringCloud(3)---Eureka服務註冊與發現SpringGCCloud