精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

時延降低 50%,小紅書圖數(shù)據(jù)庫如何實現(xiàn)多跳查詢性能大幅提升

數(shù)據(jù)庫
多跳查詢?yōu)槠髽I(yè)提供了深入的數(shù)據(jù)洞察和分析能力,它在小紅書眾多在線業(yè)務(wù)中扮演重要的角色。然而,這類查詢往往很難滿足穩(wěn)定的 P99 時延要求。小紅書基礎(chǔ)架構(gòu)存儲團隊針對這一挑戰(zhàn),基于大規(guī)模并行處理(MPP)的理念,開發(fā)了一種圖數(shù)據(jù)庫上的分布式并行查詢框架,成功將多跳查詢的時延降低了 50% 以上...

多跳查詢?yōu)槠髽I(yè)提供了深入的數(shù)據(jù)洞察和分析能力,它在小紅書眾多在線業(yè)務(wù)中扮演重要的角色。然而,這類查詢往往很難滿足穩(wěn)定的 P99 時延要求。小紅書基礎(chǔ)架構(gòu)存儲團隊針對這一挑戰(zhàn),基于大規(guī)模并行處理(MPP)的理念,開發(fā)了一種圖數(shù)據(jù)庫上的分布式并行查詢框架,成功將多跳查詢的時延降低了 50% 以上,尤其是使 3 跳查詢在在線場景從不能用到落地,極大地增強了在線業(yè)務(wù)的數(shù)據(jù)處理能力。

本文核心貢獻在于:團隊提出了一種從框架層面優(yōu)化多跳查詢時延的方案,在業(yè)務(wù)上使在線場景中使用多跳查詢成為可能,在技術(shù)上實現(xiàn)了圖數(shù)據(jù)庫查詢的框架級優(yōu)化。全文將從以下幾個方面依次展開:

  • 介紹小紅書使用圖數(shù)據(jù)庫的背景,并分析多跳查詢在實際業(yè)務(wù)中因時延高而受限的現(xiàn)狀(需求是什么)
  • 深入探討 REDgraph 架構(gòu),揭示原有查詢模式的不足和可優(yōu)化點(存在的問題)
  • 詳細闡述優(yōu)化原查詢模式的方案,并提供部分實現(xiàn)細節(jié)(改進方案)
  • 通過一系列性能測試,驗證優(yōu)化措施的有效性(改進后效果)

本方案為具有復(fù)雜查詢需求的在線存儲產(chǎn)品提供了優(yōu)化思路,歡迎業(yè)界同行深入探討。

同時,作者再興曾在「DataFunCon 2024·上海站」分享過本議題,感興趣的同學歡迎點擊“閱讀原文”,回看完整錄播視頻。

一、背景

1.1 圖數(shù)據(jù)庫在小紅書的使用場景


圖片

小紅書是一個以社區(qū)屬性為主的產(chǎn)品,覆蓋多個領(lǐng)域,鼓勵用戶通過圖文、短視頻、直播等形式記錄和分享生活點滴。在社交領(lǐng)域中,我們存在多種實體,如用戶、筆記、商品等,它們之間構(gòu)成了復(fù)雜的關(guān)系網(wǎng)絡(luò)。為高效處理這些實體間的一跳查詢,小紅書自研了圖存儲系統(tǒng) REDtao,滿足極致性能的需求。

(參見:小紅書如何應(yīng)對萬億級社交網(wǎng)絡(luò)關(guān)系挑戰(zhàn)?圖存儲系統(tǒng) REDtao 來了!

面對更為復(fù)雜的多跳查詢場景,我們自研了圖數(shù)據(jù)庫系統(tǒng) REDgraph,將多跳查詢的需求應(yīng)用于小紅書多個業(yè)務(wù)領(lǐng)域,包括但不限于:

  • 社區(qū)推薦:利用用戶間的關(guān)系鏈和分享鏈,為用戶推薦可能感興趣的好友、筆記和視頻。這類推薦機制通常涉及多于一跳的復(fù)雜關(guān)系。
  • 風控場景:通過分析用戶和設(shè)備的行為模式,識別可能的欺詐行為(如惡意薅羊毛),從而保護平臺免受濫用和作弊行為的影響。
  • 電商場景:構(gòu)建商品與商品、商品與品牌之間的關(guān)聯(lián)模型,優(yōu)化商品分類和推薦,從而提升用戶的購物體驗。

在傳統(tǒng)的 SQL 產(chǎn)品(如 MySQL)中,想實現(xiàn)這些多跳查詢,通常需要在一個查詢語句中寫多個 JOIN,這樣的性能無疑是較差的。若想利用鍵值存儲 KV 產(chǎn)品實現(xiàn),則需要分多次發(fā)送 get 請求,并自行處理中間結(jié)果,實現(xiàn)過程也較為麻煩。

相比之下,圖數(shù)據(jù)庫的設(shè)計理念為處理這類查詢提供了天然優(yōu)勢。在圖數(shù)據(jù)庫中,數(shù)據(jù)表被抽象為頂點,表之間的關(guān)系被抽象為邊,并且邊作為一等公民被存儲和處理。這樣一來,執(zhí)行 n 度關(guān)系查詢只需查詢 n 次邊表,大大簡化查詢過程,并提高了效率。

1.2 業(yè)務(wù)上面臨的困境

小紅書在社交、風控及離線任務(wù)調(diào)度等場景中均采用了圖數(shù)據(jù)庫,然而在實際應(yīng)用過程中遇到了一些挑戰(zhàn)。

場景一:社交推薦

在社交推薦中,我們希望能夠及時地將用戶可能感興趣的好友或內(nèi)容推薦給他們。例如,如果用戶 A 關(guān)注了用戶 B,而用戶 B 點贊了筆記 C,那么用戶 D(也點贊了筆記 C)就可能成為用戶 A 的潛在好友,使小紅書的好友社區(qū)建立更豐富的連接。

業(yè)務(wù)當然可以使用離線任務(wù)分析,基于分析結(jié)果進行推薦,但社交圖譜是無時無刻不在變化,基于離線分析做出的推薦往往是滯后的。如果推薦得更及時,能更好地抓住一些潛在的用戶關(guān)系,建立更豐富完善的社交圖譜,賦能其他業(yè)務(wù)(如:社區(qū)興趣小組,電商商品推薦)。

業(yè)務(wù)希望能即時向用戶推送可能感興趣的 “好友” 或 “內(nèi)容”,如果能即時完成此推薦,則能有效優(yōu)化用戶使用體驗,提升留存率。然而,由于先前 REDgraph 在某些方面的能力尚未完善,導致三跳時延比較高,所以業(yè)務(wù)一直只采用了一跳和兩跳查詢。

場景二:社區(qū)生態(tài)與風險控制

小紅書致力于促進社區(qū)生態(tài)的健康發(fā)展,對優(yōu)質(zhì)內(nèi)容創(chuàng)作者提供獎勵。然而,這也吸引了一些作弊用戶想薅羊毛。例如,作弊用戶可能會通過組織點贊來提升低質(zhì)量筆記的排名,將低質(zhì)筆記偽造成優(yōu)質(zhì)筆記以賺取獎勵。

風控業(yè)務(wù)需要對這種行為予以識別并防范,借助圖數(shù)據(jù)庫的多跳查詢,我們構(gòu)建出一個包含用戶和筆記為頂點、點贊為邊的復(fù)雜關(guān)系圖(“用戶->筆記-> ... ->用戶->筆記“)。隨后,對每篇筆記查詢其多度關(guān)系(筆記 -> 用戶 -> 筆記 -> 用戶)上作弊用戶的比例,若比例高于一定閾值,把筆記打上作弊標簽,系統(tǒng)便不對作弊用戶和作弊筆記發(fā)放獎勵。

打標行為往往是實時消費消息隊列去查詢圖數(shù)據(jù)庫,如果查詢動作本身比較慢,則會造成整體消費積壓。例如,如果一個查詢?nèi)蝿?wù)本應(yīng)在 12:00 執(zhí)行,但由于性能問題直到 12:10 才開始觸發(fā),那么在這十分鐘的延遲期間,一篇劣質(zhì)筆記已成為優(yōu)質(zhì)筆記,作者薅羊毛成功。等到發(fā)現(xiàn)這是作弊用戶時,顯然「為時晚矣」,因為損失已經(jīng)造成了。

