1. 程式人生 > 實用技巧 >流量暴增,掌門教育如何基於 Spring Cloud Alibaba 構建微服務體系?

流量暴增,掌門教育如何基於 Spring Cloud Alibaba 構建微服務體系?

作者 | 童子龍  掌門教育基礎架構部架構師

導讀:本文整理自作者於 2020 年雲原生微服務大會上的分享《掌門教育雲原生落地實踐》,本文主要介紹了掌門教育雲原生落地實踐,主要圍繞 Spring Cloud Alibaba & Nacos & Sentinel & Arthas 等微服務雲原生技術棧實施構建,基於 Docker 和 阿里雲 Kubernetes 雲原生容器的實現落地,著重介紹 Nacos 伺服器高可用性部署、監控,Nacos 和 Eureka 同步伺服器高可用雙向同步和容災,以及和 DevOps 運維釋出平臺的整合。

阿里巴巴雲原生公眾號後臺回覆 818 即可獲取直播回看地址和大會 PPT 合集。

背景

掌門教育自 2014 年正式轉型線上教育以來,秉承“讓教育共享智慧,讓學習高效快樂”的宗旨和願景,經歷雲端計算、大資料、人工智慧、 AR / VR / MR 以及現今最火的 5G ,一直堅持用科技賦能教育。掌門教育的業務近幾年得到了快速發展,特別是今年的疫情,使線上教育成為了新的風口,也給掌門教育新的機遇。

隨著業務規模進一步擴大,流量進一步暴增,微服務數目進一步增長,使老的微服務體系所採用的註冊中心 Eureka 不堪重負,同時 Spring Cloud 體系已經演進到第二代,第一代的 Eureka 註冊中心已經不大適合現在的業務邏輯和規模,同時它目前被 Spring Cloud 官方置於維護模式,將不再向前發展。如何選擇一個更為優秀和適用的註冊中心,這個課題就擺在了掌門人的面前。

為什麼選擇 Spring Cloud Alibaba&Nacos

經過對 Alibaba Nacos 、HashiCorp Consul 等開源註冊中心做了深入的調研和比較,以下是各個註冊中心的特性對比:

  • Nacos
    • 支援 AP+CP 一致性共識協議
    • 支援 Agent DNS-F 服務註冊發現方式,跨語言
    • 支援負載均衡,雪崩保護機制
    • 支援多資料中心,跨註冊中心遷移
  • Consul
    • 只支援 CP 協議
    • 支援 HTTP/DNS 協議
  • K8s CoreDns
    • 支援 DNS 協議

結論:Nacos 滿足目前掌門的服務治理技術棧,能實現註冊中心的平滑遷移,社群發展非常活躍,所提供的特性,使得圍繞 Spring Cloud Alibaba&Nacos 能夠非常方便的構建雲原生應用的動態服務註冊發現。

一.Nacos server 落地

1. Nacos Server 部署


(Nacos Server 部署概覽圖)

  • Nacos Server 環境和域名

掌門的應用環境分為 4 套,DEV、FAT、UAT、PROD 分別對應開發、測試、準生產環境、生產環境,因此 Nacos Server 也分為 4 套獨立環境。除了 DEV 環境是單機部署外,其他是叢集方式部署。對外均以域名方式訪問,SLB 做負載均衡,包括 SDK 方式連線 Nacos Server 和訪問 Nacos Server Dashboard 控制檯頁面。

  • Nacos Server 環境隔離和呼叫隔離

Nacos 資料模型由 namespace / group / service 構成。 可以通過建立不同的名稱空間,做到同一個應用環境的基礎上更細粒度的劃分,隔離服務註冊和發現。在某些場景下,開發本地有需要連線測試環境的 Nacos Server ,但其他測試服務不能呼叫到開發本地,這時候可以將 NacosDiscoveryProperties 的 enabled 屬性設定為 false 。

  • Nacos Server 整合 Ldap

Nacos Server Dashboard 整合公司的 Ldap 服務,並在使用者首次登入時記錄使用者資訊。

2. Nacos Server 介面

  • Nacos 介面許可權

Nacos Server Dashboard 使用者首次登陸時,預設分配普通使用者(即非 ROLE_ADMIN )角色,對查詢以外的按鈕均無操作許可權,以免出現誤操作導致服務非正常上下線。

  • Nacos 介面顯示服務概覽

