如何快速构建服务发现的高可用能力
作者:十眠
背景
注冊中心作為承擔(dān)服務(wù)注冊發(fā)現(xiàn)的核心組件,是微服務(wù)架構(gòu)中必不可少的一環(huán)。在 CAP 的模型中,注冊中心可以犧牲一點(diǎn)點(diǎn)數(shù)據(jù)一致性(C),即同一時刻每一個節(jié)點(diǎn)拿到的服務(wù)地址允許短暫的不一致,但必須要保證可用性(A)。因?yàn)橐坏┯捎谀承﹩栴}導(dǎo)致注冊中心不可用,或者服務(wù)連不上注冊中心,那么想要連接他的節(jié)點(diǎn)可能會因?yàn)闊o法獲取服務(wù)地址而對整個系統(tǒng)出現(xiàn)災(zāi)難性的打擊。
一個真實(shí)的案例
全篇從一個真實(shí)的案例說起,某客戶在阿里云上使用 Kubernetes 集群部署了許多自己的微服務(wù),由于某臺 ECS 的網(wǎng)卡發(fā)生了異常,雖然網(wǎng)卡異常很快恢復(fù)了,但是卻出現(xiàn)了大面積持續(xù)的服務(wù)不可用,業(yè)務(wù)受損。
我們來看一下這個問題鏈?zhǔn)侨绾涡纬傻?#xff1f;
風(fēng)險環(huán)環(huán)相扣,缺一不可。
最終導(dǎo)致故障的原因是服務(wù)無法調(diào)用下游,可用性降低,業(yè)務(wù)受損。下圖示意的是客戶端缺陷導(dǎo)致問題的根因:
回顧整個案例,每一環(huán)每個風(fēng)險看起來發(fā)生概率都很小,但是一旦發(fā)生就會造成惡劣的影響。服務(wù)發(fā)現(xiàn)高可用是微服務(wù)體系中很重要的一環(huán),當(dāng)然也是我們時常忽略的點(diǎn)。在阿里內(nèi)部的故障演練中,這一直是必不可少的一個環(huán)節(jié)。
面向失敗的設(shè)計
由于網(wǎng)絡(luò)環(huán)境的抖動比如 CoreDns 的異常,或者是由于某些因素導(dǎo)致我們的注冊中心不可用等情況,經(jīng)常會出現(xiàn)服務(wù)批量閃斷的情況,但這種情況其實(shí)不是業(yè)務(wù)服務(wù)的不可用,如果我們的微服務(wù)可以識別到這是一種異常情況(批量閃斷或地址變空時),應(yīng)該采取一種保守的策略,以免誤推從而導(dǎo)致全部服務(wù)出現(xiàn)"no provider"的問題,會導(dǎo)致所有的微服務(wù)不可用的故障,并且持續(xù)較長時間難以恢復(fù)。
站在微服務(wù)角度上考慮,我們?nèi)绾慰梢郧卸我陨系膯栴}鏈呢?以上的案例看起來是 Nacos-client 低版本造成的問題,但是如果我們用的是 zookeeper、eureka 等注冊中心呢?我們能拍著胸脯說,不會發(fā)生以上的問題嗎?面向失敗的設(shè)計原則告訴我們,如果注冊中心掛掉了,或者我們的服務(wù)連不上注冊中心了,我們需要有一個方式保證我們的服務(wù)正常調(diào)用,線上的業(yè)務(wù)持續(xù)不斷。
本文介紹的是服務(wù)發(fā)現(xiàn)過程中的高可用的機(jī)制,從服務(wù)框架層面思考如何徹底解決以上的問題。
服務(wù)發(fā)現(xiàn)過程中的高可用原理解析
服務(wù)發(fā)現(xiàn)高可用-推空保護(hù)
面向失敗的設(shè)計告訴我們,服務(wù)并不能完全相信注冊中心的通知的地址,當(dāng)注冊中心的推送地址為空時候,服務(wù)調(diào)用肯定會出 no provider 錯誤,那么我們就忽略此次推送的地址變更。
微服務(wù)治理中心提供推空保護(hù)能力
-
默認(rèn)無侵入支持市面上近五年來的 Spring Cloud 與 Dubbo 框架
-
無關(guān)注冊中心實(shí)現(xiàn),無需升級 client 版本
服務(wù)發(fā)現(xiàn)高可用-離群實(shí)例摘除
心跳續(xù)約是注冊中心感知實(shí)例可用性的基本途徑。但是在特定情況下,心跳存續(xù)并不能完全等同于服務(wù)可用。
因?yàn)槿匀淮嬖谛奶?#xff0c;但服務(wù)不可用的情況,例如:
-
Request 處理的線程池滿
-
依賴的 RDS 連接異常導(dǎo)致出現(xiàn)大量慢 SQL
-
某幾臺機(jī)器由于磁盤滿,或者是宿主機(jī)資源爭搶導(dǎo)致 load 很高
此時服務(wù)并不能完全相信注冊中心的通知的地址,推送的地址中,可能存在一些服務(wù)質(zhì)量低下的服務(wù)提供者,因此客戶端需要自己根據(jù)調(diào)用的結(jié)果來判斷服務(wù)地址的可用性與提供服務(wù)質(zhì)量的好壞,來定向忽略某些地址。
微服務(wù)治理中心提供離群實(shí)例摘除
-
默認(rèn)無侵入,支持市面上近五年來的 Spring Cloud 與 Dubbo 框架
-
無關(guān)注冊中心實(shí)現(xiàn),無需升級 client 版本
-
基于異常檢測的摘除策略:包含網(wǎng)絡(luò)異常和網(wǎng)絡(luò)異常 + 業(yè)務(wù)異常(HTTP 5xx)
-
設(shè)置異常閾值、QPS 下限、摘除比例下限
-
摘除事件通知、釘釘群告警
離群實(shí)例摘除的能力是一個補(bǔ)充,根據(jù)特定接口的調(diào)用異常特征,來衡量服務(wù)的可用性。
動手實(shí)踐
前提條件
-
已創(chuàng)建 Kubernetes 集群,請參見創(chuàng)建 Kubernetes 托管版集群 [1] 。
-
已開通 MSE 微服務(wù)治理專業(yè)版,請參見開通?MSE 微服務(wù)治理 [2] 。
準(zhǔn)備工作
開啟 MSE 微服務(wù)治理
1、開通微服務(wù)治理專業(yè)版:
2、安裝 MSE 微服務(wù)治理組件:
3、為應(yīng)用開啟微服務(wù)治理:
部署 Demo 應(yīng)用程序
部署示例應(yīng)用(springcloud)
YAML:
# 開啟推空保護(hù)的 sc-consumerapiVersion: apps/v1kind: Deploymentmetadata:name: sc-consumerspec:replicas: 1selector:matchLabels:app: sc-consumertemplate:metadata:annotations:msePilotCreateAppName: sc-consumerlabels:app: sc-consumerspec:containers:- env:- name: JAVA_HOMEvalue: /usr/lib/jvm/java-1.8-openjdk/jre- name: spring.cloud.nacos.discovery.server-addrvalue: nacos-server:8848- name: profiler.micro.service.registry.empty.push.reject.enablevalue: "true"image: registry.cn-hangzhou.aliyuncs.com/mse-demo-hz/demo:sc-consumer-0.1imagePullPolicy: Alwaysname: sc-consumerports:- containerPort: 18091livenessProbe:tcpSocket:port: 18091initialDelaySeconds: 10periodSeconds: 30# 無推空保護(hù)的sc-consumer-empty---apiVersion: apps/v1kind: Deploymentmetadata:name: sc-consumer-emptyspec:replicas: 1selector:matchLabels:app: sc-consumer-emptytemplate:metadata:annotations:msePilotCreateAppName: sc-consumer-emptylabels:app: sc-consumer-emptyspec:containers:- env:- name: JAVA_HOMEvalue: /usr/lib/jvm/java-1.8-openjdk/jre- name: spring.cloud.nacos.discovery.server-addrvalue: nacos-server:8848image: registry.cn-hangzhou.aliyuncs.com/mse-demo-hz/demo:sc-consumer-0.1imagePullPolicy: Alwaysname: sc-consumer-emptyports:- containerPort: 18091livenessProbe:tcpSocket:port: 18091initialDelaySeconds: 10periodSeconds: 30# sc-provider---apiVersion: apps/v1kind: Deploymentmetadata:name: sc-providerspec:replicas: 1selector:matchLabels:app: sc-providerstrategy:template:metadata:annotations:msePilotCreateAppName: sc-providerlabels:app: sc-providerspec:containers:- env:- name: JAVA_HOMEvalue: /usr/lib/jvm/java-1.8-openjdk/jre- name: spring.cloud.nacos.discovery.server-addrvalue: nacos-server:8848image: registry.cn-hangzhou.aliyuncs.com/mse-demo-hz/demo:sc-provider-0.3imagePullPolicy: Alwaysname: sc-providerports:- containerPort: 18084livenessProbe:tcpSocket:port: 18084initialDelaySeconds: 10periodSeconds: 30# Nacos Server---apiVersion: apps/v1kind: Deploymentmetadata:name: nacos-serverspec:replicas: 1selector:matchLabels:app: nacos-servertemplate:metadata:labels:app: nacos-serverspec:containers:- env:- name: MODEvalue: standaloneimage: nacos/nacos-server:latestimagePullPolicy: Alwaysname: nacos-serverdnsPolicy: ClusterFirstrestartPolicy: Always# Nacos Server Service 配置---apiVersion: v1kind: Servicemetadata:name: nacos-serverspec:ports:- port: 8848protocol: TCPtargetPort: 8848selector:app: nacos-servertype: ClusterIP我們只需在 Consumer 增加一個環(huán)境變量?profiler.micro.service.registry.empty.push.reject.enable=true,開啟注冊中心的推空保護(hù)(無需升級注冊中心的客戶端版本,無關(guān)注冊中心的實(shí)現(xiàn),支持 MSE 的 Nacos、eureka、zookeeper 以及自建的 Nacos、eureka、console、zookeeper 等)
分別給 Consumer 應(yīng)用增加 SLB 用于公網(wǎng)訪問
以下分別使用 {sc-consumer-empty} 代表 sc-consumer-empty 應(yīng)用的 slb 的公網(wǎng)地址,{sc-consumer} 代表 sc-consumer 應(yīng)用的 slb 的公網(wǎng)地址。
應(yīng)用場景
下面通過上述準(zhǔn)備的 Demo 來分別實(shí)踐以下場景
- 編寫測試腳本
vi curl.sh
while :doresult=`curl $1 -s`if [[ "$result" == *"500"* ]]; thenecho `date +%F-%T` $resultelseecho `date +%F-%T` $resultfisleep 0.1done- 測試,分別開兩個命令行,執(zhí)行如下腳本,顯示如下
% sh curl.sh {sc-consumer-empty}:18091/user/rest2022-01-19-11:58:12 Hello from [18084]10.116.0.142!2022-01-19-11:58:12 Hello from [18084]10.116.0.142!2022-01-19-11:58:12 Hello from [18084]10.116.0.142!2022-01-19-11:58:13 Hello from [18084]10.116.0.142!2022-01-19-11:58:13 Hello from [18084]10.116.0.142!2022-01-19-11:58:13 Hello from [18084]10.116.0.142!
% sh curl.sh {sc-consumer}:18091/user/rest2022-01-19-11:58:13 Hello from [18084]10.116.0.142!2022-01-19-11:58:13 Hello from [18084]10.116.0.142!2022-01-19-11:58:13 Hello from [18084]10.116.0.142!2022-01-19-11:58:14 Hello from [18084]10.116.0.142!2022-01-19-11:58:14 Hello from [18084]10.116.0.142!2022-01-19-11:58:14 Hello from [18084]10.116.0.142!
并保持腳本一直在調(diào)用,觀察 MSE?控制臺分別看到如下情況
- 將 coredns 組件縮容至數(shù)量 0,模擬 DNS 網(wǎng)絡(luò)解析異常場景。
發(fā)現(xiàn)實(shí)例與 Nacos 的連接斷開且服務(wù)列表為空。
- 模擬 DNS 服務(wù)恢復(fù),將其擴(kuò)容回數(shù)量 2。
結(jié)果驗(yàn)證
在以上過程中保持持續(xù)的業(yè)務(wù)流量,我們發(fā)現(xiàn) sc-consumer-empty 服務(wù)出現(xiàn)大量且持續(xù)的報錯
2022-01-19-12:02:37 {“timestamp”:“2022-01-19T04:02:37.597+0000”,“status”:500,“error”:“Internal Server Error”,“message”:“com.netflix.client.ClientException: Load balancer does not have available server for client: mse-service-provider”,“path”:"/user/feign"}2022-01-19-12:02:37 {“timestamp”:“2022-01-19T04:02:37.799+0000”,“status”:500,“error”:“Internal Server Error”,“message”:“com.netflix.client.ClientException: Load balancer does not have available server for client: mse-service-provider”,“path”:"/user/feign"}2022-01-19-12:02:37 {“timestamp”:“2022-01-19T04:02:37.993+0000”,“status”:500,“error”:“Internal Server Error”,“message”:“com.netflix.client.ClientException: Load balancer does not have available server for client: mse-service-provider”,“path”:"/user/feign"}
相比之下,sc-consumer 應(yīng)用全流程沒有任何報錯
- 只有重啟了 Provider,sc-consumer-empty 才恢復(fù)正常
相比之下,sc-consumer 應(yīng)用全流程沒有任何報錯
后續(xù)
我們當(dāng)發(fā)生推空保護(hù)后,我們會上報事件、告警至釘釘群,同時建議配合離群實(shí)例摘除使用,推空保護(hù)可能會導(dǎo)致 Consumer 持有過多的 Provider 地址,當(dāng) Provider 地址為無效地址時,離群實(shí)例摘除可以對其進(jìn)行邏輯隔離,保證業(yè)務(wù)的高可用。
尾
保障云上業(yè)務(wù)的永遠(yuǎn)在線,是 MSE 一直在追求的目標(biāo),本文通過面向失敗設(shè)計的服務(wù)發(fā)現(xiàn)高可用能力的分享,以及 MSE 的服務(wù)治理能力快速構(gòu)建起服務(wù)發(fā)現(xiàn)高可用能力的演示,模擬了線上不可預(yù)期的服務(wù)發(fā)現(xiàn)相關(guān)異常發(fā)生時的影響以及我們?nèi)绾晤A(yù)防的手段,展示了一個簡單的開源微服務(wù)應(yīng)用應(yīng)該如何構(gòu)建起服務(wù)發(fā)現(xiàn)高可用能力。
相關(guān)鏈接
[1] 創(chuàng)建 Kubernetes 托管版集群
https://help.aliyun.com/document_detail/95108.htm#task-skz-qwk-qfb
[2] 開通?MSE 微服務(wù)治理
https://help.aliyun.com/document_detail/347625.htm#task-2140253
[3] 開通?MSE 微服務(wù)治理
https://common-buy.aliyun.com/?commodityCode=mse_basic_public_cn
[4]?價格說明
?https://help.aliyun.com/document_detail/170443.htm#concept-2519524?
[5]?容器服務(wù)控制臺
?https://cs.console.aliyun.com?
[6]?MSE 治理中心控制臺
?https://mse.console.aliyun.com?
?點(diǎn)擊???此處??,前往 MSE 官網(wǎng)查看更多!?
總結(jié)
以上是生活随笔為你收集整理的如何快速构建服务发现的高可用能力的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Spring Boot Serverle
- 下一篇: 国内唯一,阿里云容器服务进入 Forre