具體來說,社交推薦場景要求三跳的 P99 低于 50 毫秒,風控場景則要求三跳的 P99 低于 200 毫秒,這是目前 REDgraph 所面臨的一大難題。那為何一至二跳可行,三跳及以上就難以實現(xiàn)呢?對此,我們基于圖數(shù)據(jù)庫與其他類型系統(tǒng)在工作負載的差異,做了一些難點與可行性分析。

1.3 難點與可行性分析

圖片

首先在并發(fā)方面,OLTP 的并發(fā)度很高,而 OLAP 則相對較低。圖的三跳查詢,服務(wù)的仍然是在線場景,其并發(fā)度也相對較高,這塊更貼近 OLTP 場景。

其次在計算復(fù)雜度方面,OLTP 場景中的查詢語句較為簡單,包含一到兩個 join 操作就算是較為復(fù)雜的情況了,因此,OLTP 的計算復(fù)雜度相對較低。OLAP 則是專門為計算設(shè)計的,因此其計算復(fù)雜度自然較高。圖的三跳查詢則介于 OLTP 和 OLAP 之間,它雖不像 OLAP 那樣需要執(zhí)行大量的計算,但其訪問的數(shù)據(jù)量相對于 OLTP 來說還是更可觀的,因此屬于中等復(fù)雜度。

第三,數(shù)據(jù)時效性方面,OLTP 對時效性的要求較高,必須基于最新的數(shù)據(jù)提供準確且實時的響應(yīng)。而在 OLAP 場景中則沒有這么高的時效要求,早期的 OLAP 數(shù)據(jù)庫通常提供的是 T+1 的時效。圖的三跳查詢,由于我們服務(wù)的是在線場景,所以對時效性有一定的要求,但并不是非常高。使用一小時或 10 分鐘前的狀態(tài)進行推薦,也不會產(chǎn)生過于嚴重的后果。因此,我們將其定義為中等時效性。

最后,查詢失敗代價方面。OLTP 一次查詢的成本較低,因此其失敗的代價也低;而 OLAP 由于需要消耗大量的計算資源,因此其失敗代價很高。圖查詢在這塊,更像 OLTP 場景一些,能夠容忍一些失敗,但畢竟訪問的數(shù)據(jù)量較大,在查一遍代價稍高,因此同樣歸屬到中等。

總結(jié)一下:圖的三跳查詢具備 OLTP 級別的并發(fā)度,卻又有比一般 OLTP 大得多的數(shù)據(jù)訪問量和計算復(fù)雜度,所以比較難在在線場景中使用。好在其對數(shù)據(jù)時效性的要求沒那么高,也能容忍一些查詢失敗,所以我們能嘗試對其優(yōu)化。

此外正如上文指出的,在小紅書業(yè)務(wù)場景中,三跳查詢的首要目標還是降低延遲。有些系統(tǒng)中會考慮犧牲一點時延來換取吞吐的大幅提升,而這在小紅書業(yè)務(wù)上是不可接受的。如果吞吐上不去,還可以通過擴大集群規(guī)模來作為兜底方案,而如果時延高則直接不能使用了。

圖片

二、原架構(gòu)問題分析

2.1 REDgraph 架構(gòu)

圖片

REDgraph 的整體結(jié)構(gòu)如上圖所示,其與當前較為流行的 NewSQL,如 TiDB 的架構(gòu)構(gòu)相似,采用了存算分離 + shared-nothing 的架構(gòu)。奇包含三類節(jié)點:

  • Meta 服務(wù):負責管理圖數(shù)據(jù)庫的元信息,包括數(shù)據(jù)模式(Schema)、用戶賬號和權(quán)限、存儲分片的位置信息、作業(yè)與后臺任務(wù)等;
  • Graph 服務(wù):負責處理用戶的查詢請求,并做相應(yīng)的處理,涵蓋查詢的解析、校驗、優(yōu)化、調(diào)度、執(zhí)行等環(huán)節(jié)。其本身是無狀態(tài)的,便于彈性擴縮容;
  • Storgae 服務(wù):負責數(shù)據(jù)的物理存儲,其架構(gòu)分為三層。最上層是圖語義 API,將 API 請求轉(zhuǎn)換為對 Graph 的鍵值(KV)操作;中間層采用 Raft 協(xié)議實現(xiàn)共識機制,確保數(shù)據(jù)副本的強一致性和高可用性;最底層是單機存儲引擎,使用 rocksdb 來執(zhí)行數(shù)據(jù)的增刪查等操作。

2.2 圖切分方式

圖片

圖切分的含義是,如果我們擁有一個巨大的圖,規(guī)模在百億到千億水平,應(yīng)該如何將其存儲在集群的各節(jié)點之中,即如何對其切分。在工業(yè)界中,主要存在兩種典型的切分策略:邊切分和點切分。

邊切分,以頂點為中心,這種切分策略的核心思想是每個頂點會根據(jù)其 ID 進行哈希運算,并將其路由到特定的分片上。每個頂點上的每條邊在磁盤中都會被存儲兩份,其中一份與起點位于同一分片,另一份則與終點位于同一分片。

點切分,與邊切分相對應(yīng),也就是以邊為中心做哈希打散,每個頂點會在集群內(nèi)保存多份。

這兩種切分方式各有利弊。邊切分的優(yōu)點在于每個頂點與其鄰居都保存在同一個分片中,因此當需要查詢某個頂點的鄰居時,其訪問局部性極佳;其缺點在于容易負載不均,且由于節(jié)點分布的不均勻性,引發(fā)熱點問題。點切分則恰恰相反,其優(yōu)點在于負載較為均衡,但缺點在于每個頂點會被切成多個部分,分配到多個機器上,因此更容易出現(xiàn)同步問題。

REDgraph 作為一個在線的圖查詢系統(tǒng),選擇的是邊切分的方案。

2.3 優(yōu)化方案 1.0

圖片

·  通用性差,且在 3 跳場景中效果還不夠。

我們之前已經(jīng)實施了一些優(yōu)化,可以稱之為優(yōu)化方案 1.0。當時主要考慮的是如何快速滿足用戶需求,因此我們的方案包括:首先根據(jù)常用的查詢模式提供一些定制化的算法,這些算法可以跳過解析、校驗、優(yōu)化和執(zhí)行等繁瑣步驟,直接處理請求,從而實現(xiàn)加速。其次,我們會對每個頂點的扇出操作進行優(yōu)化,即每個頂點在向外擴展時,對其擴展數(shù)量進行限制,以避免超級點的影響,降低時延。此外,我們還完善了算子的下推策略,例如 filter、sample、limit 等,使其盡可能在存儲層完成,以減少網(wǎng)絡(luò)帶寬的消耗。同時,我們還允許讀從節(jié)點、讀寫線程分離、提高垃圾回收頻率等優(yōu)化。

然而,這些優(yōu)化策略有一個共性,就是每個點都比較局部化和零散,因此其通用性較低。比如第一個優(yōu)化,如果用戶需要發(fā)起新的查詢模式,那么此前編寫的算法便無法滿足其需求,需要另行編寫。第二個優(yōu)化,如果用戶所需要的是頂點的全部結(jié)果,那此項也不再適用。第三個優(yōu)化,如果查詢中本身就不存在這些運算符,那么自然也無法進行下推操作。諸如此類,通用性較低,因此需要尋找一種更為通用,能夠減少重復(fù)工作的優(yōu)化策略。

2.4 新方案思考

圖片

如上圖所示,我們對一個耗時接近一秒的三跳查詢的 profile 分析。我們發(fā)現(xiàn)在每一跳產(chǎn)出的記錄數(shù)量上,第一跳至第二跳擴散了 200 多倍,第二跳至第三跳擴散了 20 多倍,表現(xiàn)在結(jié)果上,需要計算的數(shù)據(jù)行數(shù)從 66 條直接躍升至 45 萬條,產(chǎn)出增長速度令人驚訝。此外,我們發(fā)現(xiàn)三跳算子在整個查詢過程中占據(jù)了較大的比重,其在查詢層的耗時更是占據(jù)了整個查詢的 80% 以上。

那么應(yīng)該如何進行優(yōu)化呢?在數(shù)據(jù)庫性能優(yōu)化方面,有許多可行的方案,主要分為三大類:存儲層的優(yōu)化、查詢計劃的優(yōu)化以及執(zhí)行引擎的優(yōu)化。

由于耗時大頭在查詢層,所以我們重點關(guān)注這塊。因為查詢計劃的優(yōu)化是一個無止境的工程,用戶可能會寫出各種查詢語句,產(chǎn)生各種算子,難以找到一個通用且可收斂的方案來覆蓋所有情況。而執(zhí)行引擎則可以有一個相對固定的優(yōu)化方案,因此我們優(yōu)先選擇了優(yōu)化執(zhí)行引擎。

圖數(shù)據(jù)庫的核心就是多跳查詢執(zhí)行框架,而其由于數(shù)據(jù)量大,計算量大,導致查詢時間較長,因此我們借鑒了 MPP 數(shù)據(jù)庫和其他計算引擎的思想,提出了分布式并行查詢的解決方案。

2.5 原多跳查詢執(zhí)行流程

圖片

原有的多跳查詢執(zhí)行流程如上圖所示。假設(shè)我們要查詢 933 頂點的三跳鄰居節(jié)點 ID,即檢索到藍圈中的所有頂點。經(jīng)過查詢層處理后,將生成右圖所示執(zhí)行計劃,START 表示計劃的起點,本身并無實際操作。GetNeighbor 算子則負責實際查詢頂點的鄰居,例如根據(jù) 933 找到 A 和 B。后續(xù)的 Project、InnerJoin 以及 Project 等操作均為對先前產(chǎn)生的結(jié)果進行數(shù)據(jù)結(jié)構(gòu)的轉(zhuǎn)換、處理及裁剪等操作,以確保整個計算流程的順利進行。正是后續(xù)的這幾個算子耗費的時延較高。

2.6 可優(yōu)化點分析

2.6.1 Barrier 等待使時延增加

從上述物理執(zhí)行中可以看出:查詢節(jié)點必須等所有存儲節(jié)點的響應(yīng)返回后,才會執(zhí)行后面的算子。這樣即使大多數(shù)存儲節(jié)點很快返回,只要有一個「慢存儲節(jié)點」存在,整個查詢都得 block 住。

圖片

在圖計算(AP)場景中,一次計算往往要經(jīng)過很多輪迭代(Epoch),并且每輪迭代后都需要進行全局指標的更新,更新完再繼續(xù)下一輪迭代。在 Epoch 之間插入 Barrier 做同步是有必要的。

但在圖查詢(TP)場景中,通常不需要全局性更新,只是在下發(fā)請求時對起點 ID 做去重,即使有往往也是在查詢的最后一步,因此沒有必要 barrier。

此外,圖數(shù)據(jù)庫負載往往呈現(xiàn)出“冪律分布”現(xiàn)象,即少數(shù)頂點鄰居邊多、多數(shù)頂點鄰居邊少;REDgraph 本身也是以邊切分的方式存儲數(shù)據(jù),這就使得「慢存儲節(jié)點」很容易出現(xiàn)。加之某個存儲節(jié)點的網(wǎng)絡(luò)抖動或節(jié)點負載高等因素,可能導致響應(yīng)時間進一步延長,影響查詢效率。

圖片

如圖所示,如果查詢層收到一個響應(yīng)就處理一個響應(yīng)(類似于 pipeline 的機制),則能避免無意義的空等,從整體上加速查詢的執(zhí)行。

2.6.2 查詢層串行執(zhí)行效率低

在整個查詢計劃中,只有 GetNeighbor 算子是在多個存儲節(jié)點上并行執(zhí)行,而其他算子是在查詢節(jié)點上串行執(zhí)行,這里我們想到兩個問題:

  • 串行執(zhí)行的效率天然低于并行執(zhí)行。只有在數(shù)據(jù)量太少或者計算邏輯太簡單的情況下,上下文切換的開銷會超過并行的收益。在正常負載的圖查詢場景中,數(shù)據(jù)量和計算邏輯都挺可觀;
  • 當多個存儲節(jié)點的響應(yīng)數(shù)據(jù)匯聚到查詢節(jié)點時,數(shù)據(jù)量仍然相當可觀。如果能在 storaged 節(jié)點上完成這些計算,將顯著減少查詢節(jié)點需要處理的數(shù)據(jù)量。

我們在業(yè)務(wù)的線上集群和性能測試顯示:GetNeighbors 和 GetVertices 不是所有算子中最耗時的,反倒是不起眼的 Project 算子往往耗費更多時間,特別是那些緊隨 GetNeighbors 和 GetVertices 之后的 Project 算子,因為它不僅需要執(zhí)行數(shù)據(jù)投影,還負責將 map 展平。

這表明整個查詢的主要瓶頸在于計算量大。而查詢計劃中大部分都是純計算型算子,將它們并行化對于提升查詢效率很有必要。

2.6.3 查詢結(jié)果轉(zhuǎn)發(fā)浪費 IO

如上文所說,在圖查詢場景中一般不需要做全局性的更新,查詢節(jié)點收到各存儲節(jié)點的響應(yīng)后,只是簡單地再次分區(qū)然后下發(fā),所以存儲節(jié)點的結(jié)果轉(zhuǎn)發(fā)到查詢層,再從查詢節(jié)點分發(fā)到各存儲節(jié)點很浪費。

