改了 Nacos 一行配置,搞崩線上支付系統(tǒng)!
節(jié)前上線出問題,線上灰度發(fā)布后部分用戶反饋付款后訂單狀態(tài)不更新,支付服務(wù)的失敗率飆升。一頓排查后發(fā)現(xiàn)致命配置錯(cuò)誤。小可愛上線時(shí),將payment-service服務(wù)的 Nacos 注冊(cè)類型改成了ephemeral=false(持久化實(shí)例)。
當(dāng)時(shí)其中一臺(tái)服務(wù)節(jié)點(diǎn)因內(nèi)存泄漏頻繁 GC,心跳線程被阻塞超過 30 秒,但是由于持久化實(shí)例沒被 Nacos 剔除,導(dǎo)致調(diào)用方持續(xù)往這臺(tái)異常節(jié)點(diǎn)發(fā)請(qǐng)求,最終拖垮整個(gè)支付鏈路。
這個(gè)面試場(chǎng)景題總問,不過很多同學(xué)對(duì) Nacos 臨時(shí)、持久實(shí)例的認(rèn)知,只停留在服務(wù)會(huì)不會(huì)消失的表面,什么時(shí)候該用臨時(shí),什么時(shí)候該用持久,適用場(chǎng)景是什么,沒太明白。
注冊(cè)中心和配置中心本質(zhì)區(qū)別
我們用 Nacos 主要使用到它的服務(wù)注冊(cè)中心和配置中心,它們的設(shè)計(jì)初衷不同,服務(wù)注冊(cè)中心要求符合 CAP 中的高可用(AP)服務(wù)發(fā)現(xiàn)不能中斷,允許短暫數(shù)據(jù)不一致;注冊(cè)中心要求是一致性(CP),配置不能錯(cuò)、不能丟,更新需同步到所有節(jié)點(diǎn)。
簡(jiǎn)單說,注冊(cè)中心的實(shí)例是活的服務(wù)節(jié)點(diǎn),配置中心的實(shí)例是死的配置文件。
它們之間的實(shí)例的概念也不太一樣:
對(duì)比維度 | 服務(wù)注冊(cè)中心的實(shí)例 | 配置中心的實(shí)例 |
本質(zhì) | 運(yùn)行中的服務(wù)節(jié)點(diǎn)(如 | 靜態(tài)配置數(shù)據(jù)單元(如 |
核心作用 | 提供服務(wù)發(fā)現(xiàn),讓調(diào)用方找到可用節(jié)點(diǎn) | 集中管理配置,支持動(dòng)態(tài)更新 |
創(chuàng)建方式 | 客戶端自動(dòng)注冊(cè)(如 Spring Cloud 服務(wù)啟動(dòng)時(shí)) | 手動(dòng)創(chuàng)建(控制臺(tái) / API)或代碼推送 |
生命周期依賴 | 依賴服務(wù)節(jié)點(diǎn)的運(yùn)行狀態(tài)(節(jié)點(diǎn)宕機(jī)則實(shí)例失效) | 依賴手動(dòng)維護(hù)(不刪就一直存在) |
注冊(cè)中心:默認(rèn)臨時(shí)實(shí)例
要知道服務(wù)注冊(cè)中心的核心需求是實(shí)時(shí)感知服務(wù)可用性。
它設(shè)計(jì)了臨時(shí)實(shí)例和持久化實(shí)例兩種模式,分別對(duì)應(yīng)動(dòng)態(tài)服務(wù)和靜態(tài)服務(wù)場(chǎng)景。
臨時(shí)實(shí)例
臨時(shí)實(shí)例是 Nacos 服務(wù)注冊(cè)的默認(rèn)模式。
Spring Cloud、Dubbo 等業(yè)務(wù)服務(wù)啟動(dòng)時(shí),若不額外配置,都會(huì)以臨時(shí)實(shí)例注冊(cè)。核心邏輯是心跳保活,來檢測(cè)服務(wù)的可用性。
- 心跳機(jī)制:客戶端每 5 秒向 Nacos 服務(wù)端發(fā)送一次心跳;服務(wù)端 15 秒沒收到心跳,就把實(shí)例標(biāo)記為不健康;30 秒沒收到,直接從注冊(cè)表中剔除實(shí)例;
- 存儲(chǔ)方式:實(shí)例信息只存在服務(wù)端內(nèi)存中,不寫磁盤。Nacos 重啟后,所有臨時(shí)實(shí)例都會(huì)消失,需客戶端重新注冊(cè);
- 故障表現(xiàn):服務(wù)節(jié)點(diǎn)宕機(jī)、網(wǎng)絡(luò)中斷,或像我們支付服務(wù)那樣因 GC 阻塞心跳,實(shí)例會(huì)被自動(dòng)摘除,調(diào)用方不會(huì)再路由到無效節(jié)點(diǎn)。
持久化實(shí)例
持久化實(shí)例則完全相反,它針對(duì)長(zhǎng)期穩(wěn)定運(yùn)行、很少變化的基礎(chǔ)服務(wù)(如 MySQL、Redis、Elasticsearch)設(shè)計(jì),核心邏輯是服務(wù)端主動(dòng)探活 + 數(shù)據(jù)持久化,不適合支付、訂單這類動(dòng)態(tài)業(yè)務(wù)服務(wù)。
- ?;顧C(jī)制:不需要客戶端發(fā)心跳,而是 Nacos 服務(wù)端主動(dòng)探活。支持 TCP 端口探測(cè)(如 MySQL 的 3306 端口)、HTTP 接口探測(cè)(如 Redis 的 /health 接口)、自定義協(xié)議探測(cè);
- 存儲(chǔ)方式:實(shí)例信息會(huì)持久化到 Nacos 的數(shù)據(jù)庫(默認(rèn) Derby,生產(chǎn)用 MySQL),即使 Nacos 重啟,實(shí)例信息也不會(huì)丟失;
- 故障表現(xiàn):實(shí)例宕機(jī)后,Nacos 只會(huì)把它標(biāo)記為不健康,不會(huì)刪除。運(yùn)維能在控制臺(tái)實(shí)時(shí)看到故障節(jié)點(diǎn),方便排查,恢復(fù)后實(shí)例自動(dòng)變回健康。
在 SpringCloud 項(xiàng)目中,只需在application.yml中添加一行配置,就能切換實(shí)例類型,就是這行配置,被新人改錯(cuò)導(dǎo)致了故障:
spring:
cloud:
nacos:
discovery:
server-addr:192.168.1.100:8848
ephemeral:false# 新人誤改為此值,正確應(yīng)為true(默認(rèn))
service:payment-service# 注冊(cè)的服務(wù)名配置中心:默認(rèn)持久化
Nacos 配置中心的所有配置實(shí)例(即配置文件)默認(rèn)都是持久化的,根本不存在臨時(shí)配置的概念,所謂的動(dòng)態(tài)更新也和臨時(shí)無關(guān)。
Nacos 配置中心的設(shè)計(jì)初衷是集中管理配置,避免配置丟失,因此所有配置都滿足以下特性:
- 存儲(chǔ)層面:無論在控制臺(tái)創(chuàng)建、還是用 API 推送的配置,都會(huì)持久化到數(shù)據(jù)庫(如 MySQL),即使 Nacos 服務(wù)端重啟、甚至服務(wù)器宕機(jī),配置也不會(huì)丟失;
- 生命周期:配置只會(huì)被手動(dòng)刪除或覆蓋更新,不會(huì)因?yàn)榭蛻舳藬嚅_連接、或服務(wù)重啟而自動(dòng)消失;
- 動(dòng)態(tài)更新:客戶端通過長(zhǎng)輪詢機(jī)制監(jiān)聽配置變化(默認(rèn)每 30 秒輪詢一次,可調(diào)整),配置更新后 1 秒內(nèi)推送到客戶端。但動(dòng)態(tài)更新是 內(nèi)容實(shí)時(shí)變化,不是配置臨時(shí)存在。
寫在最后
說了一大堆其實(shí)總結(jié)起來就兩句話:
- 服務(wù)注冊(cè)中心:動(dòng)態(tài)業(yè)務(wù)服務(wù)(支付、訂單)用臨時(shí)實(shí)例(默認(rèn)),靜態(tài)基礎(chǔ)組件(MySQL、Redis)用持久化實(shí)例;
- 配置中心:沒有臨時(shí)配置,所有配置默認(rèn)持久化,動(dòng)態(tài)更新 ≠ 臨時(shí)存在。
讀到這就等于學(xué)會(huì)!






























