Kubernetes集群中SpringBoot服務(wù)的健康探測(cè)優(yōu)化

2021年8月9日16:52:05 發(fā)表評(píng)論 3,512 ℃

今天在維護(hù)預(yù)生產(chǎn)環(huán)境的數(shù)據(jù)庫(kù)的時(shí)候,發(fā)生了一個(gè)災(zāi)難性的故障(還好不是生產(chǎn)環(huán)境),集群中除了eureka和zuul的其他服務(wù)全部springboot服務(wù)都變成了不可用狀態(tài),容器在不停的重啟中,出現(xiàn)這種情況,一般是Liveness和Readiness健康檢查失敗了。

Kubernetes集群中SpringBoot服務(wù)的健康探測(cè)優(yōu)化

為什么會(huì)出現(xiàn)這樣雪崩式的故障?接下來(lái)阿湯博客就kubernetes自愈和springboot健康檢查分享下具體原因。

一、Kubernetes自愈

Kubernetes強(qiáng)大的自愈能力毋容置疑,如何自愈?默認(rèn)實(shí)現(xiàn)方式是自動(dòng)重啟發(fā)生故障的容器,在非kubernetes集群中,要實(shí)現(xiàn)自愈是非常困難的一件事情。

那怎么判定容器發(fā)生了故障呢?kubernetes提供了Liveness和Readiness 探測(cè)機(jī)制,檢測(cè)容器的健康度。

Liveness 探測(cè)讓用戶可以自定義判斷容器是否健康的條件。如果探測(cè)失敗,Kubernetes 就會(huì)重啟容器,實(shí)現(xiàn)自愈。

Readiness 探測(cè)則是告訴 Kubernetes 什么時(shí)候可以將容器加入到 Service 負(fù)載均衡池中,對(duì)外提供服務(wù)。

Liveness VS Readiness 探測(cè)

1、Liveness 探測(cè)和 Readiness 探測(cè)是兩種 Health Check 機(jī)制,如果不特意配置,Kubernetes 將對(duì)兩種探測(cè)采取相同的默認(rèn)行為,即通過(guò)判斷容器啟動(dòng)進(jìn)程的返回值是否為零來(lái)判斷探測(cè)是否成功。

2、兩種探測(cè)的配置方法完全一樣,支持的配置參數(shù)也一樣。不同之處在于探測(cè)失敗后的行為:Liveness 探測(cè)是重啟容器;Readiness 探測(cè)則是將容器設(shè)置為不可用,不接收 Service 轉(zhuǎn)發(fā)的請(qǐng)求。

3、Liveness 探測(cè)和 Readiness 探測(cè)是獨(dú)立執(zhí)行的,二者之間沒(méi)有依賴(lài),所以可以單獨(dú)使用,也可以同時(shí)使用。用 Liveness 探測(cè)判斷容器是否需要重啟以實(shí)現(xiàn)自愈;用 Readiness 探測(cè)判斷容器是否已經(jīng)準(zhǔn)備好對(duì)外提供服務(wù)。

我們項(xiàng)目健康探測(cè)配置:

readinessProbe:
  initialDelaySeconds: 10
  periodSeconds: 12
  timeoutSeconds: 2
  successThreshold: 1
  failureThreshold: 3
  httpGet:
    path: /health
    port: 8080
livenessProbe:
  initialDelaySeconds: 300
  periodSeconds: 12
  timeoutSeconds: 2
  successThreshold: 1
  failureThreshold: 3
  httpGet:
    path: /health
    port: 8080

二、SpringBoot的spring boot actuator中的監(jiān)控檢查機(jī)制

springboot服務(wù)中引用了依賴(lài)

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

以后,對(duì)應(yīng)的服務(wù)就提供了端點(diǎn)/health。

Actuator 的 health 端點(diǎn)是主要用來(lái)檢查應(yīng)用的運(yùn)行狀態(tài),我們項(xiàng)目在kubernetes集群中也是使用此端點(diǎn)對(duì)springboot服務(wù)做的健康狀態(tài)檢測(cè)。

由于今天之前一直沒(méi)對(duì)Actuator 的 health 深入研究,導(dǎo)致出現(xiàn)了今天的雪崩故障。這也是為什么我維護(hù)數(shù)據(jù)庫(kù)的時(shí)候,導(dǎo)致所有服務(wù)都出現(xiàn)了不可用,無(wú)限重啟的情況。

故障一開(kāi)始雖然知道是健康檢查失敗了,但還是充滿了疑惑,為什么失敗呢?因?yàn)檫@期間除了維護(hù)了數(shù)據(jù)庫(kù),沒(méi)做其他操作。

于是停掉了開(kāi)發(fā)環(huán)境的數(shù)據(jù)庫(kù),馬上去查看開(kāi)發(fā)環(huán)境springboot服務(wù)pod的狀態(tài),沒(méi)過(guò)多久服務(wù)全部為不可用狀態(tài),然后就開(kāi)始重啟容器嘗試恢復(fù)。

經(jīng)過(guò)反復(fù)測(cè)試,發(fā)現(xiàn)只要數(shù)據(jù)庫(kù)一停,服務(wù)的/health端點(diǎn),返回的就是DOWN狀態(tài)。