Nacos Server Dashboard 頁面增加服務總數及例項總數的統計,該資訊每 5 秒重新整理一次。

3. Nacos 監控

  • 標準監控

基於公司現有的 Prometheus 、 Grafana 、 AlertManager 從系統層監控 Nacos。

  • 高階監控

根據 Nacos 監控手冊,結合 Prometheus 和 Grafana 監控 Nacos 指標。

  • 服務例項狀態監控

  • 監聽例項下線事件
  • 監聽例項登出事件
  • 監聽例項註冊事件
  • 監聽例項上線事件
  • 監聽例項心跳超時事件

4. Nacos 日誌

  • 日誌合併及 JSON 格式化

將 Nacos 多模組的日誌統一按 info 、 warn、error 級別合併,定義 schema 欄位標記不同模組,按 JSON 格式滾動輸出到檔案,供 ELK 採集展示。

5. Nacos 告警

  • 業務服務上下線的告警

  • 服務名大寫告警

6. Nacos 效能測試

  • 核心指令碼
def registry(ip):
    fo = open("service_name.txt", "r")
    str = fo.read()
    service_name_list = str.split(";")
    service_name = service_name_list[random.randint(0,len(service_name_list) - 1)]
    fo.close()
    client = nacos.NacosClient(nacos_host, namespace='')
    print(client.add_naming_instance(service_name,ip,333,"default",1.0,{'preserved.ip.delete.timeout':86400000},True,True))
    while True:
      print(client.send_heartbeat(service_name,ip,333,"default",1.0,"{}"))
      time.sleep(5)
  • 壓測資料

  • 壓測結果圖

總結:Nacos Server 是 3 臺 1C4G 叢集,同時承受 1499 個服務和 12715 個例項註冊,而且 CPU 和記憶體長期保持在一個合適的範圍內,果真 Nacos 效能是相當 OK 的。

二.Nacos Eureka Sync 落地

1. Nacos Eureka Sync 方案選型

① Sync 官方方案

經過研究,我們採取了官方的 Nacos Eureka Sync 方案,在小範圍試用了一下,效果良好,但一部署到 FAT 環境後,發現根本不行,一臺同步伺服器無法抗住將近 660 個服務(非例項數)的頻繁心跳,同時該方案不具備高可用特點。

② Sync 高可用一致性 Hash + Zookeeper 方案

既然一臺不行,那麼就多幾臺,但如何做高可用呢?

我們率先想到的是一致性 Hash 方式。當一臺或者幾臺同步伺服器掛掉後,採用 Zookeeper 臨時節點的 Watch 機制監聽同步伺服器掛掉情況,通知剩餘同步伺服器執行 reHash ,掛掉服務的工作由剩餘的同步伺服器來承擔。通過一致性 Hash 實現被同步的業務服務列表的平均分配,基於對業務服務名的二進位制轉換作為 Hash 的 Key 實現一致性 Hash 的演算法。我們自研了這套演算法,發現平均分配的很不理想,第一時間懷疑是否演算法有問題,於是找來 Kafka 自帶的演算法(見 Utils.murmur2 ),發現效果依舊不理想,原因還是業務服務名的本身分佈就是不平均的,於是又回到自研演算法上進行了優化,基本達到預期,下文會具體講到。但說實話,直到現在依舊無法做到非常良好的絕對平均。

③ Sync 高可用主備 + Zookeeper 方案

這個方案是個小插曲,當一臺同步伺服器掛掉後,由它的“備”頂上,當然主備切換也是基於 Zookeeper 臨時節點的 Watch 機制來實現的。後面討論下來,主備方案,機器的成本很高,實現也不如一致性 Hash 優雅,最後沒采用。

④ Sync 高可用一致性 Hash + Etcd 方案

折騰了這麼幾次後,發現同步業務服務列表是持久化在資料庫,同步伺服器掛掉後 ReHash 通知機制是由 Zookeeper 來負責,兩者能否可以合併到一箇中間件上以降低成本?於是我們想到了 Etcd 方案,即通過它實現同步業務服務列表持久化 + 業務服務列表增減的通知 + 同步伺服器掛掉後 ReHash 通知。至此方案最終確定,即兩個註冊中心( Eureka 和 Nacos )的雙向同步方案,通過 Etcd 來做橋樑。

2. Nacos Eureka Sync 落地實踐

① Nacos Eureka Sync 目標原則

註冊中心遷移目標:

  • 過程並非一蹴而就的,業務服務逐步遷移的過程要保證線上呼叫不受影響,例如, A 業務服務註冊到 Eureka 上, B 業務服務遷移到 Nacos ,A 業務服務和 B 業務服務的互相呼叫必須正常;
  • 過程必須保證雙註冊中心都存在這兩個業務服務,並且目標註冊中心的業務服務例項必須與源註冊中心的業務服務例項數目和狀態保持實時嚴格一致。

註冊中心遷移原則:

  • 一個業務服務只能往一個註冊中心註冊,不能同時雙向註冊;
  • 一個業務服務無論註冊到 Eureka 或者 Nacos,最終結果都是等效的;
  • 一個業務服務在絕大多數情況下,一般只存在一個同步任務,如果是註冊到 Eureka 的業務服務需要同步到 Nacos,那就有一個 Eureka -> Nacos 的同步任務,反之亦然;在平滑遷移中,一個業務服務一部分例項在 Eureka 上,另一部分例項在 Nacos 上,那麼會產生兩個雙向同步的任務;
  • 一個業務服務的同步方向,是根據業務服務例項元資料( Metadata )的標記 syncSource 來決定。

② Nacos Eureka Sync 問題痛點

  • Nacos Eureka Sync 同步節點需要代理業務服務例項和 Nacos Server 間的心跳上報。Nacos Eureka Sync 將心跳上報請求放入佇列,以固定執行緒消費,一個同步業務服務節點處理的服務例項數超過一定的閾值會造成業務服務例項的心跳傳送不及時,從而造成業務服務例項的意外丟失;
  • Nacos Eureka Sync 節點宕機,上面處理的心跳任務會全部丟失,會造成線上呼叫大面積失敗,後果不堪設想;
  • Nacos Eureka Sync 已經開始工作的時候,從 Eureka 或者 Nacos 上,新上線或者下線一個業務服務(非例項),都需要讓 Nacos Eureka Sync 實時感知。

③ Nacos Eureka Sync 架構思想

  • 從各個註冊中心獲取業務服務列表,初始化業務服務同步任務列表,並持久化到 Etcd 叢集中;
  • 後續遷移過程增量業務服務通過 API 介面持久化到 Etcd 叢集中,業務服務遷移過程整合 DevOps 釋出平臺。整個遷移過程全自動化,規避人為操作造成的遺漏;
  • 同步服務訂閱 Etcd 叢集獲取任務列表,並監聽同步叢集的節點狀態;
  • 同步服務根據存活節點的一致性 Hash 演算法,找到處理任務節點,後端介面通過 SLB 負載均衡,刪除任務指令輪詢到的節點。如果是自己處理任務則移除心跳,否則找到處理節點,代理出去;
  • 同步服務監聽源註冊中心每個業務服務例項狀態,將正常的業務服務例項同步到目標註冊中心,保證雙方註冊中心的業務服務例項狀態實時同步;
  • 業務服務所有例項從 Eureka 到 Nacos 後,需要業務部門通知基礎架構部手動從 Nacos Eureka Sync 同步介面摘除該同步任務。

④ Nacos Eureka Sync 叢集分片及高可用方案

服務一致性 Hash 分片路由:

  • 根據如上圖 1 多叢集部署,為每個節點設定可配置的虛擬節點數,使其在 Hash 環上能均勻分佈;
  • 根據業務服務名的 FNV1_32_HASH 演算法計算每個業務服務的雜湊值,計算該 Hash 值順時針最近的節點,將任務代理到該節點。

