天天看點

位元組跳動雲原生大資料平台運維管理實踐

作者:位元組跳動雲原生計算
雲原生大資料是大資料平台新一代架構和運作形态。随着位元組跳動内部業務的快速增長,傳統大資料運維平台的劣勢開始逐漸暴露,如元件繁多,安裝運維複雜,與底層環境過度耦合;對業務方來說缺少開箱即用的日志、監控、告警功能等。在此背景下,我們進行了一系列雲原生大資料運維管理實踐。通過雲原生的方式進行運維管理,最終達到弱化業務方對狀态的感覺,屏蔽環境的差異,統一不同環境下的使用體驗。

作者|位元組跳動資深研發工程師-羅來鋒

業務現狀與背景介紹

位元組跳動過去幾年在支撐自身業務的過程中積累了很多大資料領域的引擎工具,目前也在探索将這些引擎工具的能力進行标準化、産品化的輸出。在此過程中主要有以下幾個難點:

  • 元件繁多:大資料領域完成一項工作需要很多元件配合。比如分布式大資料存儲及各種任務執行引擎:Flink、Spark 及各種 ETL 的 OLAP 工具和排程 ETL 的任務排程工具,還有支撐工具引擎的運作日志監控系統和項目使用者權限的輔助系統等;
  • 部署複雜:這些系統的元件繁多,互相配合也非常複雜,導緻部署變得困難。比如部署一套完整的生産環境,可能會涉及到多個依賴和配置管理。有強依賴,比如各種任務引擎對底層大資料存儲的依賴;也有弱依賴,比如任務引擎對日志監控系統的依賴;甚至還有循環依賴,比如消息中間件可能需要采集日志,但日志采集本身又依賴消息中間件,另外它們的配置還會形成互相嵌套;
  • 環境耦合:比如任務執行引擎可能需要嵌套大資料存儲配置,日志采集可能需要感覺每個元件的目錄以及它的格式等。部署複雜就會造成環境的耦合,因為日常需要維護這些複雜的配置及依賴等,日積月累下就會與這套環境形成了一個深度耦合造成移植困難。

随着近幾年雲原生概念的興起,我們也嘗試将這些工具進行雲原生改造來解決以上問題。

雲原生場景特性

  • 無服務狀态感覺:使用者可以使用功能而不需要關注背後的運作狀态,也不需要關心背後的邏輯;
  • 極緻彈性伸縮:對使用者隐藏運作狀态後,在雲原生場景下的伸縮更為極緻,按需使用可以使成本降低顯著;
  • 快速故障轉移:當故障發生時借助極緻的彈性伸縮特性,可以快速下線故障節點,補充新的正常節點,進而實作快速故障轉移,并且這個故障轉移對使用者來說也是無感無損的動作。

以上這三個特性會互相促進,形成一個良性的循環。

雲原生演進方向

對于上述所說的雲原生化改造,主要歸納總結了以下幾個大的演進方向:

  • 元件微服務化:通過将整體服務按職責劃分成多個小的元件,在整體架構上更加高内聚低耦合,降低整個環境變更複雜度,更加友善大規模合作開發;
  • 應用容器化:容器提供了可移植性,可以保證環境間的一緻性;
  • 基礎設施不可變:通過将所有内容進行封裝,進而實作底層基礎設施的隔離,進而保證基礎設施不可變,可以帶來部署的一緻性、可靠性和簡單性,對環境的狀态也更加可控;
  • 聲明式 API:通過聲明式 API,使用者隻需要聲明自己想要達到的狀态,後端服務盡力去滿足,使使用者無需感覺具體過程,整體環境更加穩定,而且功能的變更與演進也會更簡單,同時也簡化了使用門檻。

架構演進

雲原生大資料簡介

位元組跳動雲原生大資料平台運維管理實踐