我去查閱了關(guān)于spring boot actuator健康檢查相關(guān)的文章,原來(lái)默認(rèn)情況下/health端點(diǎn)會(huì)檢測(cè)數(shù)據(jù)庫(kù)連接、Redis鏈接、RocketMQ、diskSpace等等這些和服務(wù)相關(guān)的中間組件的狀態(tài),只要有一個(gè)不正常,則健康檢查為失敗。

Spring Boot自帶的健康指示器
名稱(chēng) 描述
ApplicationHealthIndicator none 永遠(yuǎn)為up
DataSourceHealthIndicator db 如果數(shù)據(jù)庫(kù)能連上,則內(nèi)容是up和數(shù)據(jù)類(lèi)型,否則為DOWN
DiskSpaceHealthIndicator diskSpace 如果可用空間大于閾值,則內(nèi)容為UP和可用磁盤(pán)空間,如果空間不足則為DOWN
JmsHealthIndicator jms 如果能連上消息代理,則內(nèi)容是up和JMS提供方的名稱(chēng),否則為DOWN
MailHealthIndicator mail 如果能連上郵件服務(wù)器,則內(nèi)容是up和郵件服務(wù)器主機(jī)和端口,否則為DOWN
MongoHealthIndicator mongo 如果能連上MongoDB服務(wù)器,則內(nèi)容是up和MongoDB服務(wù)器版本,否則為DOWN
RabbitHealthIndicator rabbit 如果能連上RabbitMQ服務(wù)器,則內(nèi)容是up和版本號(hào),否則為DOWN
RedisHealthIndicator redis 如果能連上服務(wù)器,則內(nèi)容是up和Redis服務(wù)器版本,否則為DOWN
SolrHealthIndicator solr 如果能連上solr服務(wù)器,則內(nèi)容是up,否則為DOWN

因?yàn)槲襆iveness和Readiness探測(cè)都采用的spring boot actuator的/health端點(diǎn),所以當(dāng)我停掉mysql以后,所有使用了mysql的服務(wù)監(jiān)控檢查全部為DOWN狀態(tài),導(dǎo)致觸發(fā)了kubernetes的重啟自愈。

這樣就導(dǎo)致所有服務(wù)都會(huì)不停的重啟,導(dǎo)致服務(wù)器CPU一直處于滿負(fù)載,然后就形成了連鎖反應(yīng),可能會(huì)導(dǎo)致其他pod因?yàn)榻】禉z查超時(shí),出現(xiàn)失敗,然后又重啟的情況。

有了上面的問(wèn)題,就需要對(duì)當(dāng)前的健康檢測(cè)配置進(jìn)行優(yōu)化調(diào)整。

優(yōu)化思路:

當(dāng)redis、mysql、MQ等中間服務(wù)出現(xiàn)短暫的網(wǎng)絡(luò)超時(shí)或者不可用時(shí),此時(shí)服務(wù)只是無(wú)法正常處理請(qǐng)求,本身并沒(méi)有出現(xiàn)致命故障(比如:OOM),重啟服務(wù)也無(wú)法恢復(fù)正常。

所以此時(shí)不應(yīng)該讓kubernetes去重啟容器,只需要讓他把容器標(biāo)記為不可用即可,等網(wǎng)絡(luò)、或者相關(guān)中間件恢復(fù)正常再標(biāo)記為可用狀態(tài),提供正常服務(wù)即可。

優(yōu)化以后:

readinessProbe:
  initialDelaySeconds: 10
  periodSeconds: 12
  timeoutSeconds: 2
  successThreshold: 1
  failureThreshold: 3
  httpGet:
    path: /health
    port: 8080
livenessProbe:
  initialDelaySeconds: 300
  periodSeconds: 12
  timeoutSeconds: 2
  successThreshold: 1
  failureThreshold: 3
  tcpSocket:  #或者使用httpGet path為/info
    port: 8080

由于我們的springboot服務(wù)并不是通過(guò)kubernetes的service去提供對(duì)外服務(wù),標(biāo)記為不可用以后沒(méi)有什么實(shí)際意義,eureka server本身自己會(huì)對(duì)注冊(cè)中的服務(wù)做健康狀態(tài)檢測(cè),剔除不健康的服務(wù)。

這里需要注意,默認(rèn)情況下eureka-server并不是通過(guò)spring boot actuator的/health端點(diǎn)進(jìn)行健康狀態(tài)探測(cè),而是探測(cè)eureka client進(jìn)程是否正常運(yùn)行。

所以數(shù)據(jù)庫(kù)、redis等出現(xiàn)故障,默認(rèn)情況eureka 并不會(huì)把服務(wù)標(biāo)記為down,我們需要在服務(wù)配置中添加eureka.client.healthcheck.enabled=true讓eureka使用spring boot actuator的/health端點(diǎn)來(lái)對(duì)服務(wù)做健康探測(cè)。

【騰訊云】云服務(wù)器、云數(shù)據(jù)庫(kù)、COS、CDN、短信等云產(chǎn)品特惠熱賣(mài)中

發(fā)表評(píng)論

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: