Apache Kyuubi 高可用的雲原生實現

語言: CN / TW / HK

本文作者為中國移動雲能力中心大數據團隊軟件開發工程師洪鼕鼕,文章主要介紹了 Apache Kyuubi 基於 Apache ZooKeeper 實現高可用的原理,以及在雲原生場景下,利用現有的組件和技術實現雲原生的負載均衡和客户端高併發。

背景

Apache Kyuubi 是一個分佈式的、多租户網關,用於在 Lakehouse 上提供 Serverless SQL。Kyuubi 最初是基於 Apache Spark 構建的兼容 HiveServer2 協議的大規模數據處理和分析工具,目前已經支持 Flink/Trino/Hive/Doris 等引擎。Kyuubi 致力於成為一個開箱即用的數據倉庫和數據湖工具,讓任何人都可以輕鬆高效地使用各種計算引擎,在瞭解 SQL 的基礎上可以像處理普通數據一樣處理大數據。在 Kyuubi 架構中,有三個主要的特性:

1.多租户,Kyuubi 通過統一的身份驗證授權層為資源獲取和數據 / 元數據訪問提供端到端的多租户支持。2.高可用,Kyuubi 通過 ZooKeeper 提供負載均衡,它提供了企業級的高可用性,以及無限的客户端高併發。3.多個工作負載,Kyuubi 可以通過一個平台、一個數據副本和一個 SQL 接口輕鬆支持多個不同的工作負載。

在雲原生場景中,額外部署和維護 ZooKeeper 代價很高,我們是否有云原生的方案可以替代?

基於 ZooKeeper 的高可用實現

Kyuubi-ha 模塊下的 DiscoveryClient 接口中包含了服務註冊和發現所需要實現的所有的接口(基於 master 分支),大致包含:客户端的創建和關閉、節點的創建和刪除、節點是否存在、註冊和註銷服務、獲取分佈式鎖、獲取引擎地址等。下圖簡要展示了租户連接到 Kyuubi 的過程中與 discovery 交互的步驟。

當我們啟動 Kyuubi server 或者拉起 engine 時,ServiceDiscovery 會在 ZooKeeper 中註冊相關信息,租户獲取到可用 server 列表後,根據策略選擇 server 開啟 session,在開啟 session 的過程中,Kyuubi server 會根據用户連接時制定的引擎共享策略在 ZooKeeper 中查找是否有可用的 engine,如果沒有則拉起一個新的 engine 並連接。

在整個過程中,主要是用了 ZooKeeper 的兩個核心功能:服務註冊和分佈式鎖。

服務註冊

ZooKeeper 提供 4 種創建節點的方式:

1.PERSISTENT(持久化)即使客户端與 ZooKeeper 斷開連接,該節點依然存在,只要不手動刪除該節點,將永遠存在;2.PERSISTENT_SEQUENTIAL(持久化順序編號目錄節點)在持久化目錄節點基礎上,ZooKeeper 給該節點名稱進行順序編號;3.EPHEMERAL(臨時目錄節點)客户端與 ZooKeeper 斷開連接後,該節點就會被刪除;4.EPHEMERAL_SEQUENTIAL(臨時順序編號目錄節點)在臨時目錄節點基礎上 ZooKeeper 給該節點名稱進行順序編號

Kyuubi 中 server 和 engine 的服務註冊基於 EPHEMERAL_SEQUENTIAL 實現,在服務啟動時創建臨時節點,退出時斷開鏈接,ZooKeeper 自動刪除對應節點。同時,服務啟動時會創建 watcher 監聽註冊的臨時節點,當該節點被刪除時,會優雅的停止服務。

分佈式鎖

如上圖,當兩個客户端同時請求同一個引擎時,如果引擎不存在,在不加鎖狀態下,我們會啟動兩個 engine,後續再有新連接時,總會連接到後註冊的引擎,先註冊的引擎會長時間空閒。因此,在創建新的引擎時,通過對對應節點添加分佈式鎖,先獲取到鎖的客户端創建引擎,後獲取鎖的客户端直接使用已啟動的引擎。

基於 ETCD 的高可用雲原生實現

上圖是雲原生場景下,租户連接 Kyuubi 的過程,其中涉及到雲原生應用中比較關鍵的組件,ETCD 和 MetalLB。其中,ETCD 負責引擎服務註冊和發現,MetalLB 則為 Kyuubi server 提供負載均衡能力。

ETCD 既然支持引擎的註冊和發現,為什麼不像 ZooKeeper 一樣同時支持 Server 的高可用呢?

這個我們主要從客户使用方面考量,我們通常使用的 beeline、jdbc 驅動都支持基於 ZooKeeper 的服務發現,但並不支持 ETCD。如果將 server 註冊到 ETCD 中,我們沒有辦法兼容現有的客户端,需要為租户提供額外的驅動。同時,我們也知道在雲原生場景中 MetalLB 可以通過單個 IP 為下面的 pod(deployment)提供負載均衡。經過考量最終我們選擇 ETCD+MetalLB 的方式。

關於 ETCD

ETCD 是用於共享配置和服務發現的分佈式,一致性的 KV 存儲系統,是 CoreOS 公司發起的一個開源項目,授權協議為 Apache。ETCD 有很多使用場景,包括:配置管理、服務註冊與發現、leader 選舉、應用調度、分佈式隊列、分佈式鎖等。其中,比較多的應用場景是服務發現,服務發現 (Service Discovery) 要解決的是分佈式系統中最常見的問題之一,即在同一個分佈式集羣中的進程或服務如何才能找到對方並建立連接。ETCD 是 Kubernetes 的首要數據存儲,也是容器編排的實際標準系統。使用 ETCD,雲原生應用可以保持更為一致的運行時間,而且在個別服務器發生故障時也能正常工作。應用從 ETCD 讀取數據並寫入到其中;通過分散配置數據,為節點配置提供宂餘和彈性。

ETCD 與 ZooKeeper 的簡單對比如下:

  ETCD ZooKeeper
一致性協議 Raft ZAB
API HTTP+JSON, gRPC 客户端
安全控制 HTTPS Kerberos
運維 簡單 困難

關於 MetalLB

Kubernetes 默認沒有提供負載均衡器的實現,MetalLB 通過 MetalLB hooks 為 Kubernetes 中提供網絡負載均衡器的實現。簡單的説,它允許在私有的 Kubernetes 中創建 LoadBalancer 類型的 services。MetalLB 有兩大功能:

1.地址分配:在平台中申請 LB,會自動分配一個 IP,因此,MetalLB 也需要管理 IP 地址的分配工作 2.IP 外部聲明:當 MetalLB 獲取外部地址後,需要對外聲明該 IP 在 Kubernetes 中使用,並可以正常通信。

實現細節

當 Kyuubi 底層引擎啟動時,會在 ETCD 中創建對應的 Key。租户使用是,直接連接 MetalLB 提供的地址,由底層 LoadBalancer 負責負載均衡,連接到對應 Kyuubi server 後,server 會在 ETCD 中查找是否有可用的引擎,沒有則創建。其中主要涉及以下三點內容:

1.使用 Kubernetes 中原生組件 MetalLB+Deployment 方式實現實現 Kyuubi server 的高可用 2.ETCD 中模擬 EPHEMERAL_SEQUENTIAL 節點。在 ETCD 中沒有臨時 Key 的概念,無法在服務停止是自動刪除對應 Key 信息。但是在客户端中提供了 KeepAlive 功能:為特定的 Key 附加一個過期時間,並且在客户端未被關閉或超時的情況下,自動刷新這個過期時間。同時,引擎在註冊時,獲取對應節點的分佈式鎖,計算編號,以實現節點編號的自增長。3.分佈式鎖,ETCD 的分佈式鎖在使用方面和 ZooKeeper 基本一致,但在鎖持有時間方面稍有區別,ETCD 中鎖有租約時間,到時間後如果沒有主動釋放鎖,則會自動釋放,而 ZooKeeper 不主動釋放則不會釋放。

總結

首先,我們先簡單對比下雲原生架構和現有架構:

  Server+ZooKeeper Kurbernetes+ETCD
包管理 Helm3
Server 高可用 ZooKeeper LoadBalancer
Engine 註冊 ZooKeeper ETCD
部署維護成本

引入雲原生架構的 Kyuubi 在部署和運維方面極大的節約了成本,並且基於 deployment 我們可以實現 Kyuubi server 的動態擴容,基於 comfigmap 實現 server 的統一配置管理。目前,ETCD 的服務註冊和發現邏輯我們主要參考 ZooKeeper 的實現,後續工作會進一步優化調用邏輯。

最後,我們目前 Kyuubi 的整體架構圖如下,供大家參考。