同步節點宕機故障轉移:

  • 節點監聽:監聽其它節點存活狀態,配置 Etcd 叢集租約 TTL , TTL 內至少傳送 5 個續約心跳以保證一旦出現網路波動避免造成節點丟失;
  • 節點宕機:其中某個節點宕機,其任務轉移到其它節點,因為有虛擬節點的緣已經故,所以此節點的任務會均衡 ReSharding 到其它節點,那麼,叢集在任何時候,任務處理都是分片均衡的,如上圖 2 中, B 節點宕機, ##1 、 ##2 虛擬節點的任務會分別轉移到 C 和 A 節點,這樣避免一個節點承擔宕機節點的所有任務造成剩餘節點連續雪崩;
  • 節點恢復:如圖 3,節點的虛擬節點重新新增到 Hash 環中, Sharding 規則變更,恢復的節點會根據新的 Hash 環規則承擔其它節點的一部分任務,心跳任務一旦在節點產生都不會自動消失,這時需要清理其它節點的多餘任務(即重新分配給復甦節點的任務),給其它節點減負(這一步非常關鍵,不然也可能會引發叢集的連續雪崩),保障叢集恢復到最初正常任務同步狀態;
  • 節點容災:如果 Etcd 叢集連線不上,則存活節點從配置檔案中獲取,叢集正常運作,但是會失去容災能力。

3. Nacos Eureka Sync 保障手段

① Nacos Eureka Sync 同步介面

從如下介面可以保證,從 Eureka 或者 Nacos 上,新上線或者下線一個業務服務(非例項),都能讓 Nacos Eureka Sync 實時感知。但我們做了更進一層的智慧化和自動化:

  • 新增同步:結合 DevOps 釋出平臺,當一個業務服務(非例項)新上線的時候,智慧判斷它是從哪個註冊中心上線的,然後回撥 Nacos Eureka Sync 介面,自動新增同步介面,例如,A 業務服務註冊到 Eureka 上,DevOps 釋出平臺會自動新增它的 Eureka -> Nacos 的同步任務,反之亦然。當然從如下介面的操作也可實現該功能;

  • 刪除同步:由於 DevOps 釋出平臺無法判斷一個業務服務(非例項)下線,或者已經遷移到另一個註冊中心,已經全部完畢(有同學會反問,可以判斷的,即檢視那個業務服務的例項數是否是零為標準,但我們應該考慮,例項數為零在網路故障的時候也會發生,即心跳全部丟失,所以這個判斷依據是不嚴謹的),交由業務人員來判斷,同時配合釘釘機器人告警提醒,由基礎架構部同學從如下介面的操作實現該功能。

② Nacos Eureka Sync Etcd 監控

從如下介面可以監控到,業務服務列表是否在同步服務的叢集上呈現一致性 Hash 均衡分佈。

③ Nacos Eureka Sync 告警

  • Nacos Eureka Sync 告警

  • 業務服務同步完畢的告警

4.Nacos Eureka Sync 升級演練

  • 7 月某天晚上 10 點開始, FAT 環境進行演練,通過自動化運維工具 Ansible 兩次執行一鍵升級和回滾均沒問題;
  • 晚上 11 點 30 開始,執行災難性操作,觀察智慧恢復狀況, 9 臺 Nacos Eureka Sync 掛掉 3 臺的操作,只丟失一個例項,但 5 分鐘後恢復(經調查,問題定位在 Eureka 上某個業務服務例項狀態異常);
  • 晚上 11 點 45 開始,繼續掛掉 2 臺,只剩 4 臺,故障轉移,同步正常;
  • 晚上 11 點 52 開始,恢復 2 臺,Nacos Eureka Sync 叢集重新均衡 ReHash ,同步正常;
  • 晚上 11 點 55 開始,全部恢復,Nacos Eureka Sync 叢集重新均衡 ReHash ,同步正常;
  • 12 點 14 分,極限災難演練, 9 臺掛掉 8 臺,剩 1 臺也能抗住,故障轉移,同步正常;
  • 凌晨 12 點 22 分,升級 UAT 環境順利;
  • 凌晨 1 點 22,升級 PROD 環境順利;
  • 容災恢復中的 ReHash 時間小於 1 分鐘,即 Nacos Eureka Sync 服務大面積故障發生時,恢復時間小於 1 分鐘。

三.Solar 雲原生微服務實踐


(Solar 雲原生微服務體系)

Solar 微服務體系,囊括微服務治理元件,中介軟體以及基礎元件易用性封裝,告警監控體系等,連線著掌門業務服務和底層基礎設施,每項服務都遵守強有力的合約,向著雲原生微服務架構方向演進。

1. 基於 Spring Cloud Alibaba、Nacos、Sentinel 等 SDK

