目錄
背景
- 早先的都採用基於grpc+etcd做服務註冊和服務發現,都是正常的
- 後來有部分服務採用k8s部署,爲了新舊兼容,服務會按照老方式把宿主機的ip註冊到etcd上,k8s體系類使用體系類的服務發現,k8s體系外的依然使用原來的方式,互不影響
- 但是有服務基於k8s部署之後,發現client調用接口超時,而直接通過ip調用卻是正常
- 且多數是發生在k8s的出現pod彈性伸縮之後
分析
- 服務端註冊地址,從etcd來看,是正常的
- 服務端直接通過ip調用也正常的,所以排除服務端本身的問題
- etcd裏面顯示的地址的確會出現沒有的情況,但是通過日誌發現服務端lease維持的心跳卻是正常的,一度覺得懷疑人生~~
- 後來發現是下面的原因A導致的,
- 解決後,發現依然有問題,O(∩_∩)O,很奇怪~
- 通過打開grpc日誌,發現grpc的client端會收到地址列表爲空的問題:balancerWrapper: got update addr from Notify:[]
- 但是etcd裏面顯示的註冊地址卻都是存在的,一度覺得懷疑人生~~
- 後來通過閱讀grcp源碼分析,增加日誌排查 :google.golang.org/grpc/balancer.go 文件中 函數 (rr *roundRobin) watchAddrUpdates() 裏面,增加 etcd watch的數據變動行爲,發現了原因
- 通過下面的原因B的處理方式解決
原因
- 問題存在兩個
- 原因A
- 早先服務註冊:類似於
key:service/go_server_xx/10.1.1.1:9999
val:{"Op":0,"Addr":"10.1.1.1:9999","Metadata":null} -
並且通過etcd的lease機制維持心跳
- 假設一個宿主機起了兩個pod,也就兩個服務,ser1和ser2
- ser1啓動的時候會註冊 service/go_server_xx/10.1.1.1:9999 並且綁定 lease1,並且維持lease1心跳
- 之後,ser2啓動的時候也會註冊 service/go_server_xx/10.1.1.1:9999 並且綁定 lease2,並且維持lease2心跳,住以此時這個key和lease1解綁了
- 當發生彈性伸縮的時候,比如ser2關閉了,此時 lease2過期,同時與其綁定的key也被刪除,所以client會發生找不到地址列表的問題
- 但是從服務端ser1來看,依然提供服務,並且與etcd的lease1心跳也正常~~,哈哈
- 早先服務註冊:類似於
- 解決方法A
- 通過在key後邊增加後綴解決,類似於:service/go_server_xx/lease1/10.1.1.1:9999, 這樣即使一個宿主機上有多個服務,各自也會註冊各自的
- 原因B
- 上述問題解決之後,還有個問題
-
比如同一個宿主機註冊的兩個服務地址
key1:service/go_server_xx/lease1/10.1.1.1:9999 val1:{"Op":0,"Addr":"10.1.1.1:9999","Metadata":null} 和 key2:service/go_server_xx/lease2/10.1.1.1:9999 val2:{"Op":0,"Addr":"10.1.1.1:9999","Metadata":null}
- 在client端watch etcd變化的時候會發現兩個add行爲,但是 由於val中的地址是一樣的,可用addrs列表裏面只會保存一個 10.1.1.1:9999,另一個會跳過:
grpclog.Infoln("grpc: The name resolver wanted to add an existing address: ", addr)
- 當發生彈性伸縮的時候,比如ser2關閉了
- watch etcd變化的時候會收到一個del行爲,這個時候會刪除10.1.1.1:9999
- 這樣client可用地址列表裏面就是空的了
- grpc的client對象收到 balancerWrapper: got update addr from Notify:[]
- 解決方法B:
-
註冊的時候增加metadata做區分就可以了,類似
key1:service/go_server_xx/lease1/10.1.1.1:9999 val1:{"Op":0,"Addr":"10.1.1.1:9999","Metadata":lease1} 和 key2:service/go_server_xx/lease2/10.1.1.1:9999 val2:{"Op":0,"Addr":"10.1.1.1:9999","Metadata":lease2}
-
這樣增加的時候,可用地址列表裏面就會增加兩個元素
-
總結
etcd+grpc的一整套機制(服務註冊&服務發現等)是好的
k8s的那一套機制也是好的
但是兩者結合使用,就得注意很多地方,要不然會出現很多蛋疼的問題提