如果存儲節(jié)點自身具備路由和分發(fā)的能力,那可以讓存儲節(jié)點執(zhí)行完 GetNeighbors 算子后,接著執(zhí)行 Project、InnerJoin 等算子,每當遇到下一個 GetNeighbor 算子時,自行組織請求并分發(fā)給其他存儲節(jié)點。其他存儲節(jié)點收到后接著執(zhí)行后面的算子,以此規(guī)則往復(fù),直到最后一步將結(jié)果匯聚到查詢層,統(tǒng)一返回給客戶端。

2.7 改造后的執(zhí)行流程

圖片

首先,查詢服務(wù)器(Query Server)將整個執(zhí)行計劃以及執(zhí)行計劃所需的初始數(shù)據(jù)傳輸至存儲服務(wù)器(Store Server),之后 Store Server 自身來驅(qū)動整個執(zhí)行過程。以 Store Server 1 為例,當它完成首次查詢后,便會根據(jù)結(jié)果 ID 所在的分區(qū),將結(jié)果轉(zhuǎn)發(fā)至相應(yīng)的 Store Server。各個 Store Server 可以獨立地繼續(xù)進行后續(xù)操作,從而實現(xiàn)整個執(zhí)行動作的并行化,并且無同步點,也無需額外轉(zhuǎn)發(fā)。

需要說明的是,圖中右側(cè)白色方框比左側(cè)要矮一些,這是因為數(shù)據(jù)由上方轉(zhuǎn)到下方時,進行了分區(qū)下發(fā),必然比在查詢服務(wù)器接收到的總數(shù)據(jù)量要少。

可以看到,在各部分獨立驅(qū)動后,并未出現(xiàn)等待或額外轉(zhuǎn)發(fā)的情況,Query Server 只需在最后一步收集各個 Store Server 的結(jié)果并聚合去重,然后返回給客戶端。如此一來,整體時間相較于原始模型得到了顯著縮短。

三、分布式并行查詢的實現(xiàn)

分布式并行查詢的具體實現(xiàn),涉及到許多個關(guān)鍵點,接下來介紹其中一些細節(jié)。

3.1 如何保證不對 1-2 跳產(chǎn)生負優(yōu)化

圖片

首先一個問題是,在進行改造時如何確保不會對原始的 1-2 跳產(chǎn)生負優(yōu)化。在企業(yè)內(nèi)部進行新的改造和優(yōu)化時,必須謹慎評估所采取的措施是否會對原有方案產(chǎn)生負優(yōu)化。我們不希望新方案還未能帶來收益,反而破壞了原有的系統(tǒng)。因此,架構(gòu)總體上與原來保持一致。在 Store Server 內(nèi)部插入了一層,稱為執(zhí)行層,該層具有網(wǎng)絡(luò)互聯(lián)功能,主要用于分布式查詢的轉(zhuǎn)發(fā)。Query Server 層則基本保持不變。

這樣,當接收到用戶的執(zhí)行計劃后,便可根據(jù)其跳數(shù)選擇不同的處理路徑。若為 1 至 2 跳,則仍沿用原有的流程,因為原有的流程能夠滿足 1-2 跳的業(yè)務(wù)需求,而 3 跳及以上則采用分布式查詢。

3.2 如何與原有執(zhí)行框架兼容

圖片

原有代碼中每一個操作都是用算子方式實現(xiàn)。為了讓分布式并行查詢的實現(xiàn)與原有框架兼容,我們把「轉(zhuǎn)發(fā)」也定義為一個算子,取名為 Forward。這一算子的功能類似于 Spark 中的 Shuffle 算子、或 OceanBase 中的 Exchange 算子,關(guān)鍵在于它能夠確保查詢在分布式環(huán)境中順暢執(zhí)行。

我們對查詢計劃進行了以下關(guān)鍵改寫:

  • 在每個要「切換分區(qū)才能執(zhí)行的」算子前(例如 GetNeighbors、GetVertices 等),我們添加一個 FORWARD 算子。FORWARD 算子負責記錄分區(qū)的依據(jù),通常是起點 ID。
  • 為了將分布式節(jié)點的查詢結(jié)果有效地匯總,我們在查詢計劃的末端添加了 CONVERGE 算子,它指示各節(jié)點將結(jié)果發(fā)送回 DistDriver 節(jié)點,即最初接收用戶請求的節(jié)點。
  • 隨后,我們引入了 MERGE 算子,它的作用是對所有從節(jié)點收到的結(jié)果進行匯總,并將最終結(jié)果返回給客戶端。

通過這種方式,當 REDgraph-Server 準備執(zhí)行 GetNeighbors、GetVertices 算子時,它會首先執(zhí)行 FORWARD、CONVERGE算子,將必要的數(shù)據(jù)和查詢計劃轉(zhuǎn)發(fā)到其他服務(wù)器。這樣,其他服務(wù)器在接收到請求后,就能明確自己的任務(wù)和所需的數(shù)據(jù),從而推動查詢計劃的執(zhí)行。

值得注意的是,F(xiàn)ORWARD 和 CONVERGE算子都有「轉(zhuǎn)發(fā)/發(fā)送」數(shù)據(jù)的含義,不過它們的側(cè)重點不太一樣:

  • FORWARD 強調(diào)的是路由轉(zhuǎn)發(fā),并且要指定轉(zhuǎn)發(fā)的依據(jù),即 partitionKey 字段,不同的數(shù)據(jù)行會根據(jù)其 partitionKey 字段值的不同轉(zhuǎn)發(fā)到不同的節(jié)點上;
  • CONVERGE 強調(diào)的是發(fā)送匯聚,具有單一確定的目標節(jié)點,即 DistDriver;

因它們只是在做轉(zhuǎn)發(fā)/發(fā)送的工作,我們將這類算子統(tǒng)稱為「路由」算子。

在改造后的查詢計劃中,從 START 算子開始,直到遇到「路由」算子,這多個算子都可以在某個節(jié)點本地執(zhí)行的,因此我們將這一系列算子劃分到一個 stage 內(nèi)。整個查詢計劃由多個 stage 組成,其中首尾兩個 stage 在 DistDriver 上執(zhí)行,中間的 stage 在 DistWorker 上執(zhí)行。

需要注意的是:stage 是一個邏輯概念,具體執(zhí)行時,每個 stage 會依據(jù)分區(qū)和所屬節(jié)點產(chǎn)生多個 task,這些 task 會分布在多個節(jié)點上執(zhí)行,每個節(jié)點僅訪問本節(jié)點內(nèi)數(shù)據(jù),無需跨網(wǎng)絡(luò)拉取數(shù)據(jù)。這種結(jié)構(gòu)化的方法極大地提高了查詢的并行性和效率。

3.3 如何做熱點處理

圖片

在原查詢模式中,每一次在發(fā)起 GetNeighbors 算子前,查詢層會對起點 ID 去重(查詢計劃中 GetNeighbors 算子的 dedup 為 true),收到存儲節(jié)點的響應(yīng)后,再依靠后續(xù)算子將結(jié)果按需展平,因此存儲節(jié)點不會產(chǎn)生重復(fù)查詢。以下圖舉例說明:

原查詢模式的執(zhí)行流程可簡單描述為:

  1. 第一跳從存儲層查到 A->C 和 B->C,返回到查詢層;
  2. 查詢層會 Project 得到兩個 C,以備后面做 InnerJoin;
  3. 準備執(zhí)行第二跳,構(gòu)造起點集合時,由于 dedup 為 true,僅會保留一個 C;
  4. 第二跳從存儲層查到 C->D 和 C->E,返回到查詢層;
  5. 查詢層執(zhí)行 InnerJoin,由于此前有兩個 C,所以 C->D 和 C->E 也各會變成兩個;
  6. 查詢層再次 Project 取出 dstId2,得到結(jié)果 D、D、E、E。

從步驟 4 可以看到,存儲層不會產(chǎn)生重復(fù)查詢。

改造成分布式查詢后,我們只能在每個 stage 內(nèi)去重。但由于缺乏全局 barrier,多個 stage 先后往某個 DistWorker 轉(zhuǎn)發(fā)請求時,多個請求之間可能有重復(fù)的起點,會在存儲層產(chǎn)生重復(fù)查詢和計算,導致 CPU 開銷增加以及查詢時延增加。

如果每一跳產(chǎn)生的重復(fù)終點 ID(將會作為下一跳的起點 ID)很多,分布式查詢反而會帶來劣勢。為解決這一問題,我們引入一套起點 ID 去重機制 —— NeighborCache,具體方案如下:

因為沒有全局的 Barrier,無法在下發(fā)請求之前去重,我們選擇在存儲節(jié)點上提供一個 NeighborCache,其本質(zhì)就是一個 map,可表示為 map<vid +="" edgetype,="" list>。在執(zhí)行 GetNeighbors 算子前,存儲節(jié)點會首先檢查 NeighborCache,如果找到相應(yīng)的條目,則直接使用這些數(shù)據(jù)填充結(jié)果集;如果沒有找到,則訪問存儲層獲取數(shù)據(jù),并更新 NeighborCache,讀取和更新 Cache 需要用讀寫鎖做好互斥。

另外,NeighborCache 還具有如下特點:

  • 每當有更新 vid + edgeType 的請求時,都會先 invalidate cache 中對應(yīng)的條目,以此來保證緩存與數(shù)據(jù)的一致性;
  • 即使沒有更新操作存在,cache 內(nèi)的每個 kv 條目存活時間也很短,通常為秒級,超過時間就會被自動刪除。為什么這么短呢?
  • 充分性:由于在線圖查詢(OLTP)的特性,用戶的多跳查詢通常在幾秒到十幾秒內(nèi)完成。而 NeighborCache 只是為了去重而設(shè)計,來自于不同 DistWorker 的 GetNeighbors 請求大概率不會相隔太長時間到達,所以 cache 本身也不需要存活太久;
  • 必要性:從 map 結(jié)構(gòu)的 key 就會發(fā)現(xiàn),當 qps 較高,跳數(shù)多,頂點的鄰居邊多時,此 map 要承載的數(shù)據(jù)量是非常大的,所以也不能讓其存活的時間太久,否則很容易 OOM;
  • 在填充 cache 前會做內(nèi)存檢查,如果本節(jié)點當前的內(nèi)存水位已經(jīng)比較高,則不會填充,以避免節(jié)點 OOM。

通過這種起點 ID 去重機制,我們能夠有效地減少重復(fù)查詢,提高分布式查詢的效率和性能。

3.4 如何做負載均衡

圖片

第四個問題是怎么做負載均衡,包括存儲的均衡和計算的均衡。

首先,存儲的均衡在以邊切分的圖存儲里面其實是很難的,因為它天然的就是把頂點和其鄰居全部都存在了一起,這是圖數(shù)據(jù)庫相比其他數(shù)據(jù)庫的優(yōu)勢,也是其要承擔的代價。所以目前沒有一個徹底的解決方法,只能在真的碰到此問題時擴大集群規(guī)模,讓數(shù)據(jù)的哈希打散能夠更加均勻一些,避免多個熱點都落在同一個機器的情況。而在目前的業(yè)務(wù)場景上來看,其實負載不均衡的現(xiàn)象不算嚴重,例如風控的一個比較大的集群,其磁盤用量最高和最低的也不超過 10%,所以問題其實并沒有想象中的那么嚴重。

另外一個優(yōu)化方法是在存儲層及時清理那些過期的數(shù)據(jù),清理得快的話也可以減少一些不均衡。

計算均衡的問題。存儲層采用了三副本的策略,若業(yè)務(wù)能夠接受弱一致的讀取(實際上大多數(shù)業(yè)務(wù)均能接受),我們可以在請求轉(zhuǎn)發(fā)時,查看三副本中的哪個節(jié)點負載較輕,將請求轉(zhuǎn)發(fā)至該節(jié)點,以盡量平衡負載。此外,正如前文所述,熱點結(jié)果緩存也是一種解決方案,只要熱點處理速度足夠快,計算的不均衡現(xiàn)象便不易顯現(xiàn)。

3.5 如何做流程控制

圖片

在分布式查詢架構(gòu)中,由于前面取消全局 Barrier,使得各個 DistWorker 自行驅(qū)動查詢的進行。這種設(shè)計提高了靈活性,但也帶來新的挑戰(zhàn):

如圖所示,各個 DistWorker 上 stage3 的結(jié)果需要匯聚到 DistDriver 后才能向客戶端返回,但是 DistDriver 只在 stage0 的時候給 Node2 發(fā)送了請求,后面的所有轉(zhuǎn)發(fā)都是由 DistWorker 自行完成的,脫離了 DistDriver 的「掌控」。這樣 DistDriver 就不知道最后有多少個節(jié)點在執(zhí)行 stage3,也就不知道該等待哪些 DistWorker 給它發(fā)送結(jié)果,以及何時可以開始執(zhí)行 stage4。

我們引入一個進度匯報機制:在 DistDriver 上實現(xiàn)一個 Acker,負責接收各個 DistWorker 上報的 stage 執(zhí)行進度信息。每個 stage 向外擴散時,向 Acker 發(fā)送一條消息,記錄當前完成的 stage 和 即將開始的 stage 的節(jié)點數(shù)量。具體而言,就是包含兩個鍵值對:

  • 當前的 stage 編號 -> -1;
  • 下一個 stage 的編號 -> 執(zhí)行下一個 stage 的節(jié)點的數(shù)量;

比如 Node2 上的 stage-1 擴散到 stage-2 時,目標節(jié)點有 3 個:Node1、Node3、Node5,于是就發(fā)送 {stage-1: -1,stage-2: 3} 的消息到 DistDriver 上,表示有一個節(jié)點完成了 stage-1,有 3 個節(jié)點開始了 stage-2。而由于 stage-1 此前由 Node1 登記過 {stage-1: 1},這樣一正一負就表示所有的 stage-1 都已經(jīng)執(zhí)行完畢。stage-2 和 stage-3 的更新和判定方式類似,當 DistDriver 發(fā)現(xiàn)所有的前置 stage 數(shù)量都為 0 時,就可以驅(qū)動 stage-4 。