① Alibaba Nacos

  • Solar Nacos SDK 內建 DEV | FAT | UAT | PROD 四個環境的域名,業務系統無感知 Solar Nacos SDK 基於 Spring Cloud Alibaba 整合攜程 VI Cornerstone 實現微服務點火熄火拉入拉出;
  • Solar Nacos SDK 在 Nacos 和 Eureka 雙註冊中心過渡狀態下, 支援跨註冊中心呼叫的藍綠灰度釋出和子環境功能;
  • Solar Nacos SDK 整合灰度藍綠埋點到 SkyWalking;
  • Solar Nacos SDK 通過 @EnableSolarService @EnableSolarGateway 封裝了標準 Spring Boot / Spring Cloud / Apollo / Zuul 等大量註解,降低業務的使用成本;
  • Solar Nacos SDK 和 Solar Eureka SDK 升級和回滾;
  • Solar Nacos SDK 結合 Java Agent 方式,解決非同步呼叫場景下的跨執行緒呼叫的上下文丟失。

②  Alibaba Sentinel

  • Solar Sentinel SDK 內建 DEV | FAT | UAT | PROD 四個環境的域名,業務系統無感知
    • SDK通過獲取當前機器所在的環境,適配當前所要連線的Sentinel地址
  • Solar Sentinel SDK 深度整合 Apollo SDK
    • Sentinel配置,持久化到服務的apollo的namespace下面,下次重啟從apollo獲取配置載入到記憶體
    • 以appId的維度配置應用熔斷限流規則
  • Solar Sentinel SDK 整合 OpenTracing & SkyWalking,輸出 Sentinel 埋點到 SkyWalking
    • 通過SkyWalking提供的OpenTracing 工具包,手動埋點,獲取span資訊,推送到SkyWalking持久化到ES
  • Solar Sentinel SDK Dashboard 持久化改造,整合 InfluxDB & Grafana
    • 將Sentinel Metrics資料持久化到時序資料庫InfluxDB中,然後通過Grafana 展示
  • Solar Sentinel SDK Limit-App 熔斷擴充套件 (特色功能:灰度藍綠髮布指標的熔斷)
    • 灰度藍綠呼叫時,如果探測到版本匹配失敗時,則拋BlockException
  • Solar Sentinel SDK 閘道器流控 ,微服務單機限流
    • 全鏈路壓測幫助瞭解服務能承載流量峰值
    • 訊號量隔離/QPS, 併發執行緒數限流/平均響應時間、秒級異常比率、分鐘級異常數熔斷
    • 基於 TCP BBR 的系統保護演算法,自動探測系統瓶頸,保護系統穩定性
  • Solar Sentinel SDK 叢集限流
    • 通過叢集限流來解決叢集各個機器的流量不均導致整體限流效果不精確的問題

