為什么可變性對實(shí)時(shí)數(shù)據(jù)分析至關(guān)重要
?像Uber、Facebook和Amazon這樣成功的數(shù)據(jù)驅(qū)動(dòng)型公司依靠的是實(shí)時(shí)數(shù)據(jù)分析,為電子商務(wù)提供個(gè)性化的客戶體驗(yàn),管理車隊(duì)和供應(yīng)鏈,以及實(shí)現(xiàn)內(nèi)部運(yùn)營的自動(dòng)化,都需要對最新鮮的數(shù)據(jù)進(jìn)行即時(shí)洞察。
為了提供實(shí)時(shí)分析,公司需要一個(gè)現(xiàn)代技術(shù)基礎(chǔ)設(shè)施,包括這三點(diǎn)。
- 一個(gè)實(shí)時(shí)數(shù)據(jù)源,如網(wǎng)絡(luò)點(diǎn)擊流、傳感器產(chǎn)生的物聯(lián)網(wǎng)事件等。
- 一個(gè)平臺(tái),如 Apache Kafka/Confluent, Spark或 Amazon Kinesis用于發(fā)布該事件數(shù)據(jù)流。
- 一個(gè)實(shí)時(shí)分析數(shù)據(jù)庫,能夠連續(xù)攝取大量的實(shí)時(shí)事件,并在幾毫秒內(nèi)返回查詢結(jié)果。
事件流/流處理已經(jīng)存在了近十年。它已被充分理解。而實(shí)時(shí)分析則不然。實(shí)時(shí)分析數(shù)據(jù)庫的技術(shù)要求之一是可變性??勺冃允且环N超級(jí)能力,它能夠?qū)?shù)據(jù)存儲(chǔ)中的現(xiàn)有記錄進(jìn)行更新或變異。
可變和不可變數(shù)據(jù)之間的區(qū)別
在我們談?wù)摓槭裁纯勺冃允菍?shí)時(shí)分析的關(guān)鍵之前,重要的是了解什么是可變性。
可變數(shù)據(jù)是指存儲(chǔ)在表記錄中的數(shù)據(jù),可以被擦除或用更新的數(shù)據(jù)來更新。例如,在一個(gè)雇員地址的數(shù)據(jù)庫中,假設(shè)每條記錄都有個(gè)人的姓名和他們當(dāng)前的居住地址。如果雇員從一個(gè)地方搬到另一個(gè)地方,當(dāng)前的地址信息將被覆蓋。
傳統(tǒng)上,這些信息會(huì)被存儲(chǔ)在交易型數(shù)據(jù)庫中----。 Oracle Database, MySQL, PostgreSQL等--因?yàn)樗鼈冊试S可變性。存儲(chǔ)在這些交易型數(shù)據(jù)庫中的任何字段都是可更新的。對于今天的實(shí)時(shí)分析,我們還有很多其他的原因需要可變性,包括數(shù)據(jù)的豐富性和回填數(shù)據(jù)。
不可變的數(shù)據(jù)則相反--它不能被刪除或修改。更新不是寫在現(xiàn)有的記錄上,而是只做追加。這意味著更新被插入到不同的位置,或者你被迫重寫新舊數(shù)據(jù)以正確存儲(chǔ)它。稍后會(huì)有更多關(guān)于這個(gè)缺點(diǎn)的內(nèi)容。不可變的數(shù)據(jù)存儲(chǔ)在某些分析場景中是很有用的。
不變性的歷史作用
數(shù)據(jù)倉庫普及了不變性,因?yàn)樗鼫p輕了可擴(kuò)展性,特別是在分布式系統(tǒng)中。分析性查詢可以通過在RAM或SSD中緩存大量訪問的只讀數(shù)據(jù)來加速進(jìn)行。如果緩存的數(shù)據(jù)是易變的,并且有可能發(fā)生變化,那么就必須不斷地與原始數(shù)據(jù)進(jìn)行核對,以避免變得陳舊或錯(cuò)誤。這將增加數(shù)據(jù)倉庫的操作復(fù)雜性;另一方面,不可變的數(shù)據(jù)則不會(huì)產(chǎn)生這樣的問題。
不變性也減少了意外刪除數(shù)據(jù)的風(fēng)險(xiǎn),這在某些用例中是一個(gè)重要的好處。以醫(yī)療保健和病人健康記錄為例。像新的醫(yī)療處方會(huì)被添加,而不是寫在現(xiàn)有的或過期的處方上,這樣你總是有一個(gè)完整的醫(yī)療記錄。
最近,一些公司試圖將Kafka和Kinesis等流發(fā)布系統(tǒng)與用于分析的不可變的數(shù)據(jù)倉庫配對。這些事件系統(tǒng)捕獲物聯(lián)網(wǎng)和網(wǎng)絡(luò)事件,并將其存儲(chǔ)為日志文件。這些流式日志系統(tǒng)很難查詢,所以人們通常會(huì)將日志中的所有數(shù)據(jù)發(fā)送到一個(gè)不可變的數(shù)據(jù)系統(tǒng),如 Apache Druid來執(zhí)行批量分析。
數(shù)據(jù)倉庫將把新流的事件附加到現(xiàn)有的表格中。由于過去的事件在理論上是不會(huì)改變的,因此不可更改地存儲(chǔ)數(shù)據(jù)似乎是一個(gè)正確的技術(shù)決定。雖然一個(gè)不可變的數(shù)據(jù)倉庫只能按順序?qū)懭霐?shù)據(jù),但它確實(shí)支持隨機(jī)數(shù)據(jù)讀取。這使得分析性商業(yè)應(yīng)用能夠有效地查詢數(shù)據(jù),無論何時(shí)何地,它都被存儲(chǔ)起來。
不變數(shù)據(jù)的問題
當(dāng)然,用戶很快發(fā)現(xiàn),由于許多原因,數(shù)據(jù)確實(shí)需要更新。這對于事件流來說尤其如此,因?yàn)槎鄠€(gè)事件可以反映現(xiàn)實(shí)生活中物體的真實(shí)狀態(tài)?;蛘呔W(wǎng)絡(luò)問題或軟件崩潰會(huì)導(dǎo)致數(shù)據(jù)延遲交付。晚到的事件需要被重新加載或回填。
公司也開始接受數(shù)據(jù)豐富化,將相關(guān)數(shù)據(jù)添加到現(xiàn)有表格中。最后,公司開始不得不刪除客戶數(shù)據(jù),以履行消費(fèi)者隱私法規(guī),如GDPR和其 "被遺忘的權(quán)利"。"
不可變的數(shù)據(jù)庫制造商被迫創(chuàng)造變通方法,以便插入更新。一個(gè)流行的方法是由 Apache Druid和其他公司使用的一種流行方法被稱為寫時(shí)復(fù)制。數(shù)據(jù)倉庫通常將數(shù)據(jù)加載到一個(gè)暫存區(qū)域,然后再分批攝入數(shù)據(jù)倉庫,在那里進(jìn)行存儲(chǔ)、索引并為查詢做好準(zhǔn)備。如果有任何事件延遲到達(dá),數(shù)據(jù)倉庫將不得不寫入新的數(shù)據(jù),并將其保存在數(shù)據(jù)倉庫中。 重寫臨近數(shù)據(jù)以便以正確的順序正確地存儲(chǔ)所有數(shù)據(jù)。
在一個(gè)不可改變的數(shù)據(jù)系統(tǒng)中處理更新的另一個(gè)糟糕的解決方案是將原始數(shù)據(jù)保留在分區(qū)A(上面),并將晚到的數(shù)據(jù)寫入不同的位置,即分區(qū)B。應(yīng)用程序,而不是數(shù)據(jù)系統(tǒng),將不得不跟蹤所有鏈接但分散的記錄的存儲(chǔ)位置,以及任何由此產(chǎn)生的依賴關(guān)系。這個(gè)過程被稱為參考完整性,必須由應(yīng)用軟件來實(shí)現(xiàn)。
這兩種解決方法都有很大的問題。寫時(shí)復(fù)制要求數(shù)據(jù)倉庫花費(fèi)大量的處理能力和時(shí)間--當(dāng)更新很少的時(shí)候還可以忍受,但隨著更新數(shù)量的增加,成本和速度都是無法忍受的。這就造成了嚴(yán)重的數(shù)據(jù)延遲,可能排除了實(shí)時(shí)分析。數(shù)據(jù)工程師還必須手動(dòng)監(jiān)督寫入時(shí)的復(fù)制,以確保所有新舊數(shù)據(jù)被準(zhǔn)確寫入和索引。
實(shí)施參照完整性的應(yīng)用程序有其自身的問題。查詢必須反復(fù)檢查他們是否從正確的位置提取數(shù)據(jù),否則就有可能出現(xiàn)數(shù)據(jù)錯(cuò)誤。當(dāng)同一記錄的更新分散在數(shù)據(jù)系統(tǒng)的多個(gè)地方時(shí),嘗試任何查詢優(yōu)化,如緩存數(shù)據(jù),也變得更加復(fù)雜。雖然這些在節(jié)奏較慢的批處理分析系統(tǒng)中可能是可以容忍的,但當(dāng)涉及到關(guān)鍵任務(wù)的實(shí)時(shí)分析時(shí),它們是巨大的問題。
可變性有助于機(jī)器學(xué)習(xí)
在Facebook,我們建立了一個(gè)ML模型,在所有新的日歷事件被創(chuàng)建時(shí)掃描它們,并將其存儲(chǔ)在事件數(shù)據(jù)庫中。然后,實(shí)時(shí)地,一個(gè)ML算法將檢查這個(gè)事件,并決定它是否是垃圾郵件。如果它被歸類為垃圾郵件,那么ML模型代碼將在現(xiàn)有的事件記錄中插入一個(gè)新字段,將其標(biāo)記為垃圾郵件。因?yàn)橛羞@么多的事件被標(biāo)記并立即被刪除,為了提高效率和速度,數(shù)據(jù)必須是可變的。許多現(xiàn)代的ML服務(wù)系統(tǒng)都效仿我們的例子,選擇了可變的數(shù)據(jù)庫。
這種水平的性能在不可改變的數(shù)據(jù)中是不可能的。一個(gè)使用寫時(shí)復(fù)制的數(shù)據(jù)庫將很快被它必須更新的標(biāo)記事件的數(shù)量所拖累。如果數(shù)據(jù)庫將原始事件存儲(chǔ)在分區(qū)A,并將標(biāo)記的事件附加到分區(qū)B,這將需要額外的查詢邏輯和處理能力,因?yàn)槊總€(gè)查詢都必須合并兩個(gè)分區(qū)的相關(guān)記錄。這兩種解決方法都會(huì)給我們的Facebook用戶帶來難以忍受的延遲,增加數(shù)據(jù)錯(cuò)誤的風(fēng)險(xiǎn),并給開發(fā)人員和/或數(shù)據(jù)工程師帶來更多的工作。
可變性如何實(shí)現(xiàn)實(shí)時(shí)分析
在Facebook,我?guī)椭O(shè)計(jì)了可變的分析系統(tǒng),提供實(shí)時(shí)的速度、效率和可靠性。
我創(chuàng)立的技術(shù)之一是開源的 RocksDB的高性能鍵值引擎,該引擎被MySQL、Apache Kafka和 CockroachDB.RocksDB的數(shù)據(jù)格式是一種可變的數(shù)據(jù)格式,這意味著你可以更新、覆蓋或刪除一條記錄中的個(gè)別字段。它也是Rockset的嵌入式存儲(chǔ)引擎,Rockset是我創(chuàng)立的一個(gè)實(shí)時(shí)分析數(shù)據(jù)庫,具有完全可變的索引。
通過調(diào)整開源的RocksDB,可以實(shí)現(xiàn)對事件和更新的SQL查詢,而這些事件和更新僅在幾秒鐘前到達(dá)。這些查詢可以在低至幾百毫秒的時(shí)間內(nèi)返回,即使在復(fù)雜的、臨時(shí)的和高并發(fā)的情況下。RocksDB的壓縮算法還能自動(dòng)合并舊的和更新的數(shù)據(jù)記錄,以確保查詢訪問最新的、正確的版本,并防止數(shù)據(jù)膨脹,以免妨礙存儲(chǔ)效率和查詢速度。
通過選擇RocksDB,你可以避免不可改變的數(shù)據(jù)倉庫的笨拙、昂貴和產(chǎn)生錯(cuò)誤的變通方法,如寫時(shí)復(fù)制和在不同分區(qū)中分散更新。
總而言之,可變性是當(dāng)今實(shí)時(shí)分析的關(guān)鍵,因?yàn)槭录骺赡苁遣煌暾幕蚴虻?。?dāng)這種情況發(fā)生時(shí),數(shù)據(jù)庫將需要糾正和回填丟失和錯(cuò)誤的數(shù)據(jù)。為了確保高性能、低成本、無錯(cuò)誤的查詢和開發(fā)人員的效率,你的數(shù)據(jù)庫必須支持可變性。?