雲原生大資料主要是建構在容器上的,這裡的容器可以是公有雲的容器服務,也可以是私有雲的容器底座,私有雲的容器底座可以是開源的 K8s/基于 K8s 改造的底座,整個雲原生大資料可以分為三大平台和一大支撐體系,三大平台分别是排程層、引擎層和平台層。在容器之上是資源排程層,負責統一管理排程整個叢集的計算、存儲和網絡等資源。排程層上面的核心引擎層主要是是位元組自研的統一大資料存儲系統,相容 HDFS 語義的同時支援對接标準的 S3 對象存儲。存儲層的上一層是 Flink、Spark 等各類位元組自研或優化的計算引擎、消息中間件、日志搜尋及實時分析引擎等工具。最上面即是平台服務層,負責将這些引擎能力封裝整合成一個對外輸出的産品。

本次介紹的運維管理平台支撐了上述的三大平台,提供日常元件運維的管理功能,為了更好地适應整個大資料雲原生的改造,我們對運維管理子產品也做了雲原生的改進。

雲原生上的運維實踐

  • 資源占用率低:運維管理子產品不是面向使用者的産品核心功能,是以它的存在感要足夠低,資源占比要足夠小,甚至在一些小型場景下要可以被忽略不計;
  • 伸縮性強:在日常的運維管理中,因為日志監控跟叢集的規模是呈正相關的,那麼所有運維管理相關的功能要有跟環境進行快速水準伸縮的能力;
  • 穩定性高:運維管理對穩定性的要求很高,即使在發生故障的情況下,也要能夠快速恢複,并且也需要對其他元件提供容災管理的能力;
  • 可移植性強: 運維管理子產品的一個大目标就是支援整個雲原生大資料産品的快速移植,那麼就要求它本身就不能有環境耦合的問題,并且所有的相關功能都需要支援插拔式設計,可以靈活的在不同環境提供一套完整的運維管理功能;
  • 環境感覺弱:向上層業務屏蔽由于環境差異帶來的運維管理的差異性,保證上層業務可以用統一的方式使用不同環境上的運維管理功能。

是以為了滿足以上要求總結了接下來需要關注的幾個方向。在環境管理方面需要我們抽象出一套統一的環境模型去适應不同的部署;另外還要有一個靈活便捷的元件管理服務統一管理元件中繼資料的依賴、配置等資訊;最後還需要擁有功能抽象的能力,比如對常見的日志、監控、告警等功能可以通過抽象統一對上層業務屏蔽環境差異性。

環境管理與元件服務

環境管理

位元組跳動雲原生大資料平台運維管理實踐

可以将整個環境按照功能劃分成三個邏輯區域,分别是控制面、系統面和資料面,需要注意的是這三塊區域隻是邏輯區域的劃分,并不是實體環境上的隔離。比如在一些場景下控制面可以與系統面進行合并,甚至在一些小型場景下,三個面也可以合并在一個實體叢集内。

  • 控制面:用來提供弱業務承載,是全局唯一一個負責環境管控、成本核算及服務網關等支撐性的工作;
  • 系統面:在每個邏輯單元内是唯一的,但是整個系統中可以有多個邏輯單元,比如在同城多活/異地多活的場景下,每一個邏輯單元都可能對應着一個機房/一個區域,多個邏輯單元間的關系依靠控制面協調;
  • 資料面:用于提供引擎運作所需的計算、存儲、網絡等資源,并且在系統面的統一協調下多個資料面可以形成一個邏輯上的聯邦叢集。

組建服務

位元組跳動雲原生大資料平台運維管理實踐

通過對環境的區域劃分對元件進行層級的劃分,主要可以分成系統級、叢集級、租戶級和項目級。系統級負責大部分的業務管控邏輯;叢集級則主要完成日志資料/監控資料 Agent 和内部自研的排程器及 Operator 等的采集工作;租戶級主要用于支撐特定大使用者獨占的元件;最下層的項目級就是使用者的作業執行個體、中間件執行個體及其他第三方工具等。通過這裡的劃分就把整個部署劃分為了網格形式,使每個元件隻需要關注自己所在的網格,很好的屏蔽了元件與環境資訊的耦合。