2. 灰度藍綠和環境隔離

  • 基於 Spring Cloud Alibaba 、Nacos SDK、Nepxion Discovery 開源框架(https://github.com/Nepxion/Discovery
  • 藍綠灰度釋出 :版本匹配灰度釋出、版本權重灰度釋出
  • 多區域路由:區域匹配灰度路由、區域權重灰度路由
  • 環境隔離:環境隔離、環境路由

3. 基於 DevOps 釋出平臺的智慧化和半自動化灰度藍綠

  • **智慧化釋出入口介面 **

  • 藍綠條件驅動模式介面

  • 藍綠權重放量模式介面

  • 全量釋出和回滾介面

4. 基於 DevOps 釋出平臺的滾動無損釋出

  1. 運維 CD 釋出平臺,先將例項狀態設定 disabled ,例項從註冊中心拉出;
  2. 消費者訂閱註冊中心,通知消費者例項處於不可用狀態;
  3. 消費者停止路由轉發到不可用例項;
  4. 服務上面流量繼續處理,30S 後才會啟動例項釋出指令碼;
  5. 例項重啟成功後,CD 平臺通過請求寄宿在業務 Web 容器裡的 VI 介面檢測例項健康狀態;
  6. 狀態檢測健康後,註冊到 Nacos 註冊中心;
  7. 消費者訂閱到新的例項,請求正常負載。

5. 分散式追蹤和 APM 系統 SkyWalking

  • 所有服務異常監控大盤

  • 介面效能指標

  • 服務維度的異常監控看板,聚合鏈路中異常數量,幫助業務快速定位問題

  • 整合 Solar 全鏈路灰度藍綠埋點

  • 整合 Sentinel 限流降級熔斷埋點

  • 整合服務、例項、介面維度效能指標
  • 快速定位異常、慢 SQL、熔斷鏈路
  • 整合鏈路與日誌
  • 服務、例項、介面、鏈路維度拓撲圖
  • 整合應用診斷系統(Arthas & Bistoury)

6. 應用診斷系統 Arthas & Bistoury

  • 無需登入機器
  • 整合 Arthas,Web 化控制檯  從 CPU 、執行緒、記憶體、JVM 等方面對應用進行診斷
  • 熱點方法分析
  • 線上 Debug

四. Solar 雲原生容器化實踐

1. CI/CD 持續釋出

  • CD Platform 通過 jinkens 編譯打包生成 Jar 包和 Docker img,通過 Harbor 上傳映象到 OSS 平臺,Harbor 通過 SLB 做高可用;
  • 自研 Hyperion 中間服務,作為連線 Harbor 和阿里雲 K8s 的 API 呼叫中間層;
  • CD Platform 通過 Hyperion 呼叫阿里雲 K8s API 釋出映象,K8s 從 Harbor 拉取映象,deploy 到物理節點;
  • 阿里雲 K8s 推送狀態事件給 Hyperion,Hyperion 將資料推送給 .CD Platform 實時展示釋出狀態資訊。

2. 日誌收集

  1. Pod 將日誌寫到容器內的路徑 /opt/logs/{appid}/xxx;
  2. 建立軟連線指向 Node 路徑 /var/log/{appid}/{podid}/xxx;
  3. 一個物理節點啟動一個 FileBeat 程序收集此物理節點上所有 Pod 日誌資訊;

PS:經過全面的壓測,一個物理節點上啟動一個 FileBeat 程序收集所有 Pod 日誌,效能沒有問題
如果存在日誌收集不及時問題,則可以一個 Pod 掛載一個 FileBeat 程序來解決,這樣的缺點是會佔用更多系統資源。

  1. FileBeat 將日誌資訊推送到 Kafka;
  2. GoHangout 併發消費 Kafka 中資料,持久化到 ES 叢集中;

GoHangout 併發消費 Kafka 訊息效能比較好。

  1. Kibana 顯示 ES 中所有日誌索引資料。

3. 微服務彈性擴容和自愈

  • CPU 負載
  • Memory
  • Metrics:根據熔斷、限流、監控等元件提供的 Metric 指標做彈性伸縮和自愈;
  • 根據課堂排課資訊的容量規劃:如下圖掌門上課情況非常規律,流量峰值也規律分佈,根據排課資訊等資料來規劃未來幾小時內微服務需要承載容量,並按照計劃,分配 Pod 數量

4. 平滑遷移網路解決方案

  • 阿里雲 Terway Kubernetes 叢集提供 CNI Plugin 實現 Pod IP、Node IP 處於同一平面;
  • Pod 每次釋出 IP 都會發生變化,內網沿用虛擬機器時代的訪問和治理方案;
  • 外網訪問通過阿里雲 SLB,SLB 能自動探測 IP 變化;
  • 基礎架構在微服務構建上面已經有很深的積累,充分利用 Spring Cloud Alibaba 以及 Nacos 等一系列服務治理方案 ,使我們雲原生容器化過程能夠平滑遷移到阿里雲 K8s。

結語:以上就是掌門教育圍繞 Spring Cloud Alibaba 構建雲原生微服務技術體系的一個全貌,掌門教育也會跟隨社群技術發展的腳步,朝著微服務 Service Mesh 網格化,serverless 函式計算的方向不斷演進,很多年前,大家可能在討論服務上雲的風險,隨著雲原生技術的不斷成熟,現在大家更多的是討論服務不上雲的風險,希望此次分享能給那些準備使用 Spring Cloud Alibaba 微服務繫上雲的或者正在上雲的同學一些實用性的參考和指引,謝謝大家!

Spring Cloud Alibaba 七天訓練營火熱開營!

PC 端點選連結瞭解詳情:https://developer.aliyun.com/learning/trainingcamp/spring/1

阿里巴巴雲原生關注微服務、Serverless、容器、Service Mesh 等技術領域、聚焦雲原生流行技術趨勢、雲原生大規模的落地實踐,做最懂雲原生開發者的公眾號。”