云原生大數(shù)據(jù)是大數(shù)據(jù)平臺新一代架構和運行形態(tài)。隨著字節(jié)跳動內(nèi)部業(yè)務的快速增長,傳統(tǒng)大數(shù)據(jù)運維平臺的劣勢開始逐漸暴露,如組件繁多,安裝運維復雜,與底層環(huán)境過度耦合;對業(yè)務方來說缺少開箱即用的日志、監(jiān)控、告警功能等。在此背景下,我們進行了一系列云原生大數(shù)據(jù)運維管理實踐。通過云原生的方式進行運維管理,最終達到弱化業(yè)務方對狀態(tài)的感知,屏蔽環(huán)境的差異,統(tǒng)一不同環(huán)境下的使用體驗。
業(yè)務現(xiàn)狀與背景介紹
背景介紹
字節(jié)跳動過去幾年在支撐自身業(yè)務的過程中積累了很多大數(shù)據(jù)領域的引擎工具,目前也在探索將這些引擎工具的能力進行標準化、產(chǎn)品化的輸出。在此過程中主要有以下幾個難點:
-
組件繁多:大數(shù)據(jù)領域完成一項工作需要很多組件配合。比如分布式大數(shù)據(jù)存儲及各種任務執(zhí)行引擎:Flink、Spark 及各種 ETL 的 OLAP 工具和調度 ETL 的任務調度工具,還有支撐工具引擎的運行日志監(jiān)控系統(tǒng)和項目用戶權限的輔助系統(tǒng)等;
-
部署復雜:這些系統(tǒng)的組件繁多,相互配合也非常復雜,導致部署變得困難。比如部署一套完整的生產(chǎn)環(huán)境,可能會涉及到多個依賴和配置管理。有強依賴,比如各種任務引擎對底層大數(shù)據(jù)存儲的依賴;也有弱依賴,比如任務引擎對日志監(jiān)控系統(tǒng)的依賴;甚至還有循環(huán)依賴,比如消息中間件可能需要采集日志,但日志采集本身又依賴消息中間件,另外它們的配置還會形成相互嵌套;
-
環(huán)境耦合:比如任務執(zhí)行引擎可能需要嵌套大數(shù)據(jù)存儲配置,日志采集可能需要感知每個組件的目錄以及它的格式等。部署復雜就會造成環(huán)境的耦合,因為日常需要維護這些復雜的配置及依賴等,日積月累下就會與這套環(huán)境形成了一個深度耦合造成移植困難。
隨著近幾年云原生概念的興起,我們也嘗試將這些工具進行云原生改造來解決以上問題。
云原生場景特性
-
無服務狀態(tài)感知:用戶可以使用功能而不需要關注背后的運行狀態(tài),也不需要關心背后的邏輯;
-
極致彈性伸縮:對用戶隱藏運行狀態(tài)后,在云原生場景下的伸縮更為極致,按需使用可以使成本降低顯著;
-
快速故障轉移:當故障發(fā)生時借助極致的彈性伸縮特性,可以快速下線故障節(jié)點,補充新的正常節(jié)點,從而實現(xiàn)快速故障轉移,并且這個故障轉移對用戶來說也是無感無損的動作。
以上這三個特性會相互促進,形成一個良性的循環(huán)。
云原生演進方向
對于上述所說的云原生化改造,主要歸納總結了以下幾個大的演進方向:
-
組件微服務化:通過將整體服務按職責劃分成多個小的組件,在整體架構上更加高內(nèi)聚低耦合,降低整個環(huán)境變更復雜度,更加方便大規(guī)模合作開發(fā);
-
應用容器化:容器提供了可移植性,可以保證環(huán)境間的一致性;
-
基礎設施不可變:通過將所有內(nèi)容進行封裝,從而實現(xiàn)底層基礎設施的隔離,進而保證基礎設施不可變,可以帶來部署的一致性、可靠性和簡單性,對環(huán)境的狀態(tài)也更加可控;
-
聲明式 API:通過聲明式 API,用戶只需要聲明自己想要達到的狀態(tài),后端服務盡力去滿足,使用戶無需感知具體過程,整體環(huán)境更加穩(wěn)定,而且功能的變更與演進也會更簡單,同時也簡化了使用門檻。
架構演進
云原生大數(shù)據(jù)簡介
?
云原生大數(shù)據(jù)主要是構建在容器上的,這里的容器可以是公有云的容器服務,也可以是私有云的容器底座,私有云的容器底座可以是開源的 K8s/基于 K8s 改造的底座,整個云原生大數(shù)據(jù)可以分為三大平臺和一大支撐體系,三大平臺分別是調度層、引擎層和平臺層。在容器之上是資源調度層,負責統(tǒng)一管理調度整個集群的計算、存儲和網(wǎng)絡等資源。調度層上面的核心引擎層主要是是字節(jié)自研的統(tǒng)一大數(shù)據(jù)存儲系統(tǒng),兼容 HDFS 語義的同時支持對接標準的 S3 對象存儲。存儲層的上一層是 Flink、Spark 等各類字節(jié)自研或優(yōu)化的計算引擎、消息中間件、日志搜索及實時分析引擎等工具。最上面即是平臺服務層,負責將這些引擎能力封裝整合成一個對外輸出的產(chǎn)品。
本次介紹的運維管理平臺支撐了上述的三大平臺,提供日常組件運維的管理功能,為了更好地適應整個大數(shù)據(jù)云原生的改造,我們對運維管理模塊也做了云原生的改進。
云原生上的運維實踐
-
資源占用率低:運維管理模塊不是面向用戶的產(chǎn)品核心功能,所以它的存在感要足夠低,資源占比要足夠小,甚至在一些小型場景下要可以被忽略不計;
-
伸縮性強:在日常的運維管理中,因為日志監(jiān)控跟集群的規(guī)模是呈正相關的,那么所有運維管理相關的功能要有跟環(huán)境進行快速水平伸縮的能力;
-
穩(wěn)定性高:運維管理對穩(wěn)定性的要求很高,即使在發(fā)生故障的情況下,也要能夠快速恢復,并且也需要對其他組件提供容災管理的能力;
-
可移植性強: 運維管理模塊的一個大目標就是支持整個云原生大數(shù)據(jù)產(chǎn)品的快速移植,那么就要求它本身就不能有環(huán)境耦合的問題,并且所有的相關功能都需要支持插拔式設計,可以靈活的在不同環(huán)境提供一套完整的運維管理功能;
-
環(huán)境感知弱:向上層業(yè)務屏蔽由于環(huán)境差異帶來的運維管理的差異性,保證上層業(yè)務可以用統(tǒng)一的方式使用不同環(huán)境上的運維管理功能。
所以為了滿足以上要求總結了接下來需要關注的幾個方向。在環(huán)境管理方面需要我們抽象出一套統(tǒng)一的環(huán)境模型去適應不同的部署;另外還要有一個靈活便捷的組件管理服務統(tǒng)一管理組件元數(shù)據(jù)的依賴、配置等信息;最后還需要擁有功能抽象的能力,比如對常見的日志、監(jiān)控、告警等功能可以通過抽象統(tǒng)一對上層業(yè)務屏蔽環(huán)境差異性。
環(huán)境管理與組件服務
環(huán)境管理
?
可以將整個環(huán)境按照功能劃分成三個邏輯區(qū)域,分別是控制面、系統(tǒng)面和數(shù)據(jù)面,需要注意的是這三塊區(qū)域只是邏輯區(qū)域的劃分,并不是物理環(huán)境上的隔離。比如在一些場景下控制面可以與系統(tǒng)面進行合并,甚至在一些小型場景下,三個面也可以合并在一個物理集群內(nèi)。
-
控制面:用來提供弱業(yè)務承載,是全局唯一一個負責環(huán)境管控、成本核算及服務網(wǎng)關等支撐性的工作;
-
系統(tǒng)面:在每個邏輯單元內(nèi)是唯一的,但是整個系統(tǒng)中可以有多個邏輯單元,比如在同城多活/異地多活的場景下,每一個邏輯單元都可能對應著一個機房/一個區(qū)域,多個邏輯單元間的關系依靠控制面協(xié)調;
-
數(shù)據(jù)面:用于提供引擎運行所需的計算、存儲、網(wǎng)絡等資源,并且在系統(tǒng)面的統(tǒng)一協(xié)調下多個數(shù)據(jù)面可以形成一個邏輯上的聯(lián)邦集群。
組件服務
通過對環(huán)境的區(qū)域劃分對組件進行層級的劃分,主要可以分成系統(tǒng)級、集群級、租戶級和項目級。系統(tǒng)級負責大部分的業(yè)務管控邏輯;集群級則主要完成日志數(shù)據(jù)/監(jiān)控數(shù)據(jù) Agent 和內(nèi)部自研的調度器及 Operator 等的采集工作;租戶級主要用于支撐特定大用戶獨占的組件;最下層的項目級就是用戶的作業(yè)實例、中間件實例及其他第三方工具等。通過這里的劃分就把整個部署劃分為了網(wǎng)格形式,使每個組件只需要關注自己所在的網(wǎng)格,很好的屏蔽了組件與環(huán)境信息的耦合。
組件服務:Helm 定制化改進
?
K8s 對單個資源的支持十分友好,對特定領域的操作也十分豐富。但是簡單的服務也需要多個資源的配合,比如 Deployment 承載業(yè)務邏輯就需要 ConfigMap 去保存它的配置,然后又為了方便地對外暴露服務需要通過 Service 統(tǒng)一訪問入口,但是這里的資源協(xié)調在 K8s 中并沒有提供很好的工具。在開源的解決方案中很多開源組件基本上都提供了遷移 K8s 的 Helm Chart,但為了更好地融入開源的生態(tài)體系,我們也基于 Helm 構建了自己的組件服務。
由于開源 Helm 命令行工具并不適用于云原生場景下組件間的 API 調用,所以我們對開源 Helm 進行了深度服務化定制,在常見的部署、卸載、升級、回滾等需求中通過 API 的方式進行對外暴露,并增加可視化界面,同時還支持了一些深度的仿真部署,讓用戶可以快速的進行部署、驗證、調試等工作,也對層級配置做了精細的劃分使組件在部署時可以進行合并覆蓋,另外在組件部署時配置了對資源的動態(tài)修改,通過以上措施使上層的業(yè)務組件可以更加關注在自己的業(yè)務領域。
磁盤管理
原生的 K8s 對無狀態(tài)的負載支持是十分友好的,但對有狀態(tài)的負載支持就有點差強人意,主要體現(xiàn)在本地磁盤的使用上,我們分析總結了以下痛點:
-
環(huán)境耦合:在 K8s 使用本地磁盤時需要提前感知到本地磁盤的掛載點、類型、大小等,會造成一定的耦合現(xiàn)象;
-
利用率低:缺少全局統(tǒng)一進行存儲調度和管理的組件,導致組件與組件間無法形成高效的混部,使得磁盤整體利用率偏低;
-
隔離性差:磁盤以整盤的方式使用會導致利用率低,但如果不以整盤的方式使用,又會使組件與組件間缺乏隔離性;
-
維護難度大:在業(yè)務運行期間由于組件對磁盤的動態(tài)需求往往需要做擴縮容調整,但是提前協(xié)調各個使用方的操作使時間跨度大、鏈路長、維護難度高。
統(tǒng)一調度
為此我們開發(fā)了一套統(tǒng)一的 CSI(容器存儲接口)來用于管理,不僅能夠統(tǒng)一采集集群的所有磁盤信息,也可以進行統(tǒng)一管理。在此基礎上我們將整個磁盤的使用場景分成了三類,分別是共享容量卷、共享磁盤卷和獨占磁盤卷。
共享容量卷即容量是共享的,這類場景對 IO 不敏感,也不需要很強的空間容量的限制,但對于靈活性要求更高,比如典型的大數(shù)據(jù)作業(yè)的臨時數(shù)據(jù)存儲、日志等;
共享磁盤卷對 IO 也不是很敏感,但對隔離性、持久化有一定的需求,需要在出現(xiàn)故障時能夠找回,但是找不回的情況也不會產(chǎn)生災難性的后果,其中最典型的場景就是緩存;
獨占磁盤卷需要高度的 IO 隔離特性,典型的場景如消息中間件 Kafka、HDFS 等。
磁盤管理概覽
在磁盤管理中將其分成兩大塊區(qū)域,第一塊區(qū)域是 K8s 維護的,比如常用的 EmptyDir,這個部分推薦用來存儲配置數(shù)據(jù)或者少量的臨時性數(shù)據(jù)。
剩下的區(qū)域就是上文提到的通過 CSI 進行統(tǒng)一管理,主要細化成了三塊區(qū)域,分別對應的前面提到的三個存儲卷,共享容量卷基于簡單的本地路徑的方式進行支持;對于共享磁盤卷會先會把所有的磁盤組裝組合成一個 Volume Group,當業(yè)務組件申請共享磁盤卷時可以創(chuàng)建一個邏輯卷使用,從而達到隔離的效果。
獨占磁盤卷就是擁有整塊磁盤,然后通過統(tǒng)一的 CSI 抽象成一系列的 Storage Class,上層的業(yè)務組件可以根據(jù)自己的需求申請對應的存儲卷。如果是公有云云盤或者有中心化存儲的場景下,仍然推薦通過這套 CSI 給業(yè)務提供各類的存儲卷,以達到容量管控的同時也可以通過這個 CSI 將磁盤信息與組件解耦。
統(tǒng)一的日志監(jiān)控告警
日志
日志也是產(chǎn)生可移植性困難較大的一個因素,為此我們也做了統(tǒng)一的日志采集的鏈路管理,以達到業(yè)務隔離、高效采集、公平分配、安全可靠。
對于日志采集目前支持兩種方式,一種是侵入式采集,即提供各種 Collector,主要支持 Java 、Python 兩種方式,由于這種方式具有侵入性,大部分組件習慣使用基于文件的采集,因此我們也通過 Filebeat 支持文件方式的采集。采集后匯聚到本集群的日志代理上進行流量管控,后續(xù)再匯聚到統(tǒng)一的中心化存儲中用統(tǒng)一的 API 支撐日志搜索場景。也對定制化引擎提供了針對性的 API使用戶可以根據(jù)具體場景使用對應的 API。
第二種是 Filebeat 采集,在容器場景下是一個基于文件的采集,和基于物理機的采集不同,主要區(qū)別在容器視角,日志存儲路徑與實際的物理存儲路徑也是不一樣的。為解決這個問題首先通過定制的日志規(guī)則 CRD 聲明自己的采集規(guī)則,然后再通過組件部署服務,隨著整個組件的創(chuàng)建、更新,F(xiàn)ilebeat 的 Discovery 機制可以動態(tài)地發(fā)現(xiàn)日志規(guī)則的 CRD 創(chuàng)建、變更或刪除,再通過 Filebeat 熱加載的機制生成、加載成自己的日志采集規(guī)則。
在 Filebeat 的部署形態(tài)中如果能夠感知到集群的節(jié)點信息并擁有對應的權限,那么就可以部署成 DeamonSet 的方式,使整體資源占比更低,集群是共用一套 Filebeat 進行數(shù)據(jù)采集。由于在公共云的容器服務場景下是感知不到具體的節(jié)點信息的,也沒有部署 DeamonSet 的權限,所以這里支持通過 Sidecar 的方式注入到具體的一個個 Pod 中負責日志采集,通過這種方式我們就統(tǒng)一了在容器里基于文件的日志采集。
日志數(shù)據(jù)鏈路
在云原生的場景下,日志采集遠遠不只是統(tǒng)一采集鏈路,而是要用盡可能低的資源消耗支撐日志的高效采集需求。因為云原生場景天然地面向多租戶,那么租戶與租戶間,組件與組件間的流量差異會很大,不能因為單個租戶不正常的流量對整個日志采集造成擾動。所以我們在每個集群內(nèi)部的日志代理中,會針對租戶做流量管控,當發(fā)現(xiàn)大流量異常的時采取限流或者熔斷措施。同時也要保障多租戶場景下的公平分配、日志采集的故障轉移、云原生場景下 Pod 重建/主動升級等,這幾個部分都是后續(xù)將主要投入的大方向。
告警
告警體系整體是基于開源的夜鶯改造而成的,在開源夜鶯的概覽中包括存儲指標數(shù)據(jù)的 Prometheus、存儲告警業(yè)務數(shù)據(jù)的數(shù)據(jù)庫及核心組件: WebApi 和 Server。 WebApi 用于承擔用戶的交互,比如規(guī)則的增刪改查及執(zhí)行指標查詢等。Server 負責加載規(guī)則、生成告警事件、發(fā)送告警通知等。在開源夜鶯中,Server 還承擔著 Prometheus 的 PushGateway 職責,字節(jié)的產(chǎn)品有自己的用戶體系和監(jiān)控系統(tǒng),所以對告警方面的定制主要集中在 WebApi 和 Server 上。
流程概覽
?
用戶首先通過 WebAPI 生成自己的告警規(guī)則,并持久化到數(shù)據(jù)庫中, Server 再加載規(guī)則到自己的內(nèi)存中,通過一致性哈希環(huán)決定處理哪些規(guī)則并轉換成指標查詢判斷是否有告警事件產(chǎn)生。當有告警事件產(chǎn)生時會調用對應的控制模塊發(fā)送告警通知,將告警事件回填到的數(shù)據(jù)庫中,主要優(yōu)化體現(xiàn)在以下方面:
-
首先,我們的產(chǎn)品體系中有統(tǒng)一的用戶體系,和運維管理平臺一樣,并在此基礎上增加了用戶組、值班表功能,使它更加符合告警領域的使用習慣;
-
第二,開源夜鶯加載日志規(guī)則是通過全量的方式,但是會有潛在的性能隱患,我們通過將全量加載改造成增量加載,進一步消除相關性能隱患;
-
第三,告警通知模塊,與環(huán)境有強耦合關系。因為不同環(huán)境的告警通知的差異會很大,比如釘釘、企業(yè)微信、飛書,還有短信電話等等。即使是同樣的短信告警,不同的環(huán)境可能有不同的短信提供商,有不同的對接接口等,所以我們提供了動態(tài)消息模版的能力。
動態(tài)消息模板
-
通過動態(tài)消息模板可以引用告警事件的一些信息,進而可以組裝出帶有豐富上下文的告警信息,使告警系統(tǒng)的靈活性更廣,體驗感也更好。
-
在通知方式上設計將其做成一個個插件,用戶只需要針對不同的環(huán)境開發(fā)不同的發(fā)送插件就可以了,這種操作也可以使我們的核心流程保持一致。
通知模塊
?
在通知模塊中通過 Server 生成告警事件,再由前面的消息模板渲染得到一個真實的告警消息,然后將這個告警消息發(fā)送給通知模塊,由通知模塊結合通知方式及對象生成通知記錄并放到隊列中。為了更好地適應各種環(huán)境,這里的隊列可以是真實的消息隊列,也可以是通過數(shù)據(jù)庫模擬的消息隊列。最后由若干個 Worker 并發(fā)消費信息調用不同的發(fā)送插件發(fā)送消息;Worker 之外還有一些定時的線程輪詢/巡檢整體發(fā)送的狀態(tài)對發(fā)送失敗的消息進行重試,當重試次數(shù)達到一定量的時候生成運維上的告警。
開源夜鶯系統(tǒng)還有一個比較大的特性是動態(tài)閾值,在整體的使用中就是事件發(fā)生、觸發(fā)告警、然后人工反饋到訓練分析形成循環(huán)監(jiān)督學習的過程,并不斷調整動態(tài)閾值的生成規(guī)則。
監(jiān)控
?
在整體的監(jiān)控架構概覽中可以看到上層就是前面所說的數(shù)據(jù)面,數(shù)據(jù)面中的每個集群都會有一個Prometheus用來采集、匯聚本物理集群所有組件的監(jiān)控數(shù)據(jù),這里的 Prometheus 本質是一個 Agent,不會承擔任何數(shù)據(jù)存儲、查詢等職責,最后由 Prometheus 把采集到的監(jiān)控數(shù)據(jù) Remote Write 到系統(tǒng)面的監(jiān)控系統(tǒng)中。
監(jiān)控系統(tǒng)用來保存所有的監(jiān)控數(shù)據(jù)。為了方便對數(shù)據(jù)存儲進行水平伸縮也做了一層抽象,背后的真正實現(xiàn)可以是公有云上現(xiàn)有的云監(jiān)控服務、也可以是 S3 的對象存儲服務,還可以是我們自研的大數(shù)據(jù)存儲服務,在部分私有云的場景下,也可以對接用戶自己自定義的存儲服務。在本層的統(tǒng)一存儲中通過加一個 Query 服務承擔所有監(jiān)控數(shù)據(jù)的查詢服務,并形成了可視化的大盤展示及前端交互。
對于查詢服務也做了一些針對性的優(yōu)化。比如監(jiān)控數(shù)據(jù)只有新增、沒有更新,頻繁對某個時間段的監(jiān)控數(shù)據(jù)進行反復檢索的場景引入了水平拆分的能力,通過將時間跨度大的查詢拆分成多個小跨度的子查詢并發(fā)執(zhí)行,然后聚合回憶查詢速度。另外由于監(jiān)控數(shù)據(jù)本身不可變,我們引入了緩存,可以對部分查詢出的數(shù)據(jù)做 一個緩存加上查詢場景方便預測。通過以上兩個優(yōu)化相互促進提高了整體的查詢效率。
經(jīng)過整體優(yōu)化后的監(jiān)控系統(tǒng)核心優(yōu)勢是可以支持各種環(huán)境下的一鍵指標采集;在性能優(yōu)化上支持了數(shù)據(jù)的預聚合、降采樣等能力,豐富了整體的功能體系;并且對接了大數(shù)據(jù)存儲,某種程度上可以具備存算分離的特性使得整體系統(tǒng)的水平伸縮能力得到了很大的增強;最后也把監(jiān)控和其它的運維工具,比如日志、告警、鏈路追蹤等功能做了深度整合,優(yōu)化了產(chǎn)品的整體使用體驗。
火山引擎云原生計算產(chǎn)品全景圖
文章來源:http://www.zghlxwxcb.cn/news/detail-507205.html
?文章來源地址http://www.zghlxwxcb.cn/news/detail-507205.html
到了這里,關于字節(jié)跳動云原生大數(shù)據(jù)平臺運維管理實踐的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!