服務應用突然當機了?別怕,Dubbo 幫你自動搞定服務隔離!

樓下小黑哥發表於2020-08-28

聽說貓貓可以增加點選量

某日中午,午睡正香的時候,接到系統的報警電話,提示生產某物理機異常當機了,目前該物理機已恢復,需要重啟上面部署的應用。

這時瞬間沒有了睡意,登上堡壘機,快速重啟了應用,系統恢復正常。本想著繼續午睡,但是已經沒有了睡意。

旁邊的小師弟(我們叫他小灰吧)剛才在我們邊上,目睹這一切,然後向我請教個問題。

小灰:

黑哥,剛才應用突然當機,會不會對交易有影響啊?

小黑:

影響確實會有,不過也不大,就當時應用正在執行那些那些交易會受到影響。

小灰:

不對啊,我們現在系統架構是下面這樣。

我們這次當機的是業務邏輯層,那按照目前使用 Dubbo 輪詢的負載均衡方式,不是還會有交易分發到當機那臺應用上,這些交易請求顯然會異常。

運氣差點,不是會有一半交易請求都會有問題嗎?

小黑:

沒錯,我們的系統架構圖確實如說的一樣。

不過你說的這個問題,它是不存在的。

這是因為 Dubbo 內部會自動幫我們的摘除當機的應用節點。

小灰:

啥?Dubbo 內部還有這功能啊?黑哥你給我講講原理唄!

小黑:

可以啊,不過講這個原理之前,我們首先需要了解 Dubbo 服務註冊發現流程。

我看你最近一直在看『深入理解 Apache Dubbo 與實戰』,這本書確實不錯,裡面框架原理,程式碼細節都講的很透徹。

你應該已經瞭解了 Dubbo 服務註冊發現流程,那你先跟我簡單講講原理吧。

小灰拿起紙筆,在上面畫了個圖:

Dubbo 服務註冊發現流程

恩,我當前瞭解的還不是很深,那我先聊聊目前我知道的。

我們目前使用 ZooKeeper 當做服務註冊中心,ZooKeeper 可以簡單理解成是一個 KV系統,內部是一個樹形的資料結構。

Dubbo 預設將會在 ZooKeeper 中建立一個四層的資料結構,從上到下分別為:

  • Root
  • Service
  • Category
  • URL

其中 Root 層是註冊中心分組,預設命名為 dubbo。我們可以通過修改 <dubbo:registry> 中的 group 屬性修改預設值,這樣修改之後不同分組的 dubbo 服務不會互相影響,也不會互相呼叫,可以用於環境隔離。

接下來 Service 就是服務類的全路徑,包括包路徑。

Service 層下面就是 Category 層,這其中總共有四類目錄(上面圖形只畫了兩種),分別為:

  • providers:包含服務提供者 URL 後設資料資訊
  • consumers:包含消費者 URL 後設資料資訊
  • routers:包含消費者路由策略的 URL 後設資料資訊
  • configurators:包含動態配置後設資料資訊

最後一層就是具體 Dubbo 服務 URL,類似如下:

dubbo://2.0.1.13:12345/com.dubbo.example.DemoService?xx=xx

小黑:

沒錯,這個內部結構你理還是蠻清晰的麼!

平常使用的情況下,我們重點關注 providers 以及 consumers 就好了。如果我們需要配置服務路由資訊以及動態配置,那我們需要在 Dubbo-Admin 服務治理中心下發配置。這時 routersconfigurators 就會增加相關配置。

小灰:

嘿嘿?,我們接下來講服務註冊流程。

當服務提供者啟動之後,會向註冊中心寫入自己的後設資料資訊,其實就是在 providers 節點下建立一個 URL 節點(如果上級節點都不存在,將會逐層建立),儲存值類似如下:

dubbo://10.10.11.22:20880/com.foo/BarService?key=value....

接著啟動服務消費者,消費者第一次連線上 ZooKeeper 時,將會拉取provider 節點下所有服務提供者的 URL 資訊,然後與相應的服務提供者建立連線。

同時服務消費者也會將自己資訊註冊到在 consumer 節點下,這個目的是為了服務治理中心(Dubbo-Admin)發現自己。

同時消費者將會在 provider 節點上註冊一個 watcher ,當有新的服務提供者啟動成功,provider 節點發生變更,ZooKeeper 將會推送變更資訊給 Dubbo 服務,然後 Dubbo 將會重新建立與服務提供者的連線。

小黑:

你說的整個 Dubbo 服務註冊發現流程沒有什麼問題,這裡消費者與服務提供者建立的連線的流程,我們之前踩過一個坑,你有空可以看看 天啦嚕!生產機器連線數飆升到上萬,背後發生了什麼?

另外,再考你一下:

服務節點變更時,ZooKeeper 推送 provider 下全量子節點資料給消費者嗎?

小灰:

呀,難道不是嗎?

小黑:

不是的。ZooKeeper 的 watch 機制目前只能推送節點變更資訊,比如節點內容資料變更,監聽節點下子節點列表變更等,具體如下圖:

圖片來自網路

進一步從 Zookeeper 客戶端的原始碼上來看,watcher 回撥通知內容最終轉為 WatchedEvent

image-20200823204259983

這個類只有三個欄位,所以是不會推送子節點列表資料過來。

小灰:

既然不是通過推送獲取子節點列表的資訊,那如何拿到變動子節點列表?

有了,在收到推送的時候,我們能獲取到變動節點資訊,然後我再拉取一下子節點的列表不就好了!

小黑:

沒錯,Dubbo 就是這麼做的。

這一點我們可以具體看下 Dubbo 的原始碼,位於 CuratorZookeeperClient

畫外音:下面的原始碼基於 Dubbo 2.6.7

圖中標註的地方,Dubbo 通過拉取獲取了位元組點的全量資料,同時再次註冊了一個 watcher

不過這麼多,有個缺陷的,當微服務節點數量有很多的時候,全量拉取將會佔用過多的內網頻寬,很容易造成網路風暴。

上面我們講到 Zookeeper 的這種方式,是一種典型的 Push 模式,對應的還有一種的模式為 Pull 模式,eureka 就是這種模式的典型的代表。

eureka 客戶端就是通過定期輪詢拉取資料,獲取最新的變更資料。不過拉取模式也存在很大的劣勢,如果輪詢頻率低,那麼服務變更資訊無法及時獲取,如果輪率太高這就會增加註冊中心的壓力。

小黑:

服務發現流程這下我們已經搞明白了。如果有新增服務節點,Dubbo 消費者通過通知,然後再拉取全量的子節點列表,這樣 Dubbo消費者就會新增與新的服務提供者連線,後續再通過負載均衡使用新的連線。

如果 Dubbo 服務提供者正常停止下線,那麼他將會刪除 ZooKeeper 上的自己註冊的節點資訊。刪除之後 Dubbo 消費者第一時間收到了通知,通過拉取全量的子節點列表,然後通過比對,發現某個節點下線,然後刪除之前簡歷的連線。這樣後續,就不會再呼叫這個節點。

小灰:

恩,正常應用上下線,Dubbo 消費者可以感知到,但是像服務提供者當機的情況,消費者是怎麼感知到的?

小黑:

這一點,就與 Zookeeper 的自身特性有關了。

Zookeeper 中我們可以建立四種節點型別的節點:

  • 永久節點
  • 臨時節點
  • 順序節點
    • 永久節點
    • 臨時節點

臨時節點與永久節點唯一的區別在於,一旦 Zookeeper 客戶端斷開連線,Zookeeper 服務感知到之後就會自動刪除臨時節點。

Dubbo 服務提供者就是在 Zookeeper 註冊了臨時節點,如果服務提供者當機了,臨時節點自動被刪除,後面的流程就跟 Dubbo 應用正常下線一樣了。

小灰:

すごい!原來如此,這個設計 666 啊。

小黑:

其實應用當機這種, Dubbo RPC 框架內部都可以自動幫我們處理,這種故障其實很好處理。但是如果碰到下面這這種情況:

  • 服務提供者與服務消費者網路隔離
  • 服務提供陷入緩慢

在服務消費者看來,服務提供者其實是「活著」,這是因為服務提供者與 Zookeeper 還是正常連線。

但是實際情況下,服務消費者其實已經不能正常呼叫服務提供者了,那這種情況就比較棘手了。

不過 Dubbo 內部也提供瞭解決辦法。馬上就上班了,也來不及講了,我們後面再討論!

小灰:

好的,黑哥!今天學到了!

黑哥??!愛你~

幫助連結

  1. https://www.sofastack.tech/blog/sofa-registry-service-discovery-optimization/

歡迎關注我的公眾號:程式通事,獲得日常乾貨推送。如果您對我的專題內容感興趣,也可以關注我的部落格:studyidea.cn

相關文章