实时数据聚合怎么破
作者簡(jiǎn)介
數(shù)據(jù)猩猩,攜程數(shù)據(jù)分析總監(jiān),關(guān)注分布式數(shù)據(jù)存儲(chǔ)和實(shí)時(shí)數(shù)據(jù)分析。
實(shí)時(shí)數(shù)據(jù)分析一直是個(gè)熱門話題,需要實(shí)時(shí)數(shù)據(jù)分析的場(chǎng)景也越來越多,如金融支付中的風(fēng)控,基礎(chǔ)運(yùn)維中的監(jiān)控告警,實(shí)時(shí)大盤之外,AI模型也需要消費(fèi)更為實(shí)時(shí)的聚合結(jié)果來達(dá)到很好的預(yù)測(cè)效果。
實(shí)時(shí)數(shù)據(jù)分析如果講的更加具體些,基本上會(huì)牽涉到數(shù)據(jù)聚合分析。
數(shù)據(jù)聚合分析在實(shí)時(shí)場(chǎng)景下,面臨的新問題是什么,要解決的很好,大致有哪些方面的思路和框架可供使用,本文嘗試做一下分析和厘清。
在實(shí)時(shí)數(shù)據(jù)分析場(chǎng)景下,最大的制約因素是時(shí)間,時(shí)間一變動(dòng),所要處理的源頭數(shù)據(jù)會(huì)發(fā)生改變,處理的結(jié)果自然也會(huì)因此而不同。在此背景下,引申出來的三大子問題就是:
通過何種機(jī)制觀察到變化的數(shù)據(jù)?
通過何種方式能最有效的處理變化數(shù)據(jù),將結(jié)果并入到原先的聚合分析結(jié)果中
分析后的數(shù)據(jù)如何讓使用方及時(shí)感知并獲取
可以說,數(shù)據(jù)新鮮性和處理及時(shí)性是實(shí)時(shí)數(shù)據(jù)處理中的一對(duì)基本矛盾。
另外實(shí)時(shí)是一個(gè)相對(duì)的概念,在不同場(chǎng)景下對(duì)應(yīng)的時(shí)延也差異很大,借用Uber給出的定義,大體來區(qū)分一下實(shí)時(shí)處理所能接受的時(shí)延范圍。
一、數(shù)據(jù)新鮮性
為簡(jiǎn)單起見,把數(shù)據(jù)分成兩大類,一類是關(guān)鍵的交易性數(shù)據(jù),以存儲(chǔ)在關(guān)系型數(shù)據(jù)庫為主,另一類是日志型數(shù)據(jù),以存儲(chǔ)在日志型消息隊(duì)列(如kafka)為主。
第二類數(shù)據(jù),消費(fèi)端到感知到最新的變化數(shù)據(jù),采用內(nèi)嵌的pull機(jī)制,比較容易實(shí)現(xiàn),同時(shí)日志類數(shù)據(jù),絕大部分是append-only,不涉及到刪改,無論是采用ClickHouse還是使用TimeScaleDB都可以達(dá)到很好的實(shí)時(shí)聚合效果,這里就不再贅述。
針對(duì)第一類存儲(chǔ)在數(shù)據(jù)庫中的數(shù)據(jù),要想實(shí)時(shí)感知到變化的數(shù)據(jù)(這里的變化包含有增/刪/改三種操作類型),有兩種打法。
打法一:基于時(shí)間戳方式的數(shù)據(jù)同步,假設(shè)在表設(shè)計(jì)時(shí),每張表中都有datachange_lasttime字段表示最近一次操作發(fā)生的時(shí)間,同步程序會(huì)定期掃描目標(biāo)表,把datachange_lasttime不小于上次同步時(shí)間的數(shù)據(jù)拉出進(jìn)行同步。
這種處理方式的主要缺點(diǎn)是無法感知到數(shù)據(jù)刪除操作,為了規(guī)避這個(gè)不足,可以采用邏輯刪除的表設(shè)計(jì)方式。數(shù)據(jù)刪除并不是采取物理刪除,只是修改表示數(shù)據(jù)已經(jīng)刪除的列中的值標(biāo)記為刪除或無效。使用這種方法雖然讓同步程序可以感知到刪除操作,但額外的成本是讓應(yīng)用程序在刪除和查詢時(shí),操作語句和邏輯都變得復(fù)雜,降低了數(shù)據(jù)庫的可維護(hù)性。
打法一的變種是基于觸發(fā)器方式,把變化過的數(shù)據(jù)推送給同步程序。這種方式的成本,一方面是需要設(shè)計(jì)實(shí)現(xiàn)觸發(fā)器,另一方面是了降低了insert/update/delete操作的性能, 提升了時(shí)延,降低了吞吐量。
打法二:基于CDC(Change Data Capture)的方式進(jìn)行增量數(shù)據(jù)同步,這種方式對(duì)數(shù)據(jù)庫設(shè)計(jì)的侵入性最小,性能影響也最低,同時(shí)可以獲得豐富的開源組件支持,如Cannal對(duì)MySQL有很好支持,Debezium對(duì)PostgreSQL有支持。利用這些同步組件,把變化數(shù)據(jù)寫入到Kafka,然后供后續(xù)實(shí)時(shí)數(shù)據(jù)分析進(jìn)一步處理。
二、數(shù)據(jù)關(guān)聯(lián)
新鮮數(shù)據(jù)在獲取到之后,第一步常見操作是進(jìn)行數(shù)據(jù)補(bǔ)全(Data Enrichment), 數(shù)據(jù)補(bǔ)全自然涉及到多表之間的關(guān)聯(lián)。這里有一個(gè)痛點(diǎn),要關(guān)聯(lián)的數(shù)據(jù)并不一定也會(huì)在增量數(shù)據(jù)中,如機(jī)票訂單數(shù)據(jù)狀態(tài)發(fā)生變化,要找到變化過訂單涉及到的航段信息。由于訂單信息和航段信息是兩張不同的表維護(hù),如果只是拿增量數(shù)據(jù)進(jìn)行關(guān)聯(lián),那么有可能找不到航段信息。這是一個(gè)典型的實(shí)時(shí)數(shù)據(jù)和歷史數(shù)據(jù)關(guān)聯(lián)的例子。
解決實(shí)時(shí)數(shù)據(jù)和歷史數(shù)據(jù)關(guān)聯(lián)一種非常容易想到的思路就是當(dāng)實(shí)時(shí)數(shù)據(jù)到達(dá)的時(shí)候,去和數(shù)據(jù)庫中的歷史數(shù)據(jù)進(jìn)行關(guān)聯(lián),這種做法一是加大了數(shù)據(jù)庫的訪問,導(dǎo)致數(shù)據(jù)庫負(fù)擔(dān)增加,另一方面是關(guān)聯(lián)的時(shí)延會(huì)大大加長。為了讓歷史數(shù)據(jù)迅速可達(dá),自然想到添加緩存,緩存的引入固然可以減少關(guān)聯(lián)處理時(shí)延,但容易引起緩存數(shù)據(jù)和數(shù)據(jù)庫中的數(shù)據(jù)不一致問題,另外緩存容量不易估算,成本增加。
有沒有別的套路可以嘗試?這個(gè)必須要有。
可以在數(shù)據(jù)庫側(cè)先把數(shù)據(jù)進(jìn)行補(bǔ)全,利用行轉(zhuǎn)列的方式,形成一張寬表,實(shí)現(xiàn)數(shù)據(jù)自完備,寬表的變化內(nèi)容,利用CDC機(jī)制,讓外界實(shí)時(shí)感知。
三、計(jì)算及時(shí)性
在解決好數(shù)據(jù)變化實(shí)時(shí)感知和數(shù)據(jù)完備兩個(gè)問題之后,進(jìn)入最關(guān)鍵一環(huán),數(shù)據(jù)聚合分析。為了達(dá)到結(jié)果準(zhǔn)確和處理及時(shí)之間的平衡,有兩大解決方法:一為全量,一為增量。
3.1 全量計(jì)算(1m<時(shí)延<5m)
全量計(jì)算以時(shí)間代價(jià),對(duì)變化過的數(shù)據(jù)進(jìn)行全量分析,分析結(jié)果有最高的準(zhǔn)確性和可靠性。成本是花費(fèi)較長的計(jì)算時(shí)間和消耗較多的計(jì)算資源。可以使用的分析引擎或計(jì)算框架有 Apache Spark 和 Apache Flink。
全量數(shù)據(jù)容量一般會(huì)比較大,為了節(jié)約存儲(chǔ),同時(shí)為了方便數(shù)據(jù)過濾和減少不必要的網(wǎng)絡(luò)傳輸,大多會(huì)使用列式存儲(chǔ), 列式存儲(chǔ)使用較多的當(dāng)屬Parquet和ORC。
列式存儲(chǔ)最大的不足是無法進(jìn)行刪/改操作,為了支持刪改,一般會(huì)把列式存儲(chǔ)和行式存儲(chǔ)相結(jié)合。最近時(shí)間內(nèi)變化的數(shù)據(jù)采用行式存儲(chǔ)如avro格式,然后定期合并成列式存儲(chǔ)。非常成功和紅火的Apache Hudi和Delta IO就是基于這種思路。
3.2 增量計(jì)算
假設(shè)當(dāng)前處理的時(shí)間窗口中有10萬條記錄,因?yàn)槠渲胁坏?00條的記錄發(fā)生變化,而對(duì)所有記錄的聚合指標(biāo)進(jìn)行計(jì)算重演,顯然不是非常合理,那么有沒有可能只對(duì)增量數(shù)據(jù)導(dǎo)致的變化聚合指標(biāo)進(jìn)行重算。答案是肯定的,或者說在部分場(chǎng)景下,是可以實(shí)現(xiàn)的。
讓我們把增量計(jì)算分成幾種不同情況:
1)增量數(shù)據(jù)會(huì)添加新的聚合記錄,對(duì)原有計(jì)算結(jié)果無影響?
2)增量數(shù)據(jù)會(huì)添加新的聚合記錄,并導(dǎo)致原有計(jì)算結(jié)果部分失效?
3)增量數(shù)據(jù)不添加新的聚合記錄,但導(dǎo)致原有計(jì)算結(jié)果全部失效
第1、2兩種情況下,增量計(jì)算會(huì)帶來實(shí)時(shí)性上的收益,第三種不會(huì),因?yàn)樗兄笜?biāo)均被破壞,都需要重演,已經(jīng)褪化成全量計(jì)算。
增量處理模型除了Apache Flink之外,非常著名的還有Microsoft提出的Naiad模型,后者更為高效。由于后者只提供了非常底層的調(diào)用API,在生態(tài)建設(shè)方面遠(yuǎn)不如Apache Flink,但其思想深刻影響了TensorFlow等框架的設(shè)計(jì)和實(shí)現(xiàn),等有時(shí)間再詳細(xì)介紹一下Naiad。
上面討論的全量也好,增量也罷,都是把數(shù)據(jù)從數(shù)據(jù)庫拉出來再進(jìn)行計(jì)算,那么有沒有可能在數(shù)據(jù)庫內(nèi)部實(shí)現(xiàn)增量計(jì)算的可能?
Oracle在12.x版本中提供物理視圖(materialized view)的自動(dòng)刷新機(jī)制,這意味著用戶可以把實(shí)時(shí)聚合邏輯定義在物理視圖中,然后每當(dāng)有數(shù)據(jù)更新,視圖會(huì)被自動(dòng)更新。既然Oracle有,那么在開源的世界里一定會(huì)有對(duì)應(yīng)的東西出現(xiàn),最起碼會(huì)有相應(yīng)的影子在浮現(xiàn),這個(gè)影子就是PostgreSQL IVM。
PostgreSQL IVM使用到Transition Table這個(gè)概念,在觸發(fā)器中,用戶可以看到變化前和變化后的數(shù)據(jù),從而計(jì)算出變更的內(nèi)容,利用這些Delta數(shù)據(jù),進(jìn)行刷新預(yù)先定義好的物理視圖。
四、計(jì)算觸發(fā)機(jī)制
定時(shí)觸發(fā)
trigger for every new element
計(jì)算成本比較
五、聚合結(jié)果實(shí)時(shí)可見
聚合結(jié)果的存儲(chǔ)要支持upsert語義,聚合結(jié)果的消費(fèi)者實(shí)時(shí)感知到,同時(shí)聚合結(jié)果的存儲(chǔ)要有水平可擴(kuò)性。結(jié)合這三個(gè)要求,比較推薦使用NoSQL來進(jìn)行指標(biāo)的存儲(chǔ),具體可以使用MongoDB。
六、小結(jié)
本文嘗試對(duì)實(shí)時(shí)數(shù)據(jù)聚合分析中涉及到的問題和常見思路進(jìn)行梳理,文中定有不少疏漏,不足之處希望讀者批評(píng)指正。
推薦閱讀:
1.Hive Sql最全詳解!
2.該如何設(shè)計(jì)數(shù)倉的匯總層(DWS)
3.Flink流計(jì)算常用算子大全
4.萬字詳解數(shù)據(jù)倉庫建設(shè)體系
總結(jié)
- 上一篇: NICO EXCHANGE NICO 交
- 下一篇: 计算机类课程嵌入式系统的特点及其应用,嵌