元件服務:Helm 定制化改進

位元組跳動雲原生大資料平台運維管理實踐

K8s 對單個資源的支援十分友好,對特定領域的操作也十分豐富。但是簡單的服務也需要多個資源的配合,比如 Deployment 承載業務邏輯就需要 ConfigMap 去儲存它的配置,然後又為了友善地對外暴露服務需要通過 Service 統一通路入口,但是這裡的資源協調在 K8s 中并沒有提供很好的工具。在開源的解決方案中很多開源元件基本上都提供了遷移 K8s 的 Helm Chart,但為了更好地融入開源的生态體系,我們也基于 Helm 建構了自己的元件服務。

由于開源 Helm 指令行工具并不适用于雲原生場景下元件間的 API 調用,是以我們對開源 Helm 進行了深度服務化定制,在常見的部署、解除安裝、更新、復原等需求中通過 API 的方式進行對外暴露,并增加可視化界面,同時還支援了一些深度的仿真部署,讓使用者可以快速的進行部署、驗證、調試等工作,也對層級配置做了精細的劃分使元件在部署時可以進行合并覆寫,另外在元件部署時配置了對資源的動态修改,通過以上措施使上層的業務元件可以更加關注在自己的業務領域。

磁盤管理

原生的 K8s 對無狀态的負載支援是十分友好的,但對有狀态的負載支援就有點差強人意,主要展現在本地磁盤的使用上,我們分析總結了以下痛點:

  • 環境耦合:在 K8s 使用本地磁盤時需要提前感覺到本地磁盤的挂載點、類型、大小等,會造成一定的耦合現象;
  • 使用率低:缺少全局統一進行存儲排程和管理的元件,導緻元件與元件間無法形成高效的混部,使得磁盤整體使用率偏低;
  • 隔離性差:磁盤以整盤的方式使用會導緻使用率低,但如果不以整盤的方式使用,又會使元件與元件間缺乏隔離性;
  • 維護難度大:在業務運作期間由于元件對磁盤的動态需求往往需要做擴縮容調整,但是提前協調各個使用方的操作使時間跨度大、鍊路長、維護難度高。

統一排程

為此我們開發了一套統一的 CSI(容器存儲接口)來用于管理,不僅能夠統一采集叢集的所有磁盤資訊,也可以進行統一管理。在此基礎上我們将整個磁盤的使用場景分成了三類,分别是共享容量卷、共享磁盤卷和獨占磁盤卷。

共享容量卷即容量是共享的,這類場景對 IO 不敏感,也不需要很強的空間容量的限制,但對于靈活性要求更高,比如典型的大資料作業的臨時資料存儲、日志等;

共享磁盤卷對 IO 也不是很敏感,但對隔離性、持久化有一定的需求,需要在出現故障時能夠找回,但是找不回的情況也不會産生災難性的後果,其中最典型的場景就是緩存;

獨占磁盤卷需要高度的 IO 隔離特性,典型的場景如消息中間件 Kafka、HDFS 等。

磁盤管理概覽

位元組跳動雲原生大資料平台運維管理實踐

在磁盤管理中将其分成兩大塊區域,第一塊區域是 K8s 維護的,比如常用的 EmptyDir,這個部分推薦用來存儲配置資料或者少量的臨時性資料。

剩下的區域就是上文提到的通過 CSI 進行統一管理,主要細化成了三塊區域,分别對應的前面提到的三個存儲卷,共享容量卷基于簡單的本地路徑的方式進行支援;對于共享磁盤卷會先會把所有的磁盤組裝組合成一個 Volume Group,當業務元件申請共享磁盤卷時可以建立一個邏輯卷使用,進而達到隔離的效果。

獨占磁盤卷就是擁有整塊磁盤,然後通過統一的 CSI 抽象成一系列的 Storage Class,上層的業務元件可以根據自己的需求申請對應的存儲卷。如果是公有雲雲盤或者有中心化存儲的場景下,仍然推薦通過這套 CSI 給業務提供各類的存儲卷,以達到容量管控的同時也可以通過這個 CSI 将磁盤資訊與元件解耦。