我們實際想要的是每個 stage 數(shù)量的正負抵消能力,而非 {stage-1: -1,stage-2: 3} 的字符串。為了簡化這一過程,我們便采用異或運算(相同為 0,相異為 1)跟蹤各個 stage 的狀態(tài),舉例說明:

  1. Acker 上有一個初始的 checksum 值 0000;
  2. stage-0 在擴散到 stage-1 時,生成了一個隨機數(shù) 0010(這里為了表達簡便,以 4 位二進制數(shù)代替),這個 0010 是 Node2 上的 stage-1 的 Id,然后把這個 0010 伴隨著 Forward 請求發(fā)到 Node2 上,同時也發(fā)到 Acker 上,這樣就表示 0010 這個 stage 開始了,Acker 把收到的值與本地的 checksum 做異或運算,得到 0010,并以此更新本地 checksum;
  3. stage-1 執(zhí)行完后擴散到 stage-2 時,由于有 3 個目標節(jié)點,就生成 3 個不相同的隨機數(shù) 0101、0001、1010(需要檢查這 3 個數(shù)異或之后不為 0),分別標識 3 個目標節(jié)點上的 stage-2,然后把這 3 個數(shù)伴隨著 Forward 請求發(fā)到 Node1、Node3、Node5 上,同時在本地把自身的 stage Id(0010)和這 3 個數(shù)一起做異或運算,再把運算的結(jié)果發(fā)到 Acker,Acker 再次做異或運算,也就是 0010 ^ (0010 ^ 0101 ^ 0001 ^ 1010),這樣 0010 就被消除掉了,也就表示 stage-1 執(zhí)行完成了;
  4. 重復(fù)上述過程,最后 Acker 上的 checksum 會變回 0,表示可以驅(qū)動 stage-4。

注意:盡管在某個節(jié)點的 stage 擴散時檢查了生成的隨機數(shù)異或不為 0,但是多個節(jié)點間生成的隨機數(shù)異或到一起還是可能為 0 的,比如 Node1 的 stage-2 生成的 3 個數(shù)異或后為 0001,Node3 的 stage-2 異或后為 0010,Node5 的 stage-2 異或后為 0011,0001 ^ 0010 ^ 0011 = 0。這樣就會導致 stage-3 還在執(zhí)行中時,DistDriver 就誤認為它已經(jīng)執(zhí)行完畢,提前驅(qū)動 stage-4 的執(zhí)行。

不過考慮到我們實際使用的是 int32 整數(shù),出現(xiàn)這種的情況的概率非常低。在未來的優(yōu)化中在,我們可以考慮給每個 Node 生成一個 16 位的隨機 Id(由 metad 生成),并保證這些 NodeId 異或結(jié)果不為 0,當 stage 擴散時,將 NodeId 置于隨機數(shù)的高位,確保分布式查詢的每個階段都能被準確跟蹤和協(xié)調(diào)。

另一個重要的問題便是全程鏈路的超時自檢,例如在 stage2 或 stage3 的某一個節(jié)點上運行時間過長,此時不能讓其余所有節(jié)點一直等待,因為客戶端已經(jīng)超時了。因此我們在每個算子內(nèi)部的執(zhí)行邏輯中都設(shè)置了一些埋點,用以檢查算子的執(zhí)行是否超過了用戶側(cè)的限制時間,一旦超過,便立即終止自身的執(zhí)行,從而迅速地自我銷毀,避免資源的無謂浪費。

四、性能測試

我們在改造工程完成后進行了性能測試,采用 LDBC 組織提供的 SNB 數(shù)據(jù)集,生成了一個 SF100 級別的社交網(wǎng)絡(luò)圖譜,規(guī)模達到 3 億頂點,18 億條邊。我們主要考察其一跳、二跳、三跳、四跳等多項查詢性能。

圖片

根據(jù)測試結(jié)果顯示,在一跳和二跳情況下,原生查詢和分布式查詢性能基本相當,未出現(xiàn)負優(yōu)化現(xiàn)象。從三跳起,分布式查詢相較于原生查詢能實現(xiàn) 50% 至 60% 的性能提升。例如,在 Max degree 場景下的分布式查詢已將時延控制在 50 毫秒以內(nèi)。在帶有 Max degree 或 Limit 值的情況下,時延均在 200 毫秒以下。盡管數(shù)據(jù)集與實際業(yè)務(wù)數(shù)據(jù)集存在差異,但它們皆屬于社交網(wǎng)絡(luò)領(lǐng)域,因此仍具有一定的參考價值。

圖片

四跳查詢,無論是原始查詢還是分布式查詢,其時延的規(guī)模基本上都在秒至十余秒的范圍內(nèi)。因為四跳查詢涉及的數(shù)據(jù)量實在過于龐大,已達到百萬級別,僅依賴分布式并行查詢難以滿足需求,因此需要采取其他策略。然而,即便如此,我們所提出的改進方案相較于原始查詢模式仍能實現(xiàn) 50% 至 70% 的提升,效果還是很可觀的。

五、總結(jié)與展望

在過去的較短時間內(nèi),我們基于 MPP 的理念,對 REDgraph 在分布式并行查詢上進行了深入探索和實踐。本方案能顯著優(yōu)化多跳查詢的性能,并且對業(yè)務(wù)邏輯完全兼容,沒有使用限制條件,屬于框架級的通用優(yōu)化。測試結(jié)果顯示,時延降低了 50% 以上,滿足在線業(yè)務(wù)場景的時延要求,驗證方案的有效性。

目前,許多公司的圖數(shù)據(jù)庫產(chǎn)品在在線場景中仍使用兩跳及以下的查詢。這是因為多跳查詢的時延無法滿足在線業(yè)務(wù)的要需求,導致失去許多潛在的業(yè)務(wù)價值,也未能充分發(fā)揮圖數(shù)據(jù)庫的技術(shù)優(yōu)勢。隨著小紅書 DAU 的持續(xù)增長,業(yè)務(wù)數(shù)據(jù)規(guī)模朝著萬億級規(guī)模遞增,業(yè)務(wù)上使用替代方案的瓶頸會逐漸展露。我們計劃在今年上半年完成開發(fā)工作,并在下半年開始將這套新架構(gòu)逐步應(yīng)用于相關(guān)業(yè)務(wù)場景。

本方案雖然針對的是圖數(shù)據(jù)庫,但其探索實踐對公司其他數(shù)據(jù)庫產(chǎn)品同樣具有重要的參考價值。例如,REDtable 在處理用戶請求時,經(jīng)常需要應(yīng)對復(fù)雜或計算量大的查詢,以往會建議用戶修改代碼來適應(yīng)這些情況。現(xiàn)在,我們可以借鑒本方案,為這些「具有重查詢需求」產(chǎn)品打造高性能執(zhí)行框架,以增強自身的數(shù)據(jù)處理能力。

我們將繼續(xù)提升 REDgraph 的多跳查詢能力,并將其和 REDtao 融合,打造成一個統(tǒng)一的數(shù)據(jù)庫產(chǎn)品,賦能更多業(yè)務(wù)場景。我們誠邀對技術(shù)有極致追求,志同道合的同學一起加入團隊,共同推動圖數(shù)據(jù)技術(shù)的發(fā)展。

六、作者簡介

  • 再興 
    小紅書基礎(chǔ)架構(gòu)存儲組工程師,負責自研分布式表格存儲 REDtable(NewSQL),參與分布式圖數(shù)據(jù)庫 REDgraph 的研發(fā)。
  • 敬德 
    小紅書基礎(chǔ)架構(gòu)存儲組工程師,負責自研圖存儲系統(tǒng) REDtao 和分布式圖數(shù)據(jù)庫 REDgraph。
  • 劉備 

    小紅書基礎(chǔ)架構(gòu)存儲組負責人,負責 REDkv / Redis / REDtao / REDtable / REDgraph / MySQL 的整體架構(gòu)和技術(shù)演進。
