小紅書圖數據庫在分布式并行查詢上的探索
一、背景介紹
1. 圖數據庫介紹
關于圖數據庫的概念,這里不作詳細闡述。而是以圖表的形式,對其與另外幾種 NoSQL 產品進行比較。圖數據庫本身歸屬于 NoSQL 存儲,而諸如KV 類型、寬表類型、文檔類型、時序類型等其他 NoSQL 產品,各自具備獨特的特性。從上圖左側的坐標軸中可以看到,從 KV 到寬表、文檔,再到圖,數據關聯度和查詢復雜度是越來越高的。前三者,即 KV、寬表和文檔,主要關注的是單個記錄內部的豐富性,但并未涉及記錄間的關系。而圖數據庫則專注于處理這些關系。圖數據庫主要適用于需要挖掘深鏈路或多維度關系的業務場景。
接下來通過一個具體示例,再來對比一下圖數據庫與關系型數據庫。這是社交網絡中常見的一種表結構,包括四個數據表:用戶表、好友關系表、點贊行為表以及筆記詳情表。比如要查詢 Tom 這個用戶的好友所點贊的筆記的詳細信息,那么可能需要編寫一段冗長的 SQL 語句。在該 SQL 語句中,涉及到三個 join 操作,首先將用戶表和好友關系表進行連接,從而獲取 Tom 的所有好友信息。然后,將得到的中間結果與點贊行為表進行連接,以確定 Tom 的好友都點贊了哪些筆記。最后,還需要對先前生成的臨時表和筆記詳情表進行連接,以便最終獲取這些筆記的全部內容。
關系型數據庫中的 join 操作通常復雜度較高,其執行過程中需消耗大量的 CPU 資源、內存空間以及 IO,雖然我們可以通過精心的設計,例如針對所要關聯的列創建索引,以降低掃描操作的比例,通過索引匹配來實現一定程度的性能提升。然而,這樣的舉措所產生的成本相對較高,因為所有新的場景都需要創建索引,要考慮如何撰寫 SQL 中的 join 條件,選擇哪個表作為驅動表等等,這些都需要耗費大量的精力和時間。
而如果采用圖數據庫,則會簡單很多。首先進行圖建模,創建兩類頂點,分別為用戶和筆記,同時創建兩類邊,一類是好友關系,即用戶到用戶的邊;另一類是用戶到筆記的點贊關系。當我們將這些數據存儲到圖數據庫中時,它們在邏輯上呈現出一種網狀結構,其關聯關系已經非常明確。查詢時,如上圖中使用 Gremlin 語句,僅需四行代碼即可獲取到所需的信息。其中第一行 g.V().has('name', 'Tom'),用于定位 Tom 節點,兩個 out 子句,第一個 out 子句用于查找 Tom 的好友,第二個 out 子句用于查找 Tom 的點贊筆記。當第二個 out 子句執行完畢后,就可以遍歷所有外部的綠色頂點,即筆記節點。最后,讀取它們的 content 屬性。可以發現,與關系型數據庫相比,圖數據庫的查詢語句更加簡潔、清晰易懂。
此外,圖數據庫還有一個更為顯著的優勢,就是在存儲時,它已經將頂點及其關系作為一等公民進行設計和存儲,因此在進行鄰接邊訪問和關系提取時,效率極高。即使數據規模不斷擴大,也不會導致查詢時間顯著增加。
2. 圖數據庫在小紅書的使用場景
小紅書是一個年輕的生活方式共享平臺。在小紅書,用戶可以通過短視頻、圖片等方式,直觀地記錄生活的點點滴滴。在小紅書內部,圖數據庫被廣泛應用于多種場景中,下面將分別列舉在線、近線以及離線場景的實例。
第一個案例是社交實時推薦功能。小紅書具有典型的社區特性,用戶可以在其中點贊、發布貼文、關注他人、轉發信息等。譬如我進入某用戶主頁并停留了較長時間,那么系統便會判定我對該用戶有興趣,而這個用戶可能同樣吸引了他人的注意。因此,系統會將該用戶的其他關注者以及他們所關注的其他用戶推薦給我,因為我們有共同的興趣愛好,所以他們的關注內容我也有可能感興趣,這便是一種簡單的實時推薦機制。
第二個案例是社區風控機制,小紅書社區會對優質筆記或優質視頻的創作者進行獎勵,但這也給了一些羊毛黨可乘之機,他們發布一些質量較低的帖子或筆記,將其發布在互刷群中,或者轉發給親朋好友,讓他們點贊和轉發,從而偽裝成所謂的高質量筆記,以此來騙取平臺的獎勵。社區業務部門擁有一些離線算法,能夠對已有的數據進行分析,識別出哪些用戶和筆記屬于作弊用戶,在圖中用紅色的點標出。在近線場景中,系統會判斷每個頂點在多跳關系內接觸到的作弊用戶的數量或比例,如果超過一定的閾值,則會將這個人標記為潛在的風險用戶,即黃色的頂點,進而采取防范措施。
第三個案例是離線任務的調度問題,在大數據平臺中,往往存在大量的離線任務,而任務之間的依賴關系錯綜復雜,如何合理地調度任務,成為一個棘手的問題。圖結構非常適合解決這類問題,通過拓撲排序或其他算法,可以找出最受依賴的任務,并進行反向推理。
3. 業務上面臨的困境
小紅書在社交、風控及離線任務調度等場景中均采用了圖數據庫,然而在實際應用過程中遇到了諸多挑戰。在此,簡要介紹其中基于實時推薦場景的一個痛點。
業務訴求是能即時向用戶推送可能感興趣的“好友”或“內容”,如圖所示,A 與 F 之間僅需經過三次跳躍即可到達,因此 A 與 F 構成了一種可推薦的關聯關系,如果能即時完成此推薦,則能有效提升用戶使用體驗,提升留存率。然而,由于先前 REDgraph 在某些方面的能力尚未完善,業務一直只采用了一跳和兩跳查詢,未使用三跳,風控場景也是類似。
業務對時延的具體要求為,社交推薦要求三跳的 P99 低于 50 毫秒,風控則要求三跳的 P99 低于 200 毫秒,這是目前 REDgraph 所面臨的一大難題。
那為何一至二跳可行,三跳及以上就難以實現呢?對此,我們基于圖數據庫與其他類型系統在工作負載的差異,做了一些難點與可行性分析。
首先在并發方面,OLTP 的并發度很高,而 OLAP 則相對較低。圖的三跳查詢,服務的仍然是在線場景,其并發度也相對較高,這塊更貼近 OLTP 場景。
其次在計算復雜度方面,OLTP 場景中的查詢語句較為簡單,包含一到兩個 join 操作就算是較為復雜的情況了,因此,OLTP 的計算復雜度相對較低。OLAP 則是專門為計算設計的,因此其計算復雜度自然較高。圖的三跳查詢則介于 OLTP 和 OLAP 之間,它雖不像 OLAP 那樣需要執行大量的計算,但其訪問的數據量相對于 OLTP 來說還是更可觀的,因此屬于中等復雜度。
第三,數據時效性方面,OLTP 對時效性的要求較高,必須基于最新的數據提供準確且實時的響應。而在 OLAP 場景中則沒有這么高的時效要求,早期的 OLAP 數據庫通常提供的是 T+1 的時效。圖的三跳查詢,由于我們服務的是在線場景,所以對時效性有一定的要求,但并不是非常高。使用一小時或 10 分鐘前的狀態進行推薦,也不會產生過于嚴重的后果。因此,我們將其定義為中等時效性。
最后,查詢失敗代價方面。OLTP 一次查詢的成本較低,因此其失敗的代價也低;而 OLAP 由于需要消耗大量的計算資源,因此其失敗代價很高。圖查詢在這塊,更像 OLTP 場景一些,但畢竟訪問的數據量較大,因此同樣歸屬到中等。
總結一下:圖的三跳查詢具備 OLTP 級別的并發度,卻又有比一般 OLTP 大得多的數據訪問量和計算復雜度,所以比較難在在線場景中使用。好在其對數據時效性的要求沒那么高,也能容忍一些查詢失敗,所以我們能嘗試對其優化。
正如前面提到的,在小紅書,三跳查詢的首要目標還是降低延遲。有些系統中會考慮犧牲一點時延來換取吞吐的大幅提升,而這在小紅書業務上是不可接受的。如果吞吐上不去,還可以通過擴大集群規模來兜底,而如果時延高則直接不能使用了。
二、原架構問題分析
第二部分將詳述原體系結構中所存在的問題及其優化措施。
1. RedGraph 整體架構
REDgraph 的整體結構如上圖所示,其與當前較為流行的 NewSQL,如 TiDB 的架構構相似。采用了存儲和計算分離的架構,并且存儲是 shared-nothing 的。三類節點分別為 meta-server,元信息的管理;query-server,用戶查詢請求的處理;store-server,存儲數據。
2. RedGraph 圖切分方式
圖切分的含義為,如果我們擁有一個巨大的圖,規模在百億到千億水平,應該如何將其存儲在分布式集群之中,以及如何對其進行切分。在工業界中,主要存在兩種典型的切分策略,即邊切分和點切分。
邊切分,以頂點為中心,這種切分策略的核心思想是每個頂點會根據其 ID 進行哈希運算,并將其路由到特定的分片上。每個頂點上的每條邊在磁盤中都會被存儲兩份,其中一份與起點位于同一分片,另一份則與終點位于同一分片。如上圖中的例子,其中涉及到 ABC 三個頂點的哈希定位結果。在這個例子中,A 至 C 的這條出邊,被放置在與 A 同一個節點上。同樣,B 至 C 的出邊跟 B 放到了一起,最后一個桶中保存了 C 以及 C 的入邊,即由 A 和 B 指向 C 的兩條入邊。
點切分,與邊切分相對應,以邊為中心,每個頂點會在集群內保存多份。
這兩種切分方式各有利弊。邊切分的優點在于每個頂點與其鄰居都保存在同一個分片中,因此當需要查詢某個頂點的鄰居時,其訪問局部性極佳;其缺點在于容易負載不均,且由于節點分布的不均勻性,引發熱點問題。點切分則恰恰相反,其優點在于負載較為均衡,但缺點在于每個頂點會被切成多個部分,分配到多個機器上,因此更容易出現同步問題。
REDgraph 作為一個在線的圖查詢系統,選擇的是邊切分的方案。
3. 優化方案 1.0
我們之前已經實施了一些優化,可以稱之為優化方案 1.0。當時主要考慮的是如何快速滿足用戶需求,因此我們的方案包括:首先根據常用的查詢模式提供一些定制化的算法,這些算法可以跳過解析、校驗、優化和執行等繁瑣步驟,直接處理請求,從而實現加速。其次,我們會對每個頂點的扇出操作進行優化,即每個頂點在向外擴展時,對其擴展數量進行限制,以避免超級點的影響,降低時延。此外,我們還完善了算子的下推策略,例如 filter、sample、limit 等,使其盡可能在存儲層完成,以減少網絡帶寬的消耗。同時,我們還允許讀從節點、讀寫線程分離、提高垃圾回收頻率等優化。
然而,這些優化策略有一個共性,就是每個點都比較局部化和零散,因此其通用性較低。比如第一個優化,如果用戶需要發起新的查詢模式,那么此前編寫的算法便無法滿足其需求,需要另行編寫。第二個優化,如果用戶所需要的是頂點的全部結果,那此項也不再適用。第三個優化,如果查詢中本身就不存在這些運算符,那么自然也無法進行下推操作。諸如此類,通用性較低,因此需要尋找一種更為通用,能夠減少重復工作的優化策略。
4. 新方案思考
如上圖中,是對一個耗時接近一秒的三跳查詢的 profile 分析。我們發現在每一跳產出的記錄數量上,第一跳至第二跳擴散了 200 多倍,第二跳至第三跳擴散了 20 多倍,表現在結果上,需要計算的數據行數從 66 條直接躍升至 45 萬條,產出增長速度令人驚訝。此外,我們發現三跳算子在整個查詢過程中占據了較大的比重,其在查詢層的耗時更是占據了整個查詢的 80% 以上。
那么應該如何進行優化呢?在數據庫性能優化方面,有許多可行的方案,主要分為三大類:存儲層的優化、查詢計劃的優化以及執行引擎的優化。
由于耗時大頭在查詢層,所以我們重點關注這塊。因為查詢計劃的優化是一個無止境的工程,用戶可能會寫出各種查詢語句,產生各種算子,難以找到一個通用且可收斂的方案來覆蓋所有情況。而執行引擎則可以有一個相對固定的優化方案,因此我們優先選擇了優化執行引擎。
圖數據庫的核心就是多跳查詢執行框架,而其由于數據量大,計算量大,導致查詢時間較長,因此我們借鑒了 MPP 數據庫和其他計算引擎的思想,提出了分布式并行查詢的解決方案。
原有的多跳查詢執行流程如上圖所示。假設我們要查詢933 頂點的三跳鄰居節點 ID,即檢索到藍圈中的所有頂點。經過查詢層處理后,將生成右圖所示執行計劃,START 表示計劃的起點,本身并無實際操作。GetNeighbor 算子則負責實際查詢頂點的鄰居,例如根據 933 找到 A 和 B。后續的 Project、InnerJoin 以及 Project 等操作均為對先前產生的結果進行數據結構的轉換、處理及裁剪等操作,以確保整個計算流程的順利進行。正是后續的這幾個算子耗費的時延較高。
算子的物理執行過程如上圖所示。查詢服務器(Query Server)執行 START 指令后,將請求發送至存儲節點(Store Server)中的一個,該節點獲取其鄰居信息,并反饋至查詢層。查詢層接收到結果后,會對其中的數據進行去重或其他相關處理,然后再次下發,此次的目標是另外兩個 Store Server。這一步驟即為獲取二度鄰居的信息,返回至查詢層后,再對這些結果進行匯總和去重處理,如此往復。
在整個流程中,我們明顯觀察到三個問題。首先,圖中藍色方框內的算子都是串行運行的,必須等待前一個計算完成后,才能執行下一個。對于大規模的數據,串行執行的效率顯然無法與并行執行相提并論。其次,Query Server 內部存在一個同步點,即左側標注為紅色的字(等待所有響應返回),要求 query Server 等待所有存儲節點的響應返回后,才能繼續執行后續操作。若某一存儲節點的數據量較大或負載過高,導致響應速度較慢,則會耗費大量時間在等待上,因此我們考慮取消同步等待的過程。最后,存儲層的結果需要先轉發回查詢層進行簡單處理,然后再向下發送,這無疑增加了不必要的轉發成本。如果存儲節點(Store Server)能夠自行轉發,便可避免一次網絡轉發過程,從而降低開銷。
相應的解決策略便是三點:算子并行執行,取消同步點,以及讓 Store Server 的結果直接轉發?;诖耍覀兲岢隽巳缦碌母脑焖悸?。
首先,查詢服務器(Query Server)將整個執行計劃以及執行計劃所需的初始數據傳輸至存儲服務器(Store Server),之后 Store Server 自身來驅動整個執行過程。以 Store Server 1 為例,當它完成首次查詢后,便會根據結果 ID 所在的分區,將結果轉發至相應的 Store Server。各個 Store Server 可以獨立地繼續進行后續操作,從而實現整個執行動作的并行化,并且無同步點,也無需額外轉發。
需要說明的是,圖中右側白色方框比左側要矮一些,這是因為數據由上方轉到下方時,進行了分區下發,必然比在查詢服務器接收到的總數據量要少。
可以看到,在各部分獨立驅動后,并未出現等待或額外轉發的情況,Query Server 只需在最后一步收集各個 Store Server 的結果并聚合去重,然后返回給客戶端。如此一來,整體時間相較于原始模型得到了顯著縮短。
三、分布式并行查詢實現
分布式并行查詢的具體實現,涉及到多個關鍵元素。接下來介紹其中一些細節。
1. 如何保證不對 1-2 跳產生負優化
首先一個問題是,在進行改造時如何確保不會對原始的 1-2 跳產生負優化。在企業內部進行新的改造和優化時,必須謹慎評估所采取的措施是否會對原有方案產生負優化。我們不希望新方案還未能帶來收益,反而破壞了原有的系統。因此,架構總體上與原來保持一致。在 Store Server 內部插入了一層,稱為執行層,該層具有網絡互聯功能,主要用于分布式查詢的轉發。Query Server 層則基本保持不變。
這樣,當接收到用戶的執行計劃后,便可根據其跳數選擇不同的處理路徑。若為 1 至 2 跳,則仍沿用原有的流程,因為原有的流程能夠滿足 1-2 跳的業務需求,而 3 跳及以上則采用分布式查詢。
2. 如何與原有執行框架兼容
第二個關鍵問題是如何維持與原有執行框架的兼容性,即在進行分布式技術改造時,不希望對原有代碼進行大幅修改,而希望通過最小化的調整達到目的。這里參考了其他產品的一些思路,具體來說,就是在一些需要切換分區訪問的算子(如 GetNeighbor 等)之前,添加具有路由功能的算子。這里有三種,分別為 Forward、Converge 和 Merge。Forward 的作用顯而易見,即當遇到任何運算符時,表示數據需要轉發給其他節點處理,而當前節點無法繼續處理。Converge 運算符則是在整個執行計劃的最后一步添加,用于指示最終結果應返回至最初接收用戶請求的節點。在 Converge 后,還需添加一個 Merge 運算符,該節點在收到結果后需要進行聚合操作,然后才能將結果返回給客戶端。如此修改后,我們只需實現這三個算子本身,無需對其他算子進行任何修改,且不會對網絡層造成干擾,實現了極輕量級的改造。在執行計劃修改的過程中,我們還進行了一些額外的優化,例如將 GroupBy、OrderBy 等算子也進行了下推處理。
3. 如何做熱點處理
第三問題是如何進行熱點處理,或者說是重復 ID 的處理。當整個執行流程改造成由 Store Server 自行驅動之后,會出現一種情況,例如邊 AC 和邊 BC 位于兩個不同的 Store Server 上,查詢都是單跳的操作,可能左側的機器查詢 AC 操作更快,而右側的機器查詢 BC 操作較慢,因此導致左側的機器首先查找到 C,然后將結果轉發給其他機器,向下一級中間機器查詢 C 的鄰居,即執行 GetNeighbor from C,右側的節點雖然稍顯滯后,但也需要執行查詢 C 鄰居操作。
若不進行任何操作,在中間節點便會對 C 的鄰居進行兩次查詢,造成資源浪費。優化策略非常簡單,即在每個存儲節點之上添加 NeighborCache。本質是這樣一個 Map 結構,每當讀請求到來時,首先在 Map 中查找是否存在 C 的鄰節點,若存在則獲取,否則再訪問存儲層,訪問完畢后填充 NeighborCache 的條目,每個條目的生存時間都非常短暫。之所以短暫,其充分性在于左右節點發出請求的間隔肯定不會很久,不會達到數秒的級別,否則業務上也無法承受。因此,NeighborCache 的每個條目也只需存活在秒級,超過則自動刪除。必要性則在于 Map 的 Key 的組合模式,即 Vid+edgeType 這種組合模式還是非常多的,若不及時清理,內存很容易爆炸。此外,查詢層從 Disk Store 中查詢到數據并向 NeighborCache 回填時,也需進行內存檢查,以避免 OOM。
4. 如何做負載均衡
第四個問題是怎么做負載均衡,包括兩塊,一個是存儲的均衡,另一個是計算的均衡。
首先存儲的均衡在以邊切分的圖存儲里面其實是很難的,因為它天然的就是把頂點和其鄰居全部都存在了一起,這是圖數據庫相比其他數據庫的優勢,也是其要承擔的代價。所以目前沒有一個徹底的解決方法,只能在真的碰到此問題時擴大集群規模,讓數據的哈希打散能夠更加均勻一些,避免多個熱點都落在同一個機器的情況。而在目前的業務場景上來看,其實負載不均衡的現象不算嚴重,例如風控的一個比較大的集群,其磁盤用量最高和最低的也不超過 10%,所以問題其實并沒有想象中的那么嚴重。
另外一個優化方法是在存儲層及時清理那些過期的數據,清理得快的話也可以減少一些不均衡。
計算均衡的問題。存儲層采用了三副本的策略,若業務能夠接受弱一致的讀取(實際上大多數業務均能接受),我們可以在請求轉發時,查看三副本中的哪個節點負載較輕,將請求轉發至該節點,以盡量平衡負載。此外,正如前文所述,熱點結果緩存也是一種解決方案,只要熱點處理速度足夠快,計算的不均衡現象便不易顯現。
5. 如何做流程控制
接下來的問題是如何進行流程控制。執行流程轉變為由 Store Server 自行驅動之后,僅第一個 Stage 有 Driver 參與,而后續步驟則由 Worker 之間相互傳輸和控制。那么,Driver 應如何了解當前執行的階段以及其對應的某個 Stage 何時可以開始執行呢?有一種解決方案便是要求每一個 Worker 在接收到請求后或下發請求后,向 Driver 回傳一個響應,如此便可在 Driver 內記錄所有節點的進度信息,這是可行的。
然而,此設計方案較重,因為 driver 并不需要深入了解每個節點的具體狀態,它僅需判斷自身是否具備執行條件,因此在工程實現中,我們采取了更為輕便的方式,即每個 Stage 生成一個 32 位的二進制數字 reqId,將其發送至 ACKer 確認器以傳達相關信息。Acker 也以 32 位整數形式記錄該信息,Stage1 同樣會接收到 Stage 0 發來的 reqId,經過內部一系列處理后,它會將接收到的 reqId 與自身生成的 3 個 reqId 進行異或運算,并將異或結果再次發送至確認器。由于異或操作的特性,當兩個數相同時,結果為 0,因此,當 0010 數進行異或運算后,這部分將變為 0。這就意味著 Stage 0 已經執行完畢。后續的所有階段均采用類似的方式,當確認器的結果再次變為 0 時,表示整個執行流程已經完成,即前面的 Stage 0 至 Stage 3 已經讀取完畢,此時可以執行 Stage 4,從而實現流程驅動。
另一個重要的問題便是全程鏈路的超時自檢,例如在 Stage2 或 Stage3 的某一個節點上運行時間過長,此時不能讓其余所有節點一直等待,因為客戶端已經超時了。因此我們在每個算子內部的執行邏輯中都設置了一些埋點,用以檢查算子的執行是否超過了用戶側的限制時間,一旦超過,便立即終止自身的執行,從而迅速地自我銷毀,避免資源的無謂浪費。
以上就是對一些關鍵設計的介紹。
6. 性能測試
我們在改造工程完成后進行了性能測試,采用 LDBC 組織提供的 SNB 數據集,生成了一個 SF100 級別的社交網絡圖譜,規模達到 3 億頂點,18 億條邊。我們主要考察其一跳、二跳、三跳、四跳等多項查詢性能。
根據評估結果顯示,在一跳和二跳情況下,原生查詢和分布式查詢性能基本相當,未出現負優化現象。從三跳起,分布式查詢相較于原生查詢能實現 50% 至 60% 的性能提升。例如,在 Max degree 場景下的分布式查詢已將時延控制在 50 毫秒以內。在帶有 Max degree 或 Limit 值的情況下,時延均在 200 毫秒以下。盡管數據集與實際業務數據集存在差異,但它們皆屬于社交網絡領域,因此仍具有一定的參考價值。
四跳查詢,無論是原始查詢還是分布式查詢,其時延的規?;旧隙荚诿胫潦嗝氲姆秶鷥?。因為四跳查詢涉及的數據量實在過于龐大,已達到數十萬甚至百萬級別,僅依賴分布式并行查詢難以滿足需求,因此需要采取其他策略。然而,即便如此,我們所提出的改進方案相較于原始查詢模式仍能實現 50% 至 70% 的提升,效果還是很可觀的。
四、總結與展望
我們結合 MPP 的思想,成功地對原有 REDgraph 的執行流程實現了框架級別上的革新,提出了一種較為通用的圖中分布式并行查詢方案。在完成改良后,至少在業務層面上,原本無法執行的三跳任務現在得以實現,這無疑是一項重大突破。同時,通過實驗驗證,效率得到了 50% 的顯著提升。
隨著小紅書 DAU 的持續攀升,業務數據規模正逐步向著萬億的規模發展。在這樣的大背景下,業務對多條查詢的需求也將日益強烈。因此,該方案本身具有優化的潛力,具備落地的可能性,且有實際應用的場景。因此,我們將繼續致力于提升 REDgraph 的查詢能力。另外,盡管該方案主要在圖數據庫上實施,但其思想對于其他具有類似重查詢需求的在線存儲系統同樣具有一定的參考價值。因此,其他產品也可借鑒此方案,設計出符合自身需求的高效執行框架。
最后。我們誠摯地邀請對技術有著極致追求、志同道合的同學們加入我們的團隊。在此,我們特別推薦兩個渠道:一是掃描上方二維碼加入微信群,共同探討圖數據庫相關的技術問題;二是關注小紅書的技術公眾號 REDtech,該公眾號會不定期發布技術文章,歡迎大家關注和轉發。
五、問答環節
Q:介紹中提到的 LDBC-SF 100 那個數據集選擇測試樣本的規模有多大?另外,分布式方式能夠提升性能,但分布式實施過程中可能會帶來消息通信的成本開支,反而可能導致測試結果表現不佳,可否介紹一下小紅書的解決方法。
A:三跳基本上都是在幾十萬的量級。
關于分布式引發的消息通信,這確實是一個問題,但在我們的場景下,目前這還不是最嚴重的問題。因為每一跳,特別是三跳中產生的數據量是巨大的,計算算子處理這些數據量所需的時間已經遠遠超過了消息通信的耗時。尤其是在多跳并存的環境中,比如一跳和二跳,其實它們作為中間結果其數據量并不大,一跳只有幾十上百個,二跳可能也就幾萬個,但是三跳作為最后的需要參與計算的結果直接到了幾十萬,所以通信開銷跟這個比起來,其實是非常微小的。
在消息通信方面,我們也有一些解決思路,比如在發送端開一些很小的窗口(比如 5 毫秒)來做一些聚合,把那些目標點相同的請求進行聚合,這樣可以減少一些通信的請求次數。