統一的日志監控告警

日志

日志也是産生可移植性困難較大的一個因素,為此我們也做了統一的日志采集的鍊路管理,以達到業務隔離、高效采集、公平配置設定、安全可靠。

對于日志采集目前支援兩種方式,一種是侵入式采集,即提供各種 Collector,主要支援 Java 、Python 兩種方式,由于這種方式具有侵入性,大部分元件習慣使用基于檔案的采集,是以我們也通過 Filebeat 支援檔案方式的采集。采集後彙聚到本叢集的日志代理上進行流量管控,後續再彙聚到統一的中心化存儲中用統一的 API 支撐日志搜尋場景。也對定制化引擎提供了針對性的 API使使用者可以根據具體場景使用對應的 API。

位元組跳動雲原生大資料平台運維管理實踐

第二種是 Filebeat 采集,在容器場景下是一個基于檔案的采集,和基于實體機的采集不同,主要差別在容器視角,日志存儲路徑與實際的實體存儲路徑也是不一樣的。為解決這個問題首先通過定制的日志規則 CRD 聲明自己的采集規則,然後再通過元件部署服務,随着整個元件的建立、更新,Filebeat 的 Discovery 機制可以動态地發現日志規則的 CRD 建立、變更或删除,再通過 Filebeat 熱加載的機制生成、加載成自己的日志采集規則。

在 Filebeat 的部署形态中如果能夠感覺到叢集的節點資訊并擁有對應的權限,那麼就可以部署成 DeamonSet 的方式,使整體資源占比更低,叢集是共用一套 Filebeat 進行資料采集。由于在公共雲的容器服務場景下是感覺不到具體的節點資訊的,也沒有部署 DeamonSet 的權限,是以這裡支援通過 Sidecar 的方式注入到具體的一個個 Pod 中負責日志采集,通過這種方式我們就統一了在容器裡基于檔案的日志采集。

日志資料鍊路

位元組跳動雲原生大資料平台運維管理實踐

在雲原生的場景下,日志采集遠遠不隻是統一采集鍊路,而是要用盡可能低的資源消耗支撐日志的高效采集需求。因為雲原生場景天然地面向多租戶,那麼租戶與租戶間,元件與元件間的流量差異會很大,不能因為單個租戶不正常的流量對整個日志采集造成擾動。是以我們在每個叢集内部的日志代理中,會針對租戶做流量管控,當發現大流量異常的時采取限流或者熔斷措施。同時也要保障多租戶場景下的公平配置設定、日志采集的故障轉移、雲原生場景下 Pod 重建/主動更新等,這幾個部分都是後續将主要投入的大方向。

告警

位元組跳動雲原生大資料平台運維管理實踐

告警體系整體是基于開源的夜莺改造而成的,在開源夜莺的概覽中包括存儲名額資料的 Prometheus、存儲告警業務資料的資料庫及核心元件: WebApi 和 Server。 WebApi 用于承擔使用者的互動,比如規則的增删改查及執行名額查詢等。Server 負責加載規則、生成告警事件、發送告警通知等。在開源夜莺中,Server 還承擔着 Prometheus 的 PushGateway 職責,位元組的産品有自己的使用者體系和監控系統,是以對告警方面的定制主要集中在 WebApi 和 Server 上。

流程概覽

位元組跳動雲原生大資料平台運維管理實踐

