從Postgres到ScyllaDB NoSQL,速度提升349倍
譯文譯者 | 布加迪
審校 | 重樓
速度對于Coralogix而言很重要,這是一個(gè)開發(fā)團(tuán)隊(duì)信任的可觀測性平臺,可以及時(shí)發(fā)現(xiàn)問題。Coralogix使用了實(shí)時(shí)流分析管道,提供了監(jiān)控、可視化和警報(bào)等功能,無需索引。
Coralogix主要的差異化優(yōu)勢之一是分布式查詢引擎,可以快速查詢遠(yuǎn)程存儲(chǔ)的客戶歸檔中的映射數(shù)據(jù)。該引擎使用特殊的Parquet格式查詢存儲(chǔ)在對象存儲(chǔ)(Google Cloud Storage或S3)中的半結(jié)構(gòu)化數(shù)據(jù)。它最初是底層對象存儲(chǔ)上的無狀態(tài)查詢引擎,但是在查詢執(zhí)行期間讀取Parquet元數(shù)據(jù)帶來了不可接受的延遲影響。為了克服這個(gè)問題,團(tuán)隊(duì)開發(fā)了一個(gè)元數(shù)據(jù)存儲(chǔ)(簡稱為“Metastore”),以便更快地檢索和處理執(zhí)行大型查詢所需的Parquet元數(shù)據(jù)。
最初的Metastore實(shí)現(xiàn)建立在PostgreSQL之上,速度不夠快,無法滿足該公司的需求。因此,團(tuán)隊(duì)嘗試了一種新的實(shí)現(xiàn):這次使用ScyllaDB,嘗試取得了成功。團(tuán)隊(duì)取得了顯著的性能提升——查詢處理時(shí)間從30秒縮短到86毫秒。不妨深入了解一下他們是如何做到這一點(diǎn)的,并了解一下他們計(jì)劃如何使用WebAssembly用戶定義函數(shù)(UDF)和Rust進(jìn)一步優(yōu)化它。
Metastore動(dòng)機(jī)和需求
在討論Metastore實(shí)現(xiàn)細(xì)節(jié)之前,不妨先介紹一下當(dāng)初構(gòu)建Metastore的理由。
Coralogix的首席軟件工程師Dan Harris解釋道:“我們最初將這個(gè)平臺設(shè)計(jì)為底層對象存儲(chǔ)之上的無狀態(tài)查詢引擎,但我們很快意識到,查詢執(zhí)行期間讀取Parquet元數(shù)據(jù)的成本占查詢時(shí)間的很大一部分。”他們意識到,可以通過將Parquet元數(shù)據(jù)放在一個(gè)可以快速查詢的快速存儲(chǔ)系統(tǒng)中(而不是直接從底層對象存儲(chǔ)讀取和處理Parquet元數(shù)據(jù)),加快速度。
他們設(shè)想的解決方案具有以下功能:
- 以分解格式存儲(chǔ)Parquet元數(shù)據(jù),從而獲得高擴(kuò)展性和高吞吐量。
- 使用布隆過濾器,有效地識別每個(gè)查詢要掃描的文件。
- 使用事務(wù)提交日志以事務(wù)性方式添加、更新和替換底層對象存儲(chǔ)中的現(xiàn)有數(shù)據(jù)。
關(guān)鍵需求包括低延遲、讀/寫容量方面的可擴(kuò)展性以及底層存儲(chǔ)的可擴(kuò)展性。為了理解所需的極端可擴(kuò)展性,請考慮這種情況:單單一個(gè)客戶每小時(shí)生成2000個(gè)Parquet文件(每天50000個(gè)),總計(jì)每天15TB,因此單單一天僅Parquet元數(shù)據(jù)就有20GB。
最初的PostgreSQL實(shí)現(xiàn)
Harris承認(rèn):“我們在Postgres上開始了最初的實(shí)現(xiàn),當(dāng)時(shí)我們明白從長遠(yuǎn)來看,非分布式引擎是不夠的。”最初的實(shí)現(xiàn)存儲(chǔ)諸如塊(block)之類的關(guān)鍵信息,表示一行組和一個(gè)Parquet文件。這包括元數(shù)據(jù),比如文件的URL、行組索引和關(guān)于文件的少量細(xì)節(jié)。比如說:
為了優(yōu)化讀取操作,他們使用了布隆過濾器進(jìn)行高效的數(shù)據(jù)修剪。Harris解釋道:“最終,我們希望支持全文搜索之類的操作。大致來說,當(dāng)我們將這些文件攝取到系統(tǒng)中時(shí),可以為我們在文件中找到的所有不同的令牌構(gòu)建一個(gè)布隆過濾器。然后,根據(jù)特定的查詢,我們可以使用這些布隆過濾器來修剪我們需要掃描的數(shù)據(jù)。”
他們將布隆過濾器存儲(chǔ)在塊分割的環(huán)境中,將它們分成32字節(jié)大小的塊,以便高效檢索。它們獨(dú)立存儲(chǔ),因此系統(tǒng)不必在查詢時(shí)讀取整個(gè)布隆過濾器。
此外,它們?yōu)槊總€(gè)Parquet文件存儲(chǔ)列元數(shù)據(jù)。比如說:
Harris解釋:“我們寫入的文件內(nèi)容相當(dāng)寬,有時(shí)多達(dá)2萬列。因此,如果只讀取我們需要的元數(shù)據(jù),就可以真正減少任何特定查詢所需的IO數(shù)量。”
ScyllaDB實(shí)現(xiàn)
接下來,不妨看看由Harris的同事、Coralogix的高級軟件工程師Sebastian Vercruysse概述的ScyllaDB實(shí)現(xiàn)。
塊數(shù)據(jù)建模
為了新的實(shí)現(xiàn),必須重新考慮塊建模。這里有一個(gè)塊URL的例子:s3://cgx-production-c4c-archive-data/cx/parquet/v1/team_id=555585/…
…dt = 2022-12-02 / hr = 10/0246f9e9-f0da-4723-9b64 a12346095d25.parquet
粗體部分是客戶的頂層存儲(chǔ)桶;在存儲(chǔ)桶內(nèi),各項(xiàng)按小時(shí)劃分。在這種情況下,應(yīng)該使用什么作為主鍵?
- (表url)?但有些客戶比其他客戶擁有更多的Parquet文件,他們希望保持平衡。
- ((塊url,行組))?這標(biāo)識了特定塊的獨(dú)特身份,但是很難列出某一天的所有塊,因?yàn)闀r(shí)間戳不在鍵中。
- ((表url,小時(shí)))?這很管用,因?yàn)槿绻阌?4小時(shí)的查詢時(shí)間,就很容易查詢。
- ((表url,小時(shí)),塊url,行組)?這是他們選擇的。通過將塊URL和行組添加為聚簇鍵,他們可以在一小時(shí)內(nèi)輕松檢索某個(gè)特定塊,這也簡化了更新或刪除塊和行組的過程。
布隆過濾器分塊和數(shù)據(jù)建模
下一個(gè)挑戰(zhàn)是:考慮到ScyllaDB沒有提供相應(yīng)的開箱即用功能,如何驗(yàn)證某些位是否已設(shè)置。團(tuán)隊(duì)決定讀取布隆過濾器,并在應(yīng)用程序中處理它們。不過記住,他們每天為每個(gè)客戶處理多達(dá)50000個(gè)塊,每個(gè)塊含有布隆過濾器部分的262KB。總共是12GB——對于一個(gè)查詢來說太大了,無法拉回到應(yīng)用程序中。但他們不需要每次都讀取整個(gè)布隆過濾器,只需要其中的一部分,這取決于查詢執(zhí)行期間涉及的令牌。因此,他們最終將布隆過濾器分成幾行,這將讀取的數(shù)據(jù)減少到易于管理的1.6 MB。
對于數(shù)據(jù)建模,一種選擇是使用((block_url, row_group),塊索引)作為主鍵。這將為每個(gè)布隆過濾器生成8192個(gè)32字節(jié)的塊,從而生成每個(gè)分區(qū)約262 KB的均勻分布。對于同一分區(qū)中的每個(gè)布隆過濾器,使用單個(gè)批處理查詢就可以輕松插入和刪除數(shù)據(jù)。但是有一個(gè)問題會(huì)影響讀取效率:在讀取布隆過濾器之前,您需要知道塊的ID。此外,該方法需要訪問大量的分區(qū);5萬個(gè)塊意味著5萬個(gè)分區(qū)。正如Vercruysse特別指出:“就算使用像ScyllaDB這樣快的技術(shù),仍然很難為5萬個(gè)分區(qū)實(shí)現(xiàn)亞秒級處理。”
另一個(gè)選項(xiàng)(這也是他們最終決定的):((表url,小時(shí),塊索引),塊url,行組)。請注意,這是與塊相同的分區(qū)鍵,只是在分區(qū)鍵上添加了一個(gè)索引,該索引表示查詢引擎所需的第n個(gè)令牌。使用這種方法,掃描24小時(shí)時(shí)間窗口的5個(gè)令牌可生成120個(gè)分區(qū)——與之前的數(shù)據(jù)建模選項(xiàng)相比,這個(gè)改進(jìn)很出色。
此外,這種方法在讀取布隆過濾器之前不再需要塊ID,從而允許更快的讀取。當(dāng)然,總存在不足之處。在這里,由于阻塞布隆過濾器方法,他們不得不將單個(gè)布隆過濾器拆分為8192個(gè)獨(dú)特分區(qū)。與之前允許一次攝取所有布隆過濾器塊的分區(qū)方法相比,這最終限制了攝取速度。然而,能夠在一小時(shí)內(nèi)快速讀取某個(gè)塊比快速寫入來得更重要,因此他們認(rèn)為這種取舍是值得的。
數(shù)據(jù)建模問題
毫不奇怪,從SQL遷移到NoSQL需要大量的數(shù)據(jù)建模返工,包括一些試錯(cuò)。比如說,Vercruysse表示:“有一天,我認(rèn)識到我們弄亂了最小和最大時(shí)間戳——我想知道我該如何修復(fù)它。我想也許可以重命名這些列,然后讓它重新運(yùn)行。但是,如果列是聚簇鍵的一部分,你就無法重命名列。我想也許可以添加新列并運(yùn)行UPDATE查詢來更新所有行。遺憾的是,這在NoSQL中也行不通。”
最終,他們決定截?cái)啾聿⒅匦麻_始,而不是編寫遷移代碼。在這方面,他們給出的最好建議是第一次就把事情做好。
性能提升
盡管需要進(jìn)行數(shù)據(jù)建模工作,但遷移收到了很好的成效。對于Metastore塊列表:
- 每個(gè)節(jié)點(diǎn)當(dāng)前處理4到5 TB的數(shù)據(jù)。
- 他們目前每秒處理大約1萬個(gè)寫入操作,P99延遲始終低于1毫秒。
- 塊列表在一小時(shí)內(nèi)生成了大約2000個(gè)Parquet文件;就布隆過濾器而言,他們的處理時(shí)間不到20毫秒。對于5萬個(gè)文件,處理時(shí)不到500毫秒。
他們還執(zhí)行了位校驗(yàn)。但是對于5萬個(gè)Parquet文件而言,500毫秒可以滿足需求。
在列元數(shù)據(jù)處理中,P50相當(dāng)不錯(cuò),但尾部延遲較高。Vercruysse解釋:“問題在于,如果我們有5萬個(gè)Parquet文件,我們的執(zhí)行器會(huì)并行獲取所有這些文件。這意味著我們有很多并發(fā)查詢,我們沒有使用最好的磁盤。我們認(rèn)為這是問題的根源。”
ScyllaDB設(shè)置
值得注意的是,Coralogix從最初發(fā)現(xiàn)ScyllaDB到部署到擁有TB級數(shù)據(jù)的生產(chǎn)環(huán)境僅用了兩個(gè)月(這是需要數(shù)據(jù)建模工作的SQL到NoSQL遷移,而不是簡單得多的Cassandra或DynamoDB遷移)。
實(shí)現(xiàn)是在ScyllaDB Rust驅(qū)動(dòng)程序上用Rust編寫的,他們發(fā)現(xiàn)ScyllaDB Operator for Kubernetes、ScyllaDB Monitoring和ScyllaDB Manager都對快速遷移大有幫助。由于為他們自己的客戶提供低成本的可觀測性替代方案對Coralogix很重要,因此團(tuán)隊(duì)對他們的ScyllaDB基礎(chǔ)設(shè)施的性價(jià)比感到滿意,一個(gè)三節(jié)點(diǎn)聚簇有以下配置:
- 8個(gè)vCPU
- 32 GB內(nèi)存
- Arm/Graviton
- 帶寬為500mbps、IOPS為12k的EBS卷(gp3)
使用ARM可以降低成本,而決定使用彈性塊存儲(chǔ)(EBS)(gp3)卷最終歸結(jié)為可用性、靈活性和性價(jià)比。他們承認(rèn):“這是一個(gè)有爭議的決定,但我們正在努力讓它切實(shí)可行,我們會(huì)看看我們能堅(jiān)持多久。”
汲取的經(jīng)驗(yàn)
他們在這里學(xué)到的主要經(jīng)驗(yàn)是:
- 注意分區(qū)大小:使用ScyllaDB與使用Postgres的最大區(qū)別是,您必須非常仔細(xì)地考慮分區(qū)和分區(qū)大小。有效的分區(qū)和聚簇鍵選擇對性能有很大的影響。
- 考慮讀/寫模式:您還必須仔細(xì)考慮讀/寫模式。您的工作負(fù)載是不是讀取密集型?它是否涉及搭配均衡的讀寫操作?或者,以寫入操作為主?Coralogix的工作負(fù)載有大量的寫入操作,就因?yàn)?/span>他們不斷地?cái)z取數(shù)據(jù),但需要優(yōu)先考慮讀取操作,因?yàn)樽x取延遲對業(yè)務(wù)來說最關(guān)鍵。
- 避免EBS:團(tuán)隊(duì)承認(rèn)他們被警告不要使用EBS:“我們沒有聽從,但我們可能應(yīng)該聽從。如果您在考慮使用ScyllaDB,那么查看具有本地SSD的實(shí)例而不是嘗試使用EBS卷可能是好主意。”
未來計(jì)劃:結(jié)合使用WebAssembly UDF和Rust
將來,他們希望在寫入足夠大的塊和讀取不必要的數(shù)據(jù)之間找到折衷。他們將數(shù)據(jù)塊分成大約8000行,認(rèn)為可以進(jìn)一步劃分成1000行,這有望加快插入速度。
他們的最終目標(biāo)是通過充分利用WebAssembly的用戶定義函數(shù)(UDF),將更多的工作交給ScyllaDB處理。使用現(xiàn)有的Rust代碼,集成UDF將不需要把數(shù)據(jù)發(fā)回給應(yīng)用程序,為分塊調(diào)整和潛在的改進(jìn)提供了靈活性。
Vercruysse表示:“我們已經(jīng)用Rust編寫了所有內(nèi)容。如果我們可以開始使用UDF,這樣我們不必向應(yīng)用程序發(fā)回任何其他內(nèi)容。這給了我們更大的余地來處理分塊。”
原文標(biāo)題:From Postgres to ScyllaDB NoSQL, with a 349x Speed Boost,作者:Cynthia Dunlop