責任編輯:龐桂玉 來源: 小紅書技術(shù)REDtech
相關(guān)推薦

2024-01-07 18:02:21

數(shù)據(jù)庫分片副本

2024-06-19 07:45:20

2021-01-22 08:10:21

架構(gòu)應(yīng)用云網(wǎng)絡(luò)

2023-04-10 09:15:25

Vite 4.3SWC 插件

2013-03-29 09:28:41

2025-08-19 09:58:38

2023-11-09 08:46:24

2023-05-25 20:06:17

Linux游戲性能

2011-03-28 15:44:45

惠普數(shù)據(jù)庫Oracle數(shù)據(jù)庫

2009-05-11 14:19:55

Oracle性能優(yōu)化數(shù)據(jù)庫

2024-04-11 08:00:00

人工智能機器學習

2023-11-26 09:04:10

Vue性能

2015-04-22 14:41:04

云遷移Redis緩存數(shù)據(jù)模型調(diào)整

2023-07-28 08:00:00

人工智能向量數(shù)據(jù)庫

2021-01-31 17:50:41

數(shù)據(jù)庫查詢程序員

2011-04-18 09:03:36

數(shù)據(jù)庫查詢

2020-11-10 08:38:43

數(shù)據(jù)庫HugePages內(nèi)存

2010-08-17 09:22:34

2018-11-14 10:48:52

蘇寧管理系統(tǒng)服務(wù)性能

2024-04-29 18:55:16

緩存Spring性能
點贊
收藏

51CTO技術(shù)棧公眾號