使用者首先通過 WebAPI 生成自己的告警規則,并持久化到資料庫中, Server 再加載規則到自己的記憶體中,通過一緻性哈希環決定處理哪些規則并轉換成名額查詢判斷是否有告警事件産生。當有告警事件産生時會調用對應的控制子產品發送告警通知,将告警事件回填到的資料庫中,主要優化展現在以下方面:

  • 首先,我們的産品體系中有統一的使用者體系,和運維管理平台一樣,并在此基礎上增加了使用者組、值班表功能,使它更加符合告警領域的使用習慣;
  • 第二,開源夜莺加載日志規則是通過全量的方式,但是會有潛在的性能隐患,我們通過将全量加載改造成增量加載,進一步消除相關性能隐患;
  • 第三,告警通知子產品,與環境有強耦合關系。因為不同環境的告警通知的差異會很大,比如釘釘、企業微信、飛書,還有短信電話等等。即使是同樣的短信告警,不同的環境可能有不同的短信提供商,有不同的對接接口等,是以我們提供了動态消息模版的能力。

動态消息模闆

  • 通過動态消息模闆可以引用告警事件的一些資訊,進而可以組裝出帶有豐富上下文的告警資訊,使告警系統的靈活性更廣,體驗感也更好。
  • 在通知方式上設計将其做成一個個插件,使用者隻需要針對不同的環境開發不同的發送插件就可以了,這種操作也可以使我們的核心流程保持一緻。

通知子產品

位元組跳動雲原生大資料平台運維管理實踐

在通知子產品中通過 Server 生成告警事件,再由前面的消息模闆渲染得到一個真實的告警消息,然後将這個告警消息發送給通知子產品,由通知子產品結合通知方式及對象生成通知記錄并放到隊列中。為了更好地适應各種環境,這裡的隊列可以是真實的消息隊列,也可以是通過資料庫模拟的消息隊列。最後由若幹個 Worker 并發消費資訊調用不同的發送插件發送消息;Worker 之外還有一些定時的線程輪詢/巡檢整體發送的狀态對發送失敗的消息進行重試,當重試次數達到一定量的時候生成運維上的告警。

開源夜莺系統還有一個比較大的特性是動态門檻值,在整體的使用中就是事件發生、觸發告警、然後人工回報到訓練分析形成循環監督學習的過程,并不斷調整動态門檻值的生成規則。

監控

位元組跳動雲原生大資料平台運維管理實踐

在整體的監控架構概覽中可以看到上層就是前面所說的資料面,資料面中的每個叢集都會有一個Prometheus用來采集、彙聚本實體叢集所有元件的監控資料,這裡的 Prometheus 本質是一個 Agent,不會承擔任何資料存儲、查詢等職責,最後由 Prometheus 把采集到的監控資料 Remote Write 到系統面的監控系統中。

監控系統用來儲存所有的監控資料。為了友善對資料存儲進行水準伸縮也做了一層抽象,背後的真正實作可以是公有雲上現有的雲監控服務、也可以是 S3 的對象存儲服務,還可以是我們自研的大資料存儲服務,在部分私有雲的場景下,也可以對接使用者自己自定義的存儲服務。在本層的統一存儲中通過加一個 Query 服務承擔所有監控資料的查詢服務,并形成了可視化的大盤展示及前端互動。

對于查詢服務也做了一些針對性的優化。比如監控資料隻有新增、沒有更新,頻繁對某個時間段的監控資料進行反複檢索的場景引入了水準拆分的能力,通過将時間跨度大的查詢拆分成多個小跨度的子查詢并發執行,然後聚合回憶查詢速度。另外由于監控資料本身不可變,我們引入了緩存,可以對部分查詢出的資料做 一個緩存加上查詢場景友善預測。通過以上兩個優化互相促進提高了整體的查詢效率。

經過整體優化後的監控系統核心優勢是可以支援各種環境下的一鍵名額采集;在性能優化上支援了資料的預聚合、降采樣等能力,豐富了整體的功能體系;并且對接了大資料存儲,某種程度上可以具備存算分離的特性使得整體系統的水準伸縮能力得到了很大的增強;最後也把監控和其它的運維工具,比如日志、告警、鍊路追蹤等功能做了深度整合,優化了産品的整體使用體驗。

火山引擎雲原生計算産品全景圖

位元組跳動雲原生大資料平台運維管理實踐

繼續閱讀