Keystone 流式處理平臺(tái)是 Netflix 的數(shù)據(jù)骨干,是數(shù)據(jù)驅(qū)動(dòng)基礎(chǔ)設(shè)施的重要組成部分。Keystone 平臺(tái)主要提供兩種服務(wù):數(shù)據(jù)管道和流式處理即服務(wù)(SPaaS)。數(shù)據(jù)管道由流式路由服務(wù)和 Kafka 消息服務(wù)組成,負(fù)責(zé)近乎實(shí)時(shí)地生成、收集、處理、聚合和移動(dòng)微服務(wù)產(chǎn)生的事件。流式處理即服務(wù)讓用戶能夠構(gòu)建和運(yùn)行自定義的流式處理托管應(yīng)用程序,用戶可以專注于應(yīng)用程序的業(yè)務(wù)邏輯,而平臺(tái)負(fù)責(zé)提供伸縮、運(yùn)營(yíng)和和領(lǐng)域?qū)I(yè)知識(shí)。
單個(gè)流式作業(yè):
通過(guò)平臺(tái)管理這些作業(yè):
流式處理的挑戰(zhàn)
1. 伸縮
Netflix 為來(lái)自 190 多個(gè)國(guó)家的 1.3 億用戶提供服務(wù)。流式處理平臺(tái)每天處理數(shù)萬(wàn)億個(gè)事件和 PB 級(jí)別的數(shù)據(jù),以支持日常的業(yè)務(wù)需求。隨著用戶數(shù)量的持續(xù)增長(zhǎng),整個(gè)平臺(tái)需要進(jìn)行伸縮。
2. 多樣化的用例
Keystone 路由服務(wù):這個(gè)服務(wù)負(fù)責(zé)根據(jù)用戶的配置將事件路由到托管接收器上。每個(gè)傳遞線路都通過(guò)并行流式處理作業(yè)來(lái)實(shí)現(xiàn)。用戶可以定義可選的過(guò)濾器或投影聚合。事件最終被傳遞給存儲(chǔ)接收器,便于后續(xù)的批處理或流式處理(這些處理實(shí)現(xiàn)了至少一次語(yǔ)義)。用戶可以在延遲和重復(fù)處理之間做出權(quán)衡。
流式處理即服務(wù):SPaaS 平臺(tái)只在生產(chǎn)環(huán)境中運(yùn)行了大約一年時(shí)間,但我們已經(jīng)遇到了各種各樣的需求。以下是一些常見的問(wèn)題和權(quán)衡。
作業(yè)狀態(tài):從完全無(wú)狀態(tài)并行處理到需要數(shù)十 TB 本地狀態(tài)存儲(chǔ)的作業(yè)。
作業(yè)復(fù)雜性:從將所有 operator 鏈接在一起的并行作業(yè),到具有多個(gè) shuffle 階段和復(fù)雜會(huì)話邏輯的復(fù)雜作業(yè) DAG。
窗口 / 會(huì)話:窗口大小從幾秒鐘(即捕獲事務(wù)的開始 / 結(jié)束事件)到數(shù)小時(shí)的自定義會(huì)話窗口。
流量模式:不同用例的流量模式存在很大差異。它們可能是突發(fā)的,也可能保持在 GB/ 秒級(jí)別不變。
故障恢復(fù):有些用例需要秒級(jí)的低故障恢復(fù)延遲,當(dāng)作業(yè)持有很大的狀態(tài)并涉及 shuffle 時(shí),就變得相當(dāng)具有挑戰(zhàn)性。
回填(backfill)和回放(rewind):某些作業(yè)需要從批處理數(shù)據(jù)源重放數(shù)據(jù)或從先前的檢查點(diǎn)回放數(shù)據(jù)。
資源爭(zhēng)用:作業(yè)可能會(huì)在任何物理資源上產(chǎn)生瓶頸:CPU、網(wǎng)絡(luò)帶寬或內(nèi)存等。用戶依賴平臺(tái)提供的用于進(jìn)行性能調(diào)整的見解和指導(dǎo)。
重復(fù)與延遲:應(yīng)用程序在重復(fù)與延遲方面可能有不同的權(quán)衡偏好。
事件排序:大多數(shù)用例不依賴嚴(yán)格的排序,但有些確實(shí)會(huì)依賴排序。
傳遞和處理語(yǔ)義:某些用例允許管道中丟失一些事件,而其他用例可能要求更高的持久性保證。某些有狀態(tài)的流式作業(yè)期望具備恰好一次處理保證,計(jì)算狀態(tài)需要始終保持一致。
用戶受眾:我們的用戶群十分廣泛,從技術(shù)嫻熟的分布式系統(tǒng)工程師到業(yè)務(wù)分析師,有些團(tuán)隊(duì)選擇基于我們的平臺(tái)產(chǎn)品構(gòu)建特定領(lǐng)域的平臺(tái)服務(wù)。
3. 多租戶
Keystone 支持?jǐn)?shù)千個(gè)流式作業(yè),從數(shù)據(jù)傳輸、數(shù)據(jù)分析,一直到支持微服務(wù)架構(gòu)模式。因?yàn)榱魇阶鳂I(yè)的多樣性,為了向每個(gè)用戶提供有意義的服務(wù)級(jí)別保證,基礎(chǔ)設(shè)施需要提供運(yùn)行時(shí)和運(yùn)營(yíng)隔離,同時(shí)還要最小化共享平臺(tái)開銷。
4. 彈性
盡管大多數(shù)流都具有固定的流量模式,我們?nèi)匀恍枰屜到y(tǒng)能夠應(yīng)對(duì)突發(fā)情況(流行的節(jié)目上線或意外故障引起的流量爆發(fā)),而且能夠自動(dòng)適應(yīng)并對(duì)這些情況做出響應(yīng)。
5. 云原生彈性
Netflix 的微服務(wù)完全是在云端運(yùn)行的。云具有彈性、持續(xù)變化、更高的故障率等特點(diǎn),因此我們需要讓系統(tǒng)能夠監(jiān)控、檢測(cè)和容忍故障,包括網(wǎng)絡(luò)不穩(wěn)定、實(shí)例故障、區(qū)域故障、集群故障、服務(wù)間擁塞或回壓、區(qū)域?yàn)?zāi)難故障等。
6. 運(yùn)營(yíng)開銷
我們的平臺(tái)目前為數(shù)千個(gè)路由作業(yè)和流式應(yīng)用程序提供服務(wù)。如果依靠平臺(tái)團(tuán)隊(duì)手動(dòng)管理所有流,成本會(huì)很高。因此,應(yīng)該由用戶負(fù)責(zé)聲明作業(yè)的生命周期,同時(shí)基礎(chǔ)設(shè)施應(yīng)該盡可能自動(dòng)化。
7. 敏捷性
我們希望能夠進(jìn)行快速的開發(fā)和部署,每天可以進(jìn)行多次部署。我們也希望能夠保持用戶使用平臺(tái)的敏捷性。
平臺(tái)思維與設(shè)計(jì)原則
1. 可實(shí)施性
這個(gè)平臺(tái)的主要目標(biāo)之一是讓其他團(tuán)隊(duì)能夠?qū)W⒂跇I(yè)務(wù)邏輯,讓流式處理作業(yè)的實(shí)驗(yàn)、實(shí)現(xiàn)和運(yùn)營(yíng)變得更容易。通過(guò)平臺(tái)將“難啃的硬骨頭”抽離出來(lái),消除用戶的復(fù)雜性,這將極大提升團(tuán)隊(duì)的敏捷性并促進(jìn)產(chǎn)品的創(chuàng)新。我們努力讓用戶能夠:
快速發(fā)現(xiàn)數(shù)據(jù)和開展試驗(yàn),通過(guò)數(shù)據(jù)驅(qū)動(dòng)的創(chuàng)新來(lái)推動(dòng)產(chǎn)品的發(fā)展;快速的流式處理解決方案原型設(shè)計(jì);充滿信心地進(jìn)行服務(wù)的生產(chǎn)和運(yùn)營(yíng);深入了解性能、成本、作業(yè)生命周期狀態(tài)等,以便能夠做出明智的決策;進(jìn)行自助服務(wù)。
2. 構(gòu)建塊
為了能夠讓用戶專注于業(yè)務(wù)邏輯而不必?fù)?dān)心分布式系統(tǒng)的復(fù)雜性或某些預(yù)先存在的解決方案的一般性細(xì)節(jié),我們需要為用戶提供一組可以輕松接入到流式作業(yè) DAG 的可組合 operator。
此外,流式作業(yè)本身也可以成為其他下游服務(wù)的構(gòu)建塊。我們與一些合作伙伴團(tuán)隊(duì)合作,構(gòu)建“托管數(shù)據(jù)集”和其他特定領(lǐng)域的平臺(tái)。
我們還努力通過(guò)利用其他構(gòu)建模塊(如容器運(yùn)行時(shí)服務(wù)、平臺(tái)動(dòng)態(tài)配置、通用注入框架等)與 Netflix 軟件生態(tài)系統(tǒng)深度集成。這不僅有助于我們基于其他現(xiàn)有解決方案構(gòu)建出新的服務(wù),還讓我們的用戶更加熟悉開發(fā)和運(yùn)營(yíng)環(huán)境。
3. 可調(diào)整的權(quán)衡
任何一個(gè)復(fù)雜的分布式系統(tǒng)本身都有一定的局限性,因此在設(shè)計(jì)這種系統(tǒng)時(shí)需要考慮到各種權(quán)衡,如延遲與重復(fù)、一致性與可用性、嚴(yán)格排序與隨機(jī)排序等。某些用例還可能涉及各種權(quán)衡組合,所以平臺(tái)必須提供調(diào)整入口,為個(gè)人用戶提供定制的可能性,讓他們可以聲明對(duì)系統(tǒng)的需求。
4. 故障是頭等公民
在大規(guī)模分布式系統(tǒng)中,故障是一種常態(tài),在云環(huán)境中就更是如此。任何設(shè)計(jì)合理的云原生系統(tǒng)都應(yīng)該將故障視為一等公民。以下是影響我們?cè)O(shè)計(jì)的一些重要方面:
假設(shè)網(wǎng)絡(luò)是不可靠的;信任底層運(yùn)行時(shí)基礎(chǔ)設(shè)施,但需要自動(dòng)修復(fù)能力;實(shí)現(xiàn)多租戶的作業(yè)級(jí)別隔離;出現(xiàn)故障時(shí)減少影響范圍;出現(xiàn)組件狀態(tài)漂移或發(fā)生災(zāi)難故障時(shí)能夠進(jìn)行自動(dòng)調(diào)節(jié);正確處理和傳播回壓。
5. 關(guān)注點(diǎn)分離
在用戶和平臺(tái)之間:用戶應(yīng)該能夠通過(guò)平臺(tái) UI 或 API 聲明“目標(biāo)狀態(tài)”。目標(biāo)狀態(tài)被保存在單個(gè)事實(shí)源當(dāng)中,應(yīng)該由平臺(tái)作業(yè)流程負(fù)責(zé)處理從“當(dāng)前狀態(tài)”到“目標(biāo)狀態(tài)”的變化。
在控制平面和數(shù)據(jù)平面之間:控制平面負(fù)責(zé)作業(yè)流程編排和協(xié)調(diào),數(shù)據(jù)平面負(fù)擔(dān)處理繁重的任務(wù),以確保一切處在目標(biāo)狀態(tài)內(nèi)。
在不同的子組件之間:每個(gè)組件負(fù)責(zé)自己的作業(yè)和狀態(tài)。每個(gè)組件的生命周期都是獨(dú)立的。運(yùn)行時(shí)基礎(chǔ)設(shè)施:流式處理作業(yè)部署在開源的 Netflix Titus Container 運(yùn)行時(shí)服務(wù)上,該服務(wù)提供配置、調(diào)度、資源級(jí)別的隔離(CPU、網(wǎng)絡(luò)、內(nèi)存)、高級(jí)網(wǎng)絡(luò)等。
我們的方法考慮到上述的挑戰(zhàn)和設(shè)計(jì)原則,我們幾乎完成了一個(gè)聲明式的調(diào)和架構(gòu),用以實(shí)現(xiàn)自助服務(wù)平臺(tái)。這個(gè)架構(gòu)允許用戶通過(guò) UI 聲明所需的作業(yè)屬性,平臺(tái)將編排和協(xié)調(diào)子服務(wù),以確保盡快達(dá)到目標(biāo)狀態(tài)。
以下部分介紹了平臺(tái)的架構(gòu)和平臺(tái)設(shè)計(jì)的各個(gè)方面
1. 聲明式調(diào)和
聲明式調(diào)和協(xié)議被用在整個(gè)架構(gòu)棧上,從控制平面到數(shù)據(jù)平面。從邏輯上講,利用這個(gè)協(xié)議的目的是將用戶聲明的目標(biāo)狀態(tài)的單個(gè)副本保存為持久的事實(shí)來(lái)源,其他服務(wù)基于這些事實(shí)來(lái)源進(jìn)行調(diào)和。當(dāng)出現(xiàn)狀態(tài)沖突時(shí),不管是臨時(shí)故障導(dǎo)致還是正常的用戶觸發(fā)動(dòng)作,這些事實(shí)來(lái)源都應(yīng)該被視為權(quán)威,其他所有版本的狀態(tài)應(yīng)該被視為當(dāng)前視圖。整個(gè)系統(tǒng)最終需要將事實(shí)來(lái)源作為調(diào)和目標(biāo)。
事實(shí)來(lái)源存儲(chǔ)是一種持久的存儲(chǔ),用于保存所有需要的狀態(tài)信息。我們目前使用的是 AWS RDS,它是整個(gè)系統(tǒng)的唯一事實(shí)來(lái)源。例如,如果 Kafka 集群因?yàn)?ZooKeeper 狀態(tài)損壞而出現(xiàn)故障,我們可以根據(jù)事實(shí)來(lái)源重新創(chuàng)建整個(gè)集群。相同的原則也適用于流式處理層,這使得持續(xù)自我修復(fù)和自動(dòng)化運(yùn)營(yíng)成為可能。
這個(gè)協(xié)議的另一個(gè)好處是操作的冪等性。這意味著從用戶傳給控制平面再傳給作業(yè)集群的控制指令和不可避免的故障條件不會(huì)造成長(zhǎng)時(shí)間的對(duì)立面效應(yīng)。這些服務(wù)最終會(huì)自行調(diào)和,同時(shí)也帶來(lái)了運(yùn)營(yíng)的敏捷性。
2. 部署編排
控制平面通過(guò)與 Netflix 內(nèi)部的持續(xù)部署引擎 Spinnaker 發(fā)生交互來(lái)編排作業(yè)流程。Spinnaker 對(duì) Titus 容器運(yùn)行時(shí)集成進(jìn)行了抽象,控制平面可以以不同的權(quán)衡方式來(lái)協(xié)調(diào)部署。
Flink 集群由作業(yè)管理器和任務(wù)管理器組成。我們通過(guò)為每個(gè)作業(yè)創(chuàng)建獨(dú)立的 Flink 集群來(lái)實(shí)現(xiàn)完整的作業(yè)隔離。唯一的共享服務(wù)是用于達(dá)成共識(shí)協(xié)調(diào)的 ZooKeeper 和用于保存檢查點(diǎn)狀態(tài)的 S3 后端。
在重新部署期間,無(wú)狀態(tài)應(yīng)用程序可以在延遲或重復(fù)處理之間做出權(quán)衡。對(duì)于有狀態(tài)應(yīng)用程序,用戶可以選擇從檢查點(diǎn) / 保存點(diǎn)恢復(fù)或從新狀態(tài)重新開始。
3. 自助工具
對(duì)于路由作業(yè):用戶可以通過(guò)自助服務(wù)請(qǐng)求生成事件(可聲明過(guò)濾器或投影聚合),然后將事件路由到托管接收器(如 Elasticsearch、Hive)或者讓下游實(shí)例進(jìn)行實(shí)時(shí)的消費(fèi)。
自助服務(wù) UI 從用戶那里獲取輸入,并將其轉(zhuǎn)換為最終期望的系統(tǒng)狀態(tài)。我們因此可以構(gòu)建一個(gè)能夠?qū)崿F(xiàn)目標(biāo)狀態(tài)的編排層,還可以抽離出用戶可能不關(guān)心的某些信息(例如要發(fā)送到哪個(gè) Kafka 集群或某些容器的配置),并在必要的時(shí)候提供靈活性。
對(duì)于自定義 SPaaS 作業(yè),我們提供了命令行工具用于生成 Flink 代碼模板存儲(chǔ)庫(kù)和 CI 集成等。在用戶簽入代碼后,CI 自動(dòng)化流程將開始構(gòu)建 Docker 鏡像,并通過(guò)平臺(tái)后端注冊(cè)鏡像,用戶可以執(zhí)行部署和其他操作。
4. 流式處理引擎
我們目前正在基于 Apache Flink 為 Keystone 的分析用例構(gòu)建一個(gè)生態(tài)系統(tǒng)。我們計(jì)劃集成和擴(kuò)展 Mantis 流式處理引擎。
5. 連接器、托管 operator 和應(yīng)用程序抽象
為了幫助我們的用戶提高開發(fā)敏捷性和創(chuàng)新,我們提供了全方位的抽象,包括托管連接器、讓用戶可以接入處理 DAG 的 operator,以及與各種平臺(tái)服務(wù)的集成。
我們?yōu)?Kafka、Elasticsearch、Hive 等提供了托管連接器。這些連接器抽象出了自定義連線格式、序列化、批處理 / 限定行為以及接入處理 DAG 的便利性。我們還提供動(dòng)態(tài)數(shù)據(jù)源 / 接收器 operator,用戶可以在不同的數(shù)據(jù)源或接收器之間切換,而無(wú)需重新構(gòu)建。
其他托管的 operator 還包括過(guò)濾器、投影聚合和易于理解的數(shù)據(jù)衛(wèi)生自定義 DSL。我們將繼續(xù)與用戶合作開發(fā)更多的 operator,并讓更多團(tuán)隊(duì)可以使用這些 operator。
6. 配置和不可變部署
多租戶配置管理有一定的挑戰(zhàn)性。我們希望提供動(dòng)態(tài)且易于管理的配置體驗(yàn)(用戶無(wú)需重新提交和構(gòu)建代碼)。
托管的配置和用戶定義配置都保存在應(yīng)用程序的屬性文件中,這些配置可以被環(huán)境變量覆蓋,也可以通過(guò)自助 UI 覆蓋這些屬性。這種方法適用于我們的調(diào)和架構(gòu),用戶通過(guò) UI 聲明想要的配置并部署編排,確保運(yùn)行時(shí)的最終一致性。
7. 自我恢復(fù)
在分布式系統(tǒng)中,故障是不可避免的。我們完全相信故障會(huì)在任何時(shí)候發(fā)生,所以我們的系統(tǒng)被設(shè)計(jì)成具有自我恢復(fù)能力,這樣就不必在半夜醒來(lái)處理事故。
從架構(gòu)上看,平臺(tái)組件服務(wù)被隔離出來(lái),以便在發(fā)生故障時(shí)減少影響范圍。調(diào)和架構(gòu)還通過(guò)持續(xù)調(diào)和來(lái)確保系統(tǒng)級(jí)別的自我恢復(fù)能力。
單個(gè)作業(yè)遵循相同的隔離模式,以減少故障影響。但是,為了處理故障并從故障中恢復(fù),每個(gè)托管流式作業(yè)都配有健康監(jiān)視器。健康監(jiān)視器是運(yùn)行在 Flink 集群中的內(nèi)部組件,負(fù)責(zé)檢測(cè)故障情況并執(zhí)行自我修復(fù):集群任務(wù)管理器漂移:當(dāng) Flink 容器資源視圖與容器運(yùn)行時(shí)視圖不匹配時(shí)就會(huì)出現(xiàn)漂移,通過(guò)主動(dòng)終止受影響的容器,可以自動(dòng)糾正漂移。
暫停作業(yè)管理器首領(lǐng):如果未能選舉出首領(lǐng),集群就會(huì)進(jìn)入無(wú)腦狀態(tài),此時(shí)需要對(duì)作業(yè)管理器執(zhí)行糾正措施。不穩(wěn)定的容器資源:如果某個(gè)任務(wù)管理器出現(xiàn)不穩(wěn)定的模式(如定期重啟 / 故障),它將被替換。網(wǎng)絡(luò)分區(qū):如果容器遇到網(wǎng)絡(luò)連接問(wèn)題,它將自動(dòng)終止。
8. 回填和回放
因?yàn)楣收鲜遣豢杀苊獾?,所以有時(shí)候用戶可能需要回填或回放處理作業(yè)。
對(duì)于備份到數(shù)據(jù)倉(cāng)庫(kù)中的源數(shù)據(jù),我們?cè)谄脚_(tái)中構(gòu)建了相應(yīng)的功能,用來(lái)動(dòng)態(tài)切換數(shù)據(jù)源而無(wú)需修改和重新構(gòu)建代碼。這種方法有一定的局限性,建議將它應(yīng)用在無(wú)狀態(tài)作業(yè)上。或者,用戶可以選擇回到之前自動(dòng)保存的檢查點(diǎn)開始重新處理。
9. 監(jiān)控和警報(bào)
所有單個(gè)的流式作業(yè)都配有個(gè)性化的監(jiān)控和警報(bào)儀表盤。這有助于平臺(tái) / 基礎(chǔ)設(shè)施團(tuán)隊(duì)和應(yīng)用程序團(tuán)隊(duì)監(jiān)控和診斷問(wèn)題。
10. 可靠性和測(cè)試
隨著平臺(tái)和底層基礎(chǔ)設(shè)施服務(wù)不斷創(chuàng)新,提供越來(lái)越多的新功能和改進(jìn),快速采用這些變化的壓力是自下而上的(架構(gòu)層面)。
隨著應(yīng)用程序的開發(fā)和發(fā)布,可靠性的壓力是自上而下的。于是,壓力在中間相遇了。為了獲得信任,我們需要讓平臺(tái)和用戶能夠有效地測(cè)試整個(gè)技術(shù)棧。我們堅(jiān)持為所有用戶進(jìn)行單元測(cè)試、集成測(cè)試、金絲雀運(yùn)營(yíng)。我們正在這方面取得進(jìn)展,但仍然有很多問(wèn)題需要解決。
現(xiàn)在和未來(lái)在過(guò)去的一年半中,Keystone 流式處理平臺(tái)每天可以處理萬(wàn)億個(gè)事件。我們的合作伙伴團(tuán)隊(duì)已經(jīng)用它構(gòu)建各種流式分析應(yīng)用。此外,我們也看到了一些建立在 Keystone 之上的更高級(jí)別的平臺(tái)。
但是,我們的故事并未就此結(jié)束。要實(shí)現(xiàn)我們的平臺(tái)愿景,還有很長(zhǎng)的路要走。以下是我們正在研究的一些有趣的事項(xiàng):
模式(schema)
讓平臺(tái)交互變得更靈活的服務(wù)層
提供流式 SQL 和其他更高級(jí)別的抽象,為不同的用戶提供價(jià)值
分析和機(jī)器學(xué)習(xí)用例
微服務(wù)事件溯源架構(gòu)模式
責(zé)任編輯:安旭環(huán)