在线视频亚洲欧美中文| 成人一区二区不卡免费| 亚洲看片一区| 亚洲欧美日本另类| 国产精品区在线| 在线中文字幕-区二区三区四区| 国产suv精品一区二区6| 全球成人中文在线| 青青青在线免费观看| 网红女主播少妇精品视频| 欧美午夜片在线观看| www.日本三级| 国产露出视频在线观看| 国产乱妇无码大片在线观看| 日韩av片电影专区| 欧美日韩成人免费观看| 国产一区二区三区91| 精品国产免费视频| 可以看污的网站| 欧美私密网站| 亚洲美女免费视频| 日韩av电影在线观看| 高清毛片aaaaaaaaa片| 男男成人高潮片免费网站| 久久男人av资源网站| 五月天色婷婷丁香| 精品国产一区二区三区| 日韩av中文字幕在线播放| 午夜福利123| а√天堂资源国产精品| 欧美日韩一区二区免费视频| 亚洲爆乳无码精品aaa片蜜桃| 国产69久久| 91小视频免费观看| 国产精品久久久久久久久久久久午夜片 | 国产精品毛片视频| 日韩一卡二卡三卡国产欧美| 久久99爱视频| 另类中文字幕国产精品| 精品美女国产在线| 成人网站免费观看入口| 欧美人与牲禽动交com| 亚洲欧洲日韩在线| 伊甸园精品99久久久久久| 国产精品久久一区二区三区不卡| 99麻豆久久久国产精品免费优播| 99在线视频首页| a在线观看视频| 韩国一区二区视频| 国产一区二区视频在线观看| 曰批又黄又爽免费视频| 日本一区中文字幕| 国产精品视频在线播放| 国产日韩久久久| 奇米四色…亚洲| 国产精品极品美女在线观看免费| 免费欧美一级视频| 欧美丝袜在线观看| 国产成人免费9x9x人网站视频| 精品久久久中文| 无罩大乳的熟妇正在播放| www.综合网.com| 午夜欧美一区二区三区在线播放| 欧洲精品一区二区三区久久| www中文字幕在线观看| 亚洲成人激情自拍| 国产最新免费视频| 国产精品扒开腿做爽爽爽视频软件| 色悠悠亚洲一区二区| 日本男人操女人| 久久影视精品| 日韩一区二区在线观看视频播放| 18深夜在线观看免费视频| 91精品国产自产在线丝袜啪 | 精品久久久久一区二区三区 | 蜜臀精品一区二区三区在线观看| 日韩暖暖在线视频| 一级黄色片免费| 国产精品1区二区.| 极品校花啪啪激情久久| 蜜桃视频在线入口www| 国产精品视频第一区| 免费看污污视频| segui88久久综合| a国产在线视频| 国产91精品入口| 久久精品日韩| 麻豆传媒视频在线观看| 亚洲一级二级三级在线免费观看| 人妻少妇被粗大爽9797pw| 成人开心激情| 日韩欧美色综合网站| 中文字幕一区二区久久人妻网站| 日韩在线欧美| 高清一区二区三区四区五区| 国产精品欧美综合| 国产69精品久久777的优势| 麻豆传媒一区二区| fc2ppv国产精品久久| 狠狠干狠狠久久| 免费在线观看污网站| 嫩草国产精品入口| 精品国产一区av| 婷婷激情五月网| 国产精品一区专区| 日韩亚洲欧美精品| brazzers在线观看| 欧美日韩精品一二三区| 亚洲观看黄色网| 综合天堂久久久久久久| 国产精品91一区| 日本久久一级片| 一区视频在线播放| 亚洲乱码国产一区三区| 国产人妖ts一区二区| 久久精品电影网| 亚洲大片免费观看| 成人黄色在线看| 在线视频一二三区| 国产a亚洲精品| 日韩av在线天堂网| 久草国产在线观看| 紧缚奴在线一区二区三区| 欧美日韩在线高清| 高清精品在线| 日韩精品专区在线| av最新在线观看| 久久蜜桃资源一区二区老牛| 国产精品夜夜夜一区二区三区尤| 久cao在线| 欧美午夜一区二区三区免费大片| free性中国hd国语露脸| 亚洲一级影院| αv一区二区三区| а√天堂在线官网| 5858s免费视频成人| www.99热| 日韩电影在线免费| 日本一区二区三区精品视频| 中文字幕人成乱码在线观看 | 日本国产在线| 婷婷成人激情在线网| 亚洲视频 中文字幕| 亚洲午夜极品| 国产精品一区二区三区在线| 黄色大片在线| 亚洲精品一区二区三区影院| 国产亚洲精品久久久久久打不开| 国产精品原创巨作av| 玖玖精品在线视频| 日韩精品中文字幕吗一区二区| 日韩中文字幕在线视频| 一二三区中文字幕| 亚洲欧美另类综合偷拍| 丰满饥渴老女人hd| 在线 亚洲欧美在线综合一区| 国产精品夜夜夜一区二区三区尤| 成入视频在线观看| 欧美成人日本| 久久视频这里只有精品| 中国黄色一级视频| av亚洲产国偷v产偷v自拍| 蜜桃传媒一区二区三区| 欧美日韩大片免费观看| 欧美一级免费视频| 国产爆初菊在线观看免费视频网站| 欧美在线综合视频| 欧美性生给视频| 国产高清精品网站| 青青草视频在线免费播放| 日韩美女毛片| 国产精品人成电影| 4438x成人网全国最大| 精品国产不卡一区二区三区| 五月婷婷中文字幕| 国产欧美精品一区aⅴ影院| 五月天婷婷亚洲| 欧美激情成人在线| 久久99影院| 九九热线视频只有这里最精品| 色婷婷av一区二区三区在线观看| 国产三级第一页| 亚洲第一狼人社区| 性欧美一区二区| 国产一区二区网址| 18禁免费观看网站| 99精品视频精品精品视频| av一区二区三区四区电影| 成年人黄色大片在线| 一区二区三区四区在线观看视频| 精品欧美一区二区精品少妇| 偷拍与自拍一区| 国产精品久久久久久成人| 成人在线一区二区三区| av免费网站观看| 国产精品v欧美精品v日本精品动漫| 久久婷婷开心| 国产日韩在线观看视频| 4k岛国日韩精品**专区| 国产黄大片在线观看画质优化| 亚洲激情在线视频| 国产精品玖玖玖| 欧美天堂在线观看| 久久久久人妻一区精品色欧美| 久久蜜桃av一区精品变态类天堂 | 91九色丨porny丨肉丝| 中文字幕乱码亚洲精品一区| 亚洲成年人av| 久久99精品国产91久久来源| av免费播放网址| 欧美96在线丨欧| 亚洲福利av| 欧美电影免费网站| 1卡2卡3卡精品视频| 国精产品一区一区三区四川| 午夜精品蜜臀一区二区三区免费| 免费av网站在线观看| 亚洲片av在线| 四虎免费在线观看| 日韩欧美三级在线| 国产美女永久免费| 欧美日韩精品综合在线| 丁香社区五月天| 欧美日韩亚洲视频一区| 日本一区二区三区免费视频| 亚洲欧洲日产国码二区| 欧洲av一区二区三区| www国产精品av| 日本不卡视频一区| 丰满岳乱妇一区二区三区| 三级一区二区三区| 久久国产剧场电影| 日本人视频jizz页码69| 日韩成人免费在线| 妓院一钑片免看黄大片| 乱人伦精品视频在线观看| 欧日韩免费视频| 在线 亚洲欧美在线综合一区| 国产精品无码电影在线观看| 亚洲欧美综合国产精品一区| 超碰在线免费观看97| 天天做天天爱天天综合网2021| 亚洲国产一区二区在线| 不卡av一区二区| 亚洲国产精品久久久久婷婷老年| 国产在线观看91一区二区三区| 欧美日韩精品久久| 色综合www| 欧美精品一区二区三区四区五区| 亚洲精品456| 欧美精品123| 国产中文字幕一区二区三区| 色姑娘综合av| 欧美3p视频| 做爰高潮hd色即是空| 亚洲国产老妈| 欧美乱做爰xxxⅹ久久久| 国产精品v亚洲精品v日韩精品| a级黄色小视频| 99在线精品视频在线观看| 精品久久一二三| 米奇777在线欧美播放| 亚洲欧美激情网| 久久 天天综合| 亚洲成人激情小说| 99国内精品久久| 亚洲无人区码一码二码三码的含义 | 欧美在线视频你懂得| 一区二区三区免费观看视频| 91精品视频网| 韩国av免费在线观看| 日韩精品免费在线视频观看| 黄色av免费在线观看| 三级精品视频久久久久| 91极品在线| 欧美在线视频免费观看| 小明成人免费视频一区| 91免费在线视频| 女一区二区三区| 亚洲人成网站在线观看播放| 午夜国产精品视频| 波多野结衣家庭教师视频| 久久精品国内一区二区三区| 不卡的一区二区| 久久久久久久久久久黄色| 亚洲av无一区二区三区| 亚洲成精国产精品女| 久久这里只有精品9| 日韩精品一区二区三区视频播放 | 三级视频中文字幕| 国产成人综合在线观看| 亚洲理论片在线观看| 一区二区三区高清不卡| 99超碰在线观看| 日韩欧美一级精品久久| 九色在线播放| 久久噜噜噜精品国产亚洲综合| 福利一区二区免费视频| 国产精品久久久久久免费观看| 成人高清av| www.99热这里只有精品| 国产一区二区三区日韩 | 第一会所亚洲原创| 精品少妇在线视频| 极品尤物av久久免费看| 30一40一50老女人毛片| 一区二区三区成人在线视频| 波多野结衣视频在线看| 亚洲成人精品视频在线观看| 午夜在线视频| 国产aaa精品| 极品束缚调教一区二区网站| 日韩最新中文字幕| 日本在线不卡一区| 日本japanese极品少妇| 一区二区三区日韩欧美精品| 中文字幕资源网| 亚洲精品一区久久久久久| 国产三线在线| 91手机视频在线观看| 日韩在线二区| 毛片av免费在线观看| 不卡免费追剧大全电视剧网站| 久久久久亚洲AV成人| 欧美日韩免费观看一区二区三区| 激情小视频在线| 欧美一区二区三区…… | 亚洲精品日韩成人| 日韩精品福利网| 国产精品揄拍100视频| 午夜电影久久久| 亚洲国产精品久久久久久6q| 久久国产精品久久精品| 日韩有码欧美| 宅男av一区二区三区| 美女视频网站久久| japanese中文字幕| 色av综合在线| 邻居大乳一区二区三区| 日本一区二区不卡| 无码日韩精品一区二区免费| 成熟丰满熟妇高潮xxxxx视频| 成人免费视频网站在线观看| 欧美色图亚洲视频| 欧美一区二区在线免费观看| 成视频免费观看在线看| 91在线无精精品一区二区| 亚洲综合中文| 韩国三级丰满少妇高潮| 一区二区三区在线免费播放 | 中文字幕系列一区| 少妇免费毛片久久久久久久久| 日本午夜精品视频在线观看 | 亚洲成人av在线电影| 欧洲成人一区二区三区| 性欧美长视频免费观看不卡| 欧美成人专区| 激情内射人妻1区2区3区 | 国产视频欧美视频| 婷婷激情一区| 一区二区三区偷拍| 国产美女在线观看一区| 国产亚洲自拍av| 日韩电影网在线| 精品欧美日韩精品| 一级特黄录像免费播放全99| 国内成+人亚洲+欧美+综合在线| 欧美日韩中文字幕在线观看| 精品少妇一区二区三区在线播放 | 国产精品探花一区二区在线观看| 色欧美乱欧美15图片| 欧洲美女少妇精品| 国产91社区| 视频一区欧美日韩| 欧美成人777| 亚洲国产精品悠悠久久琪琪| 日本韩国欧美| 大桥未久一区二区| 99视频在线观看一区三区| 波多野结衣一区二区三区在线| zzjj国产精品一区二区| eeuss鲁片一区二区三区| 少妇高清精品毛片在线视频 | 国产精品suv一区二区| 亚洲色图狂野欧美| 蜜桃精品视频| 播放灌醉水嫩大学生国内精品| 成人免费在线播放视频| 色一情一乱一区二区三区| 国产精品视频网站| 尤物在线精品| 国产天堂av在线| 日韩精品在线看| 警花av一区二区三区| 乱妇乱女熟妇熟女网站| 中文字幕亚洲在| 亚洲av激情无码专区在线播放| 成人a在线视频| 午夜影院日韩| 免费无遮挡无码永久在线观看视频 |