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

B站搜索建庫(kù)架構(gòu)優(yōu)化實(shí)踐

開(kāi)發(fā) 架構(gòu)
通過(guò)這一系列的技術(shù)更新和流程優(yōu)化,我們的索引構(gòu)建架構(gòu)最終從早期的單機(jī)構(gòu)建發(fā)展到分布式的數(shù)據(jù)存儲(chǔ)和建庫(kù)任務(wù),能力更強(qiáng)的同時(shí)也更易維護(hù)和迭代,索引構(gòu)建周期實(shí)現(xiàn)了從天級(jí)到小時(shí)級(jí)別的飛躍式進(jìn)步,為業(yè)務(wù)的未來(lái)發(fā)展奠定了堅(jiān)實(shí)基礎(chǔ)。

前言

搜索是B站的重要基礎(chǔ)功能,需要對(duì)包括視頻、評(píng)論、圖文等海量的站內(nèi)優(yōu)質(zhì)資源建立索引,處理來(lái)自用戶每日數(shù)億的檢索請(qǐng)求。離線索引數(shù)據(jù)的正確、高效產(chǎn)出是搜索業(yè)務(wù)的基礎(chǔ)。我們?cè)谶@里分享搜索離線架構(gòu)整體的改造實(shí)踐:從周期長(zhǎng),流程復(fù)雜的手工構(gòu)建流程,改造為高容量、高性能、易迭代的分布式建庫(kù)架構(gòu)的過(guò)程。

業(yè)務(wù)背景

B站是一個(gè)典型的多資源搜索場(chǎng)景,除了視頻外,還接入了包括UP主、番劇影視(PGC)、直播等幾十種不同類(lèi)型的資源。除了資源類(lèi)型多以外,各種資源的數(shù)據(jù)源的形式也多種多樣,包括數(shù)據(jù)庫(kù)、上游業(yè)務(wù)接口、Hive表等等。這些數(shù)據(jù)通過(guò)離線近線的聚合和構(gòu)建,以全量和增量實(shí)時(shí)流兩種方式生產(chǎn)出索引,在線上的服務(wù)中生效。

圖片圖片

實(shí)際業(yè)務(wù)中,除了搜索業(yè)務(wù)自己維護(hù)的視頻MySQL數(shù)據(jù)庫(kù)外,還接入了不同形式的數(shù)據(jù)來(lái)源,一并添加到全量/增量索引數(shù)據(jù)中構(gòu)建。這些數(shù)據(jù)有的僅T+1更新全量;有的則會(huì)提供增量數(shù)據(jù)流和接口,接入時(shí)也希望數(shù)據(jù)變更能在搜索索引中實(shí)時(shí)生效。

全量(base)索引:以文件形式提供,包含某一特定時(shí)間點(diǎn)之前的全部數(shù)據(jù),通常每天產(chǎn)出、更新一次。

增量(delta)索引:以數(shù)據(jù)流(消息隊(duì)列)的形式提供,每條消息對(duì)應(yīng)一份稿件的完整信息。增量索引能實(shí)時(shí)同步更新,適用于時(shí)效性要求高的場(chǎng)景,滿足用戶對(duì)新稿件的檢索需求。

這些第三方數(shù)據(jù)由于各種原因(MySQL容量或性能限制,數(shù)據(jù)維護(hù)團(tuán)隊(duì)不同等),不能直接集成到搜索的MySQL數(shù)據(jù)庫(kù)中。這些數(shù)據(jù)的引入在當(dāng)前的離線和近線建庫(kù)流程中是獨(dú)立的,隨著數(shù)據(jù)的種類(lèi)增加,搜索離線建庫(kù)流程也逐漸復(fù)雜起來(lái)。

索引數(shù)據(jù)產(chǎn)出流程

以視頻索引為例,構(gòu)建視頻索引時(shí)除了搜索自己維護(hù)的MySQL中視頻信息外,還需要接入多種第三方數(shù)據(jù)到索引中,如接入以下三類(lèi)數(shù)據(jù):

  • 數(shù)據(jù)A:第三方數(shù)據(jù)庫(kù)+binlog
  • 數(shù)據(jù)B:不開(kāi)放DB直接訪問(wèn),以導(dǎo)出的全量snapshot+接口+數(shù)據(jù)流形式間接提供
  • 數(shù)據(jù)C:Hive表

全量數(shù)據(jù)產(chǎn)出

為了獲取稿件信息,全量建庫(kù)流程需要先后將這些不同的數(shù)據(jù)源獲取到本地,合并為新的全量數(shù)據(jù)集,再構(gòu)建出二進(jìn)制全量索引。

圖片圖片

增量數(shù)據(jù)產(chǎn)出

對(duì)于增量索引,我們希望將每條稿件的完整字段(即包含搜索MySQL+數(shù)據(jù)源A/B/C的所有字段信息)聚合為一條增量索引消息下發(fā)。

我們監(jiān)聽(tīng)binlog A和數(shù)據(jù)流B,但只關(guān)心其中有變化的稿件id,通過(guò)變更搜索MySQL中相應(yīng)稿件的一個(gè)標(biāo)志位,觸發(fā)該稿件的一條binlog及后續(xù)的增量建庫(kù)流程。

在后續(xù)的建庫(kù)流程中,處理binlog時(shí)增加根據(jù)ID查詢MySQL A和接口B的邏輯,這樣就能從MySQL A的查詢結(jié)果,接口B的響應(yīng)和本地的文件C中拿到稿件的對(duì)應(yīng)數(shù)據(jù),寫(xiě)入到增量索引數(shù)據(jù)流中。

圖片圖片

注意這里對(duì)MySQL A和接口B有著嚴(yán)格的時(shí)效性要求,即查詢得到的數(shù)據(jù)不能比數(shù)據(jù)流下發(fā)的數(shù)據(jù)版本更舊,否則無(wú)法保證數(shù)據(jù)的最終一致性。

舉個(gè)例子,假如MySQL A的binlog來(lái)自主庫(kù),而按ID查詢時(shí)訪問(wèn)了MySQL A的從庫(kù)。

當(dāng)A中某個(gè)稿件的字段發(fā)生變化時(shí),在處理主庫(kù)的對(duì)應(yīng)binlog時(shí)會(huì)從從庫(kù)中查詢當(dāng)前值。由于主庫(kù)從庫(kù)之間的同步有一定延遲,這時(shí)有可能查詢到舊值而不是主庫(kù)中的新值,導(dǎo)致新值不會(huì)在索引中生效,除非該稿件有其他變更再次觸發(fā)binlog處理。

將MySQL A的binlog調(diào)整為由對(duì)應(yīng)從庫(kù)導(dǎo)出則可避免該問(wèn)題發(fā)生。

索引生效流程

B站的檢索引擎和正排服務(wù)加載索引數(shù)據(jù)的過(guò)程如下:

  1. 更新全量索引:服務(wù)周期性地獲取新的全量索引文件,解析元數(shù)據(jù),將索引加載到內(nèi)存中。
  2. 消費(fèi)增量數(shù)據(jù)流:加載了全量索引后,服務(wù)會(huì)從元數(shù)據(jù)指定的時(shí)間點(diǎn)開(kāi)始消費(fèi)增量索引數(shù)據(jù)流,直到消費(fèi)進(jìn)度接近當(dāng)前的最新產(chǎn)出。消費(fèi)到的數(shù)據(jù)會(huì)在服務(wù)側(cè)實(shí)時(shí)地建立增量索引,以支持查詢。當(dāng)一份稿件同時(shí)出現(xiàn)在增量索引和全量索引時(shí),全量索引中的數(shù)據(jù)被覆蓋;稿件在數(shù)據(jù)流中出現(xiàn)多次時(shí),增量索引中的舊值也會(huì)被新值覆蓋。
  3. 提供服務(wù):當(dāng)增量數(shù)據(jù)流的產(chǎn)出進(jìn)度被消費(fèi)追平后,服務(wù)進(jìn)入就緒狀態(tài),開(kāi)始處理請(qǐng)求。

問(wèn)題與挑戰(zhàn)

隨著搜索業(yè)務(wù)復(fù)雜度的增加和數(shù)據(jù)規(guī)模的增長(zhǎng),現(xiàn)有建庫(kù)邏輯在效率和資源層面逐漸難以為繼。

性能

新投稿的增多和歷史投稿的積累,讓搜索MySQL在建庫(kù)過(guò)程中的負(fù)載越來(lái)越大,開(kāi)始出現(xiàn)性能瓶頸。

造成MySQL高負(fù)載的主要場(chǎng)景有:

1. 表結(jié)構(gòu)變更:需要復(fù)制全表數(shù)據(jù)。數(shù)據(jù)復(fù)制期間,數(shù)據(jù)庫(kù)負(fù)載顯著增加。

2. 新增字段并批量導(dǎo)入:將新字段導(dǎo)入數(shù)據(jù)庫(kù)時(shí)需要大量寫(xiě)入,增加數(shù)據(jù)庫(kù)壓力。

  • 緩解措施:控制寫(xiě)入過(guò)程,在負(fù)載低峰期小批量執(zhí)行。

3. 全量索引構(gòu)建時(shí)的掃庫(kù)操作:索引構(gòu)建流程每次需要先查詢搜索MySQL數(shù)據(jù)庫(kù)獲取全量稿件信息,dump到文件中,再進(jìn)行索引構(gòu)建。當(dāng)在基線外另行構(gòu)建索引以支持AB實(shí)驗(yàn)時(shí),數(shù)據(jù)庫(kù)的查詢負(fù)載也會(huì)相應(yīng)地倍增。

  • 緩解措施:錯(cuò)開(kāi)不同構(gòu)建任務(wù)的執(zhí)行時(shí)間;將掃庫(kù)結(jié)果和元數(shù)據(jù)保存下來(lái),供多個(gè)建庫(kù)任務(wù)復(fù)用。

當(dāng)MySQL負(fù)載高時(shí),主從數(shù)據(jù)庫(kù)同步會(huì)出現(xiàn)延遲,導(dǎo)致索引數(shù)據(jù)更新不及時(shí)。用戶不能及時(shí)看到最新的投稿和變更,體驗(yàn)受損害。

我們?cè)谌粘?shí)驗(yàn)和迭代時(shí),都必須時(shí)刻考慮對(duì)數(shù)據(jù)庫(kù)的性能影響,而緩解數(shù)據(jù)庫(kù)壓力的措施往往導(dǎo)致迭代周期變長(zhǎng),不同的需求上的索引迭代也不能并行推進(jìn)。性能瓶頸和穩(wěn)定性風(fēng)險(xiǎn)成為了索引迭代的主要障礙。

維護(hù)成本

  1. 搜索索引原始數(shù)據(jù)沒(méi)有統(tǒng)一的存儲(chǔ)承載,數(shù)據(jù)可能來(lái)自多個(gè)數(shù)據(jù)庫(kù)、文件、甚至接口。離線和近線需要各自維護(hù)復(fù)雜的拼接邏輯,導(dǎo)致迭代困難,開(kāi)發(fā)周期長(zhǎng)。數(shù)據(jù)不符合預(yù)期時(shí),難以定位原因。
  2. 全量數(shù)據(jù)和增量數(shù)據(jù)的產(chǎn)出邏輯差異大,沒(méi)有機(jī)制能保證兩套鏈路上最終的產(chǎn)出結(jié)果一致。數(shù)據(jù)的不一致可能影響業(yè)務(wù)效果。
  3. 全量索引是單機(jī)構(gòu)建,構(gòu)建周期,實(shí)例部署和數(shù)據(jù)分片都需要人工維護(hù),每次迭代都消耗大量人力成本。
  4. 增量數(shù)據(jù)接入新的實(shí)時(shí)數(shù)據(jù)時(shí),數(shù)據(jù)提供方需要同時(shí)提供全量、增量數(shù)據(jù)和查詢接口。搜索業(yè)務(wù)和數(shù)據(jù)提供方的對(duì)接、開(kāi)發(fā)成本都較高。

資源

每次構(gòu)建索引時(shí),都需要對(duì)原始數(shù)據(jù)重新切詞分析,構(gòu)建正排、倒排索引。即使數(shù)據(jù)和策略沒(méi)有變化也需要重復(fù)計(jì)算。這些計(jì)算會(huì)消耗大量資源,并且增加索引構(gòu)建所需的時(shí)間。

設(shè)計(jì)目標(biāo)

反思索引構(gòu)建流程中的問(wèn)題,不管是復(fù)雜的多數(shù)據(jù)源合并流程、還是MySQL的性能壓力延遲風(fēng)險(xiǎn),歸根結(jié)底都是存儲(chǔ)設(shè)施能力不足,不能直接承載全部索引數(shù)據(jù)導(dǎo)致的問(wèn)題復(fù)雜化。我們期望將索引依賴的全部數(shù)據(jù)聚合到統(tǒng)一的存儲(chǔ)設(shè)施中,作為基準(zhǔn)數(shù)據(jù)源,直接基于該數(shù)據(jù)源導(dǎo)出全量數(shù)據(jù)和增量數(shù)據(jù)流,并將后續(xù)的建庫(kù)任務(wù)徹底分布式化,達(dá)到數(shù)據(jù)統(tǒng)一、可擴(kuò)展性大幅增強(qiáng)的目的。

預(yù)期新的架構(gòu)設(shè)計(jì)可解決當(dāng)前的痛點(diǎn):

  1. 用分布式的存儲(chǔ)設(shè)施承接搜索數(shù)據(jù),后續(xù)的構(gòu)建任務(wù)也進(jìn)行分布式化改造,讓建庫(kù)鏈路中不再有單點(diǎn)的性能瓶頸。
  2. 全量和增量都從統(tǒng)一的存儲(chǔ)設(shè)施中獲取,完全屏蔽原有不同數(shù)據(jù)來(lái)源對(duì)建庫(kù)過(guò)程的影響,可以讓建庫(kù)的流程簡(jiǎn)單化,降低開(kāi)發(fā)維護(hù)的成本。
  3. 有了足夠的存儲(chǔ)能力之后,我們可以將稿件切詞這類(lèi)較為穩(wěn)定的中間計(jì)算結(jié)果保存下來(lái),只在有數(shù)據(jù)或策略有變化時(shí)重新計(jì)算。節(jié)省計(jì)算資源的同時(shí)進(jìn)一步縮短全量構(gòu)建周期。

方案設(shè)計(jì)

既然MySQL不能滿足我們的需求,我們的人力也不允許從零開(kāi)始造一個(gè)輪子來(lái)維護(hù)索引數(shù)據(jù),首要的問(wèn)題是找到一個(gè)合適的存儲(chǔ)設(shè)施來(lái)作為基礎(chǔ),在其之上開(kāi)發(fā)數(shù)據(jù)處理和建庫(kù)邏輯。

存儲(chǔ)選型

我們希望新的存儲(chǔ)方案可以具有以下特性:

  • 高容量:可以存入目前全部的索引數(shù)據(jù)。易于水平拓展。
  • 高吞吐量:允許大批量的數(shù)據(jù)寫(xiě)入和導(dǎo)出。
  • 低延遲:可以快速隨機(jī)讀寫(xiě)單個(gè)稿件數(shù)據(jù)。
  • 易于迭代:數(shù)據(jù)的結(jié)構(gòu)可以靈活迭代,無(wú)需Online DDL操作(https://dev.mysql.com/doc/refman/8.4/en/innodb-online-ddl-operations.html)。

我們從現(xiàn)有的數(shù)據(jù)庫(kù)系統(tǒng)中尋求合適的選型:對(duì)于數(shù)據(jù)靈活迭代的需求排除了MySQL,TiDB等關(guān)系型數(shù)據(jù)庫(kù);批量更新稿件部分字段的需求對(duì)文檔存儲(chǔ)性的NoSQL數(shù)據(jù)庫(kù)不友好;HBase,Cassandra等列族存儲(chǔ)的數(shù)據(jù)模型比較合適,但簡(jiǎn)單寫(xiě)入查詢延遲較高;KV(鍵值)存儲(chǔ)延遲低,但數(shù)據(jù)模型不太匹配。

最終我們選擇在KV存儲(chǔ)的基礎(chǔ)上封裝行式(Row-Oriented)數(shù)據(jù)庫(kù)的形式,以達(dá)到兼顧吞吐與延遲的效果,并選擇了b站內(nèi)部存儲(chǔ)組件Taishan作為底層KV存儲(chǔ)。

Taishan是B站內(nèi)部的高性能分布式KV存儲(chǔ),具備多分片水平拓展能力,可應(yīng)對(duì)大規(guī)模存儲(chǔ)需求,簡(jiǎn)單讀寫(xiě)的延遲也較低,此外還具有以下特性:

  • 有序映射:key是有序的,支持scan(范圍查詢)。
  • 支持 CompareAndSwap 操作:基于CAS原子操作可實(shí)現(xiàn)樂(lè)觀鎖,在并發(fā)的數(shù)據(jù)更新時(shí)防止沖突。
  • 高效的數(shù)據(jù)導(dǎo)出:Taishan 支持快速將數(shù)據(jù)全量導(dǎo)出到對(duì)象存儲(chǔ)中,而不需要全表scan。

架構(gòu)設(shè)計(jì)

我們以Taishan為基礎(chǔ)存儲(chǔ)設(shè)施,在其上建立了強(qiáng)大的數(shù)據(jù)存儲(chǔ)層(基于表格存儲(chǔ)模型)和統(tǒng)一的數(shù)據(jù)接入和導(dǎo)出層。

圖片圖片

引入存儲(chǔ)層后,我們將原始數(shù)據(jù)源跟具體的建庫(kù)邏輯隔離,并抽象出可高度復(fù)用的數(shù)據(jù)導(dǎo)入導(dǎo)出邏輯,顯著降低了維護(hù)成本和后續(xù)開(kāi)發(fā)成本。

離線和近線使用相同的數(shù)據(jù)來(lái)源并復(fù)用導(dǎo)出邏輯,從根本上消除了全量索引和增量索引數(shù)據(jù)不一致的可能。

高容量的存儲(chǔ)層允許我們以增量計(jì)算形式來(lái)源空間換取時(shí)間:將一些中間計(jì)算結(jié)果(如切詞和Embedding等)也一并保存,僅在相關(guān)稿件屬性有變化時(shí)觸發(fā)計(jì)算并更新;建庫(kù)時(shí)直接使用保存下來(lái)的結(jié)果,計(jì)算量大幅減少。

在全部數(shù)據(jù)都經(jīng)Taishan聚合后,離線近線的流程變得清晰直觀起來(lái),同時(shí)在根本上消除了全量和增量數(shù)據(jù)不一致的可能性。增量計(jì)算的引入也減少了大量重復(fù)的計(jì)算量,節(jié)省了資源。新的數(shù)據(jù)流程使得迭代和維護(hù)都大為簡(jiǎn)化。

數(shù)據(jù)存儲(chǔ)層

表格模型

基于KV存儲(chǔ)之上封裝出表格存儲(chǔ)模型:

  • 行:每一行代表一個(gè)稿件,通過(guò)稿件ID標(biāo)識(shí)。
  • 列:每一列存儲(chǔ)稿件的若干相關(guān)字段,通過(guò)字段族名(CF,column family)標(biāo)識(shí)。
  • 單元格:行和列的組合確定一個(gè)單元格,對(duì)應(yīng)KV存儲(chǔ)中的一條記錄。

圖片圖片

如上表所示,稿件ID和行一一對(duì)應(yīng)。而稿件的具體字段和列(CF)是多對(duì)多的關(guān)系:

  • 同一稿件的若干相關(guān)字段可以打包保存在一列(如title和uname),這樣會(huì)大幅減少KV的訪問(wèn)次數(shù),提高效率。
  • 表格中不同的列可以保存相同的字段。例如:
  • 這里eb,eb1兩列分別對(duì)應(yīng)doc_embedding字段的不同版本。指定不同的列組合(fs,seg,eb)/(fs,seg,eb1),可以構(gòu)建出兩版包含相同(title,uname,title_term,uname_term),以及不同版本doc_embedding的索引數(shù)據(jù)。

支持并發(fā)寫(xiě)入

Taishan的CAS支持允許我們?cè)诓煌瑢?xiě)入方之間通過(guò)樂(lè)觀鎖來(lái)同步,避免多個(gè)寫(xiě)入方同時(shí)更新一個(gè)單元格時(shí)發(fā)生寫(xiě)入丟失。

如果一列的寫(xiě)入方唯一,也可以不使用CAS直接寫(xiě)入。

支持并發(fā)寫(xiě)入消除了將多個(gè)字段放進(jìn)同一CF的后續(xù)維護(hù)風(fēng)險(xiǎn)。即使同一列后續(xù)要增加新的寫(xiě)入方,也無(wú)需對(duì)該列進(jìn)行拆分改造。

Key設(shè)計(jì)

Key由ID和字段族名組成。下圖是稿件ID1234567890的seg列對(duì)應(yīng)的實(shí)際Key內(nèi)容。ID和列名間用 “:”來(lái)分隔。

圖片

Data Orientation

Key的設(shè)計(jì)決定了數(shù)據(jù)排列方式。底層Taishan存儲(chǔ)中,數(shù)據(jù)按Key的字符串順序連續(xù)排列。

ID1:CF1

ID1:CF2

ID2:CF1

ID2:CF2

我們將稿件ID放在列名稱(chēng)前,這樣表格數(shù)據(jù)在Taishan中實(shí)際存放形式如下:

ID1:CF1

ID1:CF2

ID2:CF1

ID2:CF2

實(shí)際使用場(chǎng)景中我們主要按行掃描(獲取相同ID的所有字段值),較少按列掃描(獲取某一字段下所有取值)。同一ID下所有列連續(xù)分布的排列使得按ID(行)讀取時(shí)有更好的訪問(wèn)局部性和Cache命中率。

同時(shí),ID使用大端序int64保存。大端序的特點(diǎn)是作為字符串看待時(shí)的順序和數(shù)字的升序一致,讓遍歷過(guò)程總是按ID升序執(zhí)行,符合人的直覺(jué)與習(xí)慣。

Value設(shè)計(jì)

Value總是以一個(gè)varint N作為header,該varint標(biāo)識(shí)隨后的N個(gè)字節(jié)保存的是元數(shù)據(jù),其余的字節(jié)則用于存儲(chǔ)實(shí)際數(shù)據(jù)。

下圖是一個(gè)包含header、元數(shù)據(jù)(大小為8字節(jié))和數(shù)據(jù)(大小為5字節(jié))的value。

圖片圖片

通過(guò)這種設(shè)計(jì),我們得到了一個(gè)高效、靈活且近似于傳統(tǒng)表格存儲(chǔ)的系統(tǒng),可以為索引建庫(kù)提供強(qiáng)大的支持。

序列化

拋棄JSON

在最初的建庫(kù)流程中,我們使用JSON Lines文件格式保存原始的稿件數(shù)據(jù),例如:video.jsonl

{"id": 81403056, "title": "高燃舞臺(tái)演繹B站最美的夜", "uname": "嗶哩嗶哩晚會(huì)", "doc_embedding": [0.168322, 0.015824, 0.091791, -0.2059]}
{"id": 613621262, "title": "【觸手猴】「強(qiáng)風(fēng)オールバック」を弾いてみた【Piano】", "uname": "marasy_觸手猴", "doc_embedding": [0.007262, 0.040466, 0.028768, 0.161083]}

JSON格式具有良好的可讀性,但效率和性能不足,主要體現(xiàn)在:

  • 存儲(chǔ)效率低:每條記錄中都會(huì)重復(fù)保存字段名及符號(hào)(如 {} 和 ""),浪費(fèi)大量存儲(chǔ)空間。
  • 序列化性能低:文本格式的解析性能較差。

如果將完整的稿件字段拆分到多個(gè)列中分別保存,導(dǎo)出和查詢時(shí)的序列化消耗會(huì)更加嚴(yán)重。

轉(zhuǎn)向protobuf

為了解決上述問(wèn)題,我們選擇了Protocol Buffers(protobuf)格式來(lái)序列化稿件字段。以下是簡(jiǎn)化的Video消息的protobuf定義:video.proto

message Video {
    int64 id = 1;
    string title = 2;
    string uname = 3;
    repeated float doc_embedding = 4;
}

protobuf的優(yōu)勢(shì)主要有:

  • 存儲(chǔ)空間優(yōu)化:protobuf使用field number(以varint形式存儲(chǔ))來(lái)區(qū)分字段,相比于JSON中存儲(chǔ)完整字段名,大大節(jié)省了存儲(chǔ)空間。
  • 性能提升:protobuf的反序列化速度優(yōu)于JSON。
  • 類(lèi)型安全:和JSON相比,protobuf為數(shù)據(jù)字段提供了強(qiáng)類(lèi)型保證,增強(qiáng)了我們對(duì)數(shù)據(jù)的信心。嚴(yán)格的數(shù)據(jù)類(lèi)型也從源頭上消除了JSON 固有的最大安全整數(shù)(https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/MAX_SAFE_INTEGER)問(wèn)題。

高效地合并

對(duì)于protobuf消息,多個(gè)序列化后的數(shù)據(jù)塊(buffer)可以直接拼接來(lái)達(dá)到合并的效果:

Video v;
v.ParseFromString(buf1 + buf2);

這與將其分布反序列化后再執(zhí)行合并是等效的:

Video v1, v2;
v1.ParseFromString(buf1);
v2.ParseFromString(buf2);
v1.MergeFrom(v2);

假設(shè)稿件的標(biāo)題保存在列1,稿件Embedding信息保存在列2,buf1/buf2分別是對(duì)應(yīng)單元格查詢的數(shù)據(jù)。我們只需要直接concate未經(jīng)反序列化的兩段buffer即可拼接出稿件完整數(shù)據(jù)。

在使用Cord(https://protobuf.dev/reference/cpp/cpp-generated/#cord)或zero_copy_stream(https://protobuf.dev/reference/cpp/api-docs/google.protobuf.io.zero_copy_stream/)的情況下,連這一次拼接也可以省去。

變更數(shù)據(jù)流

Taishan原生支持binlog導(dǎo)出,可以將變更的Key和Value導(dǎo)出到數(shù)據(jù)流。但直接使用Taishan的binlog會(huì)有以下問(wèn)題:

  • 大批量寫(xiě)入數(shù)據(jù)時(shí),會(huì)產(chǎn)出大量消息,對(duì)后續(xù)的整個(gè)近線鏈路乃至線上服務(wù)造成壓力。
  • Value只包含變更的列,獲取完整的數(shù)據(jù)仍需按ID掃描Taishan表。

為了靈活控制變處理,我們封裝了寫(xiě)入層,在數(shù)據(jù)寫(xiě)入Taishan完成后另外輸出一條變更消息,示例如下:

{"id": 613621262, "cf_changed": ["eb"]} // 稿件av613621262的eb列發(fā)生了變更

數(shù)據(jù)變更的場(chǎng)合是否輸出對(duì)應(yīng)變更消息到流中是可指定的,批量寫(xiě)入數(shù)據(jù)時(shí)我們選擇不觸發(fā)。

我們也省略了變更后的值,需要的消費(fèi)者可以直接查詢Taishan表的主節(jié)點(diǎn)獲取最新的字段。

查詢從節(jié)點(diǎn)可能得到更新前的舊值,破環(huán)數(shù)據(jù)的最終一致性。

數(shù)據(jù)接入層

存儲(chǔ)方案和序列化方式的確定后,我們開(kāi)始將現(xiàn)有的數(shù)據(jù)統(tǒng)一接入到Taishan中。具體而言是將原有的數(shù)據(jù)庫(kù)全量增量以及T+1更新的數(shù)據(jù)全部寫(xiě)入上文所說(shuō)的Taishan表格,并按需同步到變更數(shù)據(jù)流。

T+1數(shù)據(jù)接入

T+1更新的數(shù)據(jù)沒(méi)有實(shí)時(shí)的增量更新,只需要定時(shí)寫(xiě)入全量。

寫(xiě)入的邏輯是高度復(fù)用的,同過(guò)指定配置將hive表/TSV/CSV/JSON Lines文件映射到Taishan中的對(duì)應(yīng)列。

圖片圖片

從新版全量中被刪除的數(shù)據(jù)需要額外的處理:我們需要跟上一版數(shù)據(jù)對(duì)比,找出這些被刪除的數(shù)據(jù),將這些數(shù)據(jù)同步從Taishan中刪除。

實(shí)時(shí)數(shù)據(jù)接入

實(shí)時(shí)數(shù)據(jù)接入需要將數(shù)據(jù)實(shí)時(shí)寫(xiě)入Taishan,并同步到變更數(shù)據(jù)流。寫(xiě)入的順序必須為先寫(xiě)Taishan再寫(xiě)變更數(shù)據(jù)流,保證后續(xù)處理變更流時(shí)能從Taishan主節(jié)點(diǎn)查到最新取值。

圖片圖片

由于我們不能對(duì)上游提供的變更數(shù)據(jù)流的字段定義做任何的限制和假設(shè),處理增量的Worker需要開(kāi)發(fā)少量的解析邏輯。

增量寫(xiě)入只寫(xiě)入了最近有變更的數(shù)據(jù),為了讓Taishan保存全部的歷史數(shù)據(jù),在實(shí)時(shí)數(shù)量接入后,我們還需要再獲取一份全量數(shù)據(jù)(產(chǎn)出時(shí)間在增量接入后),將這些數(shù)據(jù)也寫(xiě)入Taishan中。

這的全量寫(xiě)入過(guò)程和T+1數(shù)據(jù)接入類(lèi)似,區(qū)別在于只需要初始化時(shí)執(zhí)行一次,后續(xù)的變更都可以通過(guò)增量來(lái)獲取。另外T+1全量寫(xiě)入時(shí)需要考慮和增量寫(xiě)入沖突的情況,具體在后文介紹。

寫(xiě)入沖突處理

全量vs增量

包含實(shí)時(shí)數(shù)據(jù)的數(shù)據(jù)在導(dǎo)入時(shí)往往也需要刷入一份全量數(shù)據(jù)做初始化。

一般來(lái)說(shuō),全量中的數(shù)據(jù)會(huì)比來(lái)自數(shù)據(jù)流的舊,直接寫(xiě)入會(huì)將來(lái)自數(shù)據(jù)流的新值覆蓋。

因此寫(xiě)入時(shí)需要利用CAS,僅當(dāng)滿足Precondition:值不存在時(shí),才會(huì)寫(xiě)入。

增量vs增量

同一列可以有多個(gè)寫(xiě)入方,比如兩個(gè)worker消費(fèi)兩條不同的數(shù)據(jù)流寫(xiě)入同一列中的兩個(gè)不同字段。此時(shí)需要先讀取稿件的該列的舊值,更新其中的新字段后,將完整的新值寫(xiě)入。

當(dāng)兩個(gè)worker同時(shí)運(yùn)行時(shí),可能發(fā)生寫(xiě)寫(xiě)沖突(Write-Write Conflict),導(dǎo)致一個(gè)worker寫(xiě)入的新值,被另外的worker覆蓋而丟失。

在這種場(chǎng)景下,我們同樣使用CAS,在計(jì)算出新值后,僅當(dāng)滿足Precondition:值==舊值時(shí),才會(huì)寫(xiě)入新值,當(dāng)Precondition不滿足時(shí),必須重試。

增量計(jì)算

我們將一些中間計(jì)算結(jié)果也保存在Taishan中。典型的場(chǎng)景如稿件標(biāo)題的切詞和向量化的結(jié)果。具體而言,如果使用的計(jì)算策略和稿件標(biāo)題沒(méi)有變化,切詞和向量化的結(jié)果可以認(rèn)為是穩(wěn)定的。因此我們可以保存這些結(jié)果來(lái)避免重復(fù)計(jì)算,只在稿件的屬性有變化時(shí)更新計(jì)算結(jié)果。

增量更新切詞結(jié)果的工作流如下圖所示:

圖片圖片

和實(shí)時(shí)數(shù)據(jù)接入類(lèi)似,在首次接入時(shí)也需要對(duì)全部已有數(shù)據(jù)進(jìn)行一次切詞,讓歷史稿件也有切詞結(jié)果。初始化過(guò)程同樣需要使用CAS來(lái)規(guī)避寫(xiě)寫(xiě)沖突。

數(shù)據(jù)導(dǎo)出層

數(shù)據(jù)進(jìn)入Taishan后,我們需要從中導(dǎo)出需要的數(shù)據(jù)來(lái)構(gòu)建全量和增量索引。

對(duì)于一份索引,其全量和增量構(gòu)建任務(wù)的配置是共用的,獲取到實(shí)際數(shù)據(jù)后的處理邏輯也是一致的。

Taishan中不同的列可以保存字段的多個(gè)版本,具體構(gòu)建全量和增量索引時(shí)選用哪些列中的字段,需要在配置中指定。配置中以白名單的形式指定列,無(wú)需擔(dān)心新增列對(duì)已有構(gòu)建任務(wù)產(chǎn)生影響。

不同版本的索引大部分情況下只需要調(diào)整配置再另行部署即可產(chǎn)出。

圖片圖片

全量數(shù)據(jù)導(dǎo)出

Taishan會(huì)每日定期將全量數(shù)據(jù)備份到公司內(nèi)部的對(duì)象存儲(chǔ)。我們通過(guò)備份數(shù)據(jù)好的數(shù)據(jù),遍歷其中的全部KV,也就是按行遍歷表格,取出指定的列來(lái)獲取全量索引數(shù)據(jù)。Taishan備份效率是非常高的,通常在分鐘級(jí),這也大幅地減少了掃庫(kù)的時(shí)間開(kāi)銷(xiāo)。

增量數(shù)據(jù)導(dǎo)出

增量數(shù)據(jù)的導(dǎo)出通過(guò)消費(fèi)變更數(shù)據(jù)流實(shí)現(xiàn)。消費(fèi)后對(duì)每條消息(ID+變更的CF)反查T(mén)aishan,獲取所需的完整字段。

數(shù)據(jù)迭代

新的存儲(chǔ)機(jī)制簡(jiǎn)化了索引的迭代流程,只需要將新數(shù)據(jù)寫(xiě)入Taishan,然后調(diào)整構(gòu)建任務(wù)關(guān)注的列即可。迭代的開(kāi)發(fā)量大幅下降,基本只需復(fù)用現(xiàn)有流程,調(diào)整配置后部署新任務(wù)。

圖片圖片

隨著新存儲(chǔ)方案和增量計(jì)算等優(yōu)化的落地,索引構(gòu)建的周期縮短了一半以上。迭代周期縮短的同時(shí),消除了鏈路上的性能瓶頸和延遲風(fēng)險(xiǎn)。

分布式構(gòu)建

搜索索引最早都是通過(guò)物理機(jī)crontab定時(shí)執(zhí)行腳本實(shí)現(xiàn)。腳本執(zhí)行各種掃庫(kù)操作,將數(shù)據(jù)加載到內(nèi)存中,并產(chǎn)出一份完整的JSON Lines文本文件作為原始索引數(shù)據(jù)集,然后調(diào)用indexer進(jìn)行全量切詞和構(gòu)建正排/倒排索引。物理機(jī)部署穩(wěn)定性沒(méi)有保證且難以維護(hù),我們首先把構(gòu)建遷移到K8S集群上,嘗試以服務(wù)形式部署。這樣雖然保證了建庫(kù)任務(wù)的穩(wěn)定性,但是建庫(kù)任務(wù)資源利用率很低。建庫(kù)服務(wù)構(gòu)建時(shí)需要大量資源,但在大多數(shù)時(shí)間里是不消耗任何資源的,容器依然需要占據(jù)相應(yīng)的CPU/內(nèi)存資源。雖然通過(guò)超配(低軟限高硬限)并錯(cuò)開(kāi)任務(wù)觸發(fā)時(shí)間可以來(lái)減少資源空置的情況,但維護(hù)較為繁瑣。最終我們選擇將建庫(kù)遷移到業(yè)界廣泛使用的分布式計(jì)算框架Spark上,利用Spark潮汐資源進(jìn)行索引構(gòu)建,一方面可以加大構(gòu)建并發(fā),另一方面也可以對(duì)資源進(jìn)行更充分的利用。

為了能夠盡可能的復(fù)用及降低維護(hù)成本,從流程上進(jìn)行抽象,將索引構(gòu)建流程分以下主要步驟:

  1. 讀取數(shù)據(jù):從配置中加載并進(jìn)行數(shù)據(jù)讀取,Taishan源在對(duì)象存儲(chǔ)的導(dǎo)出文件為sst格式,使用官方開(kāi)源的JNI庫(kù)進(jìn)行二次封裝。
  2. 解碼 :Taishan非Spark原生支持的數(shù)據(jù)源,需要額外開(kāi)發(fā)解析邏輯。
  3. 再分片:由于導(dǎo)出的單一文件分片數(shù)據(jù)量較大,一次性讀取將占用大量?jī)?nèi)存,甚至OOM。為解決上述問(wèn)題,參考Spark的cache機(jī)制,在讀取并解碼文件數(shù)據(jù)流的過(guò)程時(shí)先將文件載入到指定內(nèi)存buffer中,若buffer裝滿則生成一個(gè)分片(partition)并寫(xiě)入hdfs中。以此將較少的文件分片(如128個(gè))拆分為較多的hdfs文件分片(如5000個(gè)),便于Spark的后續(xù)處理。
  4. 稿件處理:通過(guò)配置對(duì)稿件數(shù)據(jù)進(jìn)行一系列的處理操作,如過(guò)濾、字段映射等。
  5. 編碼 & 索引構(gòu)建:將稿件內(nèi)容轉(zhuǎn)化為索引需要的特定編碼形式,如Flatbuffer、Protobuffer。并根據(jù)索引類(lèi)型和Meta信息,產(chǎn)出索引。
  6. 壓縮打包:對(duì)構(gòu)建出的索引及Meta數(shù)據(jù)進(jìn)行打包,產(chǎn)出最終索引文件。 

除更省資源外,Spark構(gòu)建的任務(wù)并發(fā)度也更高,進(jìn)一步縮短了構(gòu)建時(shí)間,最終達(dá)到小時(shí)級(jí)別。

總結(jié)與展望

通過(guò)這一系列的技術(shù)更新和流程優(yōu)化,我們的索引構(gòu)建架構(gòu)最終從早期的單機(jī)構(gòu)建發(fā)展到分布式的數(shù)據(jù)存儲(chǔ)和建庫(kù)任務(wù),能力更強(qiáng)的同時(shí)也更易維護(hù)和迭代,索引構(gòu)建周期實(shí)現(xiàn)了從天級(jí)到小時(shí)級(jí)別的飛躍式進(jìn)步,為業(yè)務(wù)的未來(lái)發(fā)展奠定了堅(jiān)實(shí)基礎(chǔ)。

參考

  • https://protobuf.dev/programming-guides/encoding/#varints
  • https://dev.mysql.com/doc/refman/8.4/en/innodb-online-ddl-operations.html
  • https://research.google/pubs/large-scale-incremental-processing-using-distributed-transactions-and-notifications/
  • https://protobuf.dev/programming-guides/encoding/#last-one-wins
責(zé)任編輯:武曉燕 來(lái)源: 嗶哩嗶哩技術(shù)
相關(guān)推薦

2022-07-05 15:08:52

機(jī)房架構(gòu)

2022-11-22 08:42:38

數(shù)據(jù)庫(kù)

2024-04-26 12:13:45

NameNodeHDFS核心

2024-02-28 07:50:36

大數(shù)據(jù)標(biāo)簽系統(tǒng)AB 實(shí)驗(yàn)

2022-09-15 15:18:23

計(jì)算實(shí)踐

2025-03-05 00:00:55

2022-07-29 14:53:09

數(shù)據(jù)實(shí)踐

2020-04-28 08:15:55

高可用架構(gòu)系統(tǒng)

2023-02-16 07:24:27

VPA技術(shù)

2023-02-09 07:38:39

配置中心架構(gòu)組件

2023-07-19 08:58:00

數(shù)據(jù)管理數(shù)據(jù)分析

2023-02-28 12:12:21

語(yǔ)音識(shí)別技術(shù)解碼器

2023-02-13 09:48:00

PRESTO 集群緩存優(yōu)化

2022-10-08 15:41:08

分布式存儲(chǔ)

2023-10-26 06:43:25

2012-07-03 08:57:42

ASO百度移動(dòng)搜索手機(jī)站優(yōu)化

2015-05-07 09:32:55

APP開(kāi)源

2023-11-03 12:54:00

KAFKA探索中間件

2022-04-07 16:50:28

FlinkB站Kafka

2023-03-31 13:31:45

點(diǎn)贊
收藏

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

亚洲国产国产亚洲一二三| 国产日韩电影| 成人福利视频网站| 国内伊人久久久久久网站视频 | 欧美久久九九| 亚洲成人激情在线| 欧美一区二区三区爽大粗免费 | 精品少妇一区二区三区免费观看| 成人性生活视频免费看| 日韩欧美在线番号| 免费在线观看视频一区| 欧美另类老女人| 国产精品嫩草av| 亚洲一区二区三区四区| 中文字幕一区二区日韩精品绯色| 懂色中文一区二区三区在线视频| 日本特级黄色片| 精品国产99| 欧美大片一区二区| 日韩中文字幕二区| 国产在线69| 26uuu国产一区二区三区| 日韩av电影在线网| a级片在线观看免费| 六月丁香久久丫| 精品婷婷伊人一区三区三| 亚洲小视频在线播放| 欧美亚洲精品在线观看| 蜜臀av国产精品久久久久| 久久久久久久久久国产精品| 蜜臀av一区二区三区有限公司| 99综合久久| 色综合久久88色综合天天免费| 国产又粗又爽又黄的视频| 五月婷婷在线观看视频| 狠狠狠色丁香婷婷综合久久五月| 51ⅴ精品国产91久久久久久| 激情无码人妻又粗又大| 香蕉一区二区| 精品国产欧美一区二区| 15—17女人毛片| 麻豆mv在线看| 国产精品萝li| 日本高清久久一区二区三区| www.五月激情| 精品一区精品二区高清| 日本久久中文字幕| 日韩特黄一级片| 久久久久久久久久久9不雅视频| 亚洲欧洲av一区二区| 日本不卡视频一区| 国产视频一区二区在线播放| 欧美亚洲一区三区| 99999精品视频| 高清精品在线| 亚洲午夜在线视频| 国产手机视频在线观看| av午夜在线| 国产调教视频一区| 欧美另类网站| 欧美高清成人| 久久尤物电影视频在线观看| 国产精品一区在线播放| 国内老熟妇对白xxxxhd| 国产一区欧美二区| 91欧美视频网站| 中文字幕人妻一区二区在线视频 | 精品国产一区二区三区性色av| 欧美性色综合网| 青青在线免费观看视频| 成人激情综合| 欧美视频在线一区| 欧美日韩在线观看不卡| 国产综合色激情| 欧美日韩在线不卡| 亚洲一区二区三区四区五区xx| 精品91久久| 在线观看视频欧美| 国产av人人夜夜澡人人爽| 日韩pacopacomama| 色综合久久中文综合久久牛| 国产精品亚洲αv天堂无码| 北岛玲heyzo一区二区| 色哟哟一区二区在线观看| 国产主播在线看| 成人国产精品一区二区免费麻豆 | 日本午夜免费一区二区| 欧美高清hd18日本| gogo亚洲国模私拍人体| 都市激情久久| 日韩成人在线观看| 成人免费无遮挡无码黄漫视频| 国产精品一在线观看| 神马国产精品影院av| 亚洲 欧美 变态 另类 综合| 欧美日韩在线大尺度| 9.1国产丝袜在线观看| 东京热一区二区三区四区| 日本 国产 欧美色综合| 成人写真视频福利网| 亚洲成人久久精品| 久久天天做天天爱综合色| 日韩欧美在线观看强乱免费| 国产日产一区二区三区| 亚洲精品久久久久久国产精华液| 国产www免费| 欧美日韩精品免费观看视完整| 欧美另类高清zo欧美| 欧美激情一区二区三区p站| 亚洲天堂日韩在线| 成人97在线观看视频| 狠狠躁夜夜躁人人爽天天高潮| 久久亚洲国产精品一区二区| 国产中文字幕日韩| 日本免费不卡视频| 国产精品麻豆欧美日韩ww| 成人免费毛片在线观看| 欧亚一区二区| 欧美草草影院在线视频| 日本一区二区三区网站| 久久久久蜜桃| 奇米四色中文综合久久| 中文字幕在线日亚洲9| 高清不卡在线观看| 午夜精品美女久久久久av福利| 色a资源在线| 精品视频在线免费观看| 9191在线视频| 欧美电影三区| 国产91色在线|| 亚洲黄色小说网| 国产午夜久久久久| 免费看黄在线看| 亚洲精品aaa| 亚洲一区二区福利| 久久精品亚洲无码| 久久精品久久综合| 欧美日韩精品久久| 国产深夜视频在线观看| 91.麻豆视频| 熟女丰满老熟女熟妇| 欧美视频成人| 亚洲综合精品伊人久久| av资源网在线观看| 在线观看免费亚洲| 最新中文字幕视频| 日韩图片一区| 操人视频欧美| 超碰个人在线| 欧美高清视频不卡网| 青青青视频在线播放| 久久久久91| 久久riav二区三区| av福利导福航大全在线| 精品福利av导航| 久一区二区三区| 国产精品一区二区三区网站| 亚洲精品一区二区三区樱花| 伊人成综合网站| 亚洲护士老师的毛茸茸最新章节| 九九视频免费看| 国产激情视频一区二区在线观看| 亚洲精品欧洲精品| 欧美日韩尤物久久| 亚洲小视频在线观看| 黄色片网站在线免费观看| 2024国产精品视频| 欧美三级一级片| 亚洲婷婷伊人| 国产成+人+综合+亚洲欧洲| 欧美在线观看在线观看| 日韩欧美精品中文字幕| 男人天堂av电影| 亚洲一区国产一区| 欧美高清一区二区| 日韩中文视频| 中文字幕日韩有码| 中国a一片一级一片| 国产精品美女一区二区| 国产精品自在自线| 欧美破处大片在线视频| 国产一区在线免费| 澳门成人av网| 日韩中文字幕不卡视频| 97人妻精品一区二区三区| 亚洲免费在线看| 在线观看免费视频国产| 亚洲美女色禁图| 日韩av电影免费观看| 久久久久久久性潮| 欧美贵妇videos办公室| 三区在线视频| 欧美日韩精品一区二区| 午夜三级在线观看| 不卡在线视频中文字幕| 超碰影院在线观看| 亚洲成人最新网站| 成人片在线免费看| 日韩大片欧美大片| 久久精品91久久香蕉加勒比| 丁香六月色婷婷| 91精品福利视频| 成人免费视频国产免费观看| av在线一区二区三区| 欧美 日韩 激情| 999视频精品| 国产综合av一区二区三区| 欧美日韩精品免费观看视完整| www.亚洲一区| 色婷婷av一区二区三| 欧美色视频在线观看| 免费中文字幕在线观看| 久久久久亚洲综合| 亚洲一区二区偷拍| 久久久国产精品一区二区中文| 国产福利片一区二区| 999久久精品| 国产成人一区二区在线| 七七成人影院| 亚洲一区二区福利| 隣の若妻さん波多野结衣| 在线免费不卡电影| 日本三级午夜理伦三级三| 国产精品福利一区| 瑟瑟视频在线观看| 丁香天五香天堂综合| 亚洲黄色av网址| 国产日韩1区| 第九区2中文字幕| 亚洲日产av中文字幕| 成人欧美视频在线| 成人97精品毛片免费看| 国产做受高潮69| 中文在线字幕免费观看| 国产亚洲精品久久久久久牛牛| 国产精品国产av| 欧洲精品在线观看| 欧美日韩综合在线观看| 亚洲特级片在线| 黄色三级生活片| 久久人人爽人人爽| 99精品一区二区三区无码吞精| 国内外成人在线| 亚洲77777| 性欧美精品高清| 人妻无码久久一区二区三区免费| 国产精品88久久久久久| 亚洲 国产 欧美一区| 成人同人动漫免费观看 | 成人精品网站在线观看| 亚洲一区有码| 91精品天堂| 99香蕉久久| 久久精品国产精品青草色艺 | 欧美色网在线| 国产精品成av人在线视午夜片 | 日本成人不卡| 国内精品久久久久伊人av| 国产精品xx| 日韩av手机在线| 日韩成人在线电影| 2019国产精品视频| 红杏aⅴ成人免费视频| 免费在线成人av电影| 欧美午夜精品一区二区三区电影| 亚洲一区二区免费视频软件合集 | 天堂网av成人| 色女孩综合网| 综合国产精品| 亚洲色成人一区二区三区小说| 免费国产亚洲视频| 久久久精品视频国产| youjizz久久| 五月天综合视频| 亚洲欧洲国产日本综合| 日本少妇做爰全过程毛片| 日本国产一区二区| 国产精品高潮呻吟久久久| 亚洲精品suv精品一区二区| 狠狠色伊人亚洲综合网站l| 久久久97精品| 亚洲三级欧美| 国产日韩在线看| 老牛精品亚洲成av人片| 视频一区不卡| 影音先锋久久久| 成人性做爰aaa片免费看不忠| 国产一区在线看| 久久亚洲AV无码专区成人国产| 日韩毛片在线免费观看| 国产成人免费看| 91精品国产色综合久久不卡电影| 性xxxx搡xxxxx搡欧美| 久久精品国亚洲| 在线视频cao| 91免费欧美精品| 精品视频97| 五十路熟女丰满大屁股 | 精品人妻一区二区免费视频| 欧美国产精品一区二区| 国产成人愉拍精品久久| 宅男在线国产精品| 你懂的在线观看视频网站| 久久视频在线直播| 忘忧草在线www成人影院| 国产精品对白一区二区三区| 欧美电影免费观看高清| 粗暴91大变态调教| 成人美女视频在线观看| 亚洲xxxx3d动漫| 欧美性大战xxxxx久久久| 天堂在线视频免费观看| 久久99精品国产99久久6尤物| 日韩av超清在线观看| 精品视频高清无人区区二区三区| 亚洲欧洲日韩| 成人日韩在线视频| 国产日韩欧美不卡在线| 亚洲 欧美 日韩 综合| 日韩欧美中文字幕公布| 日韩伦理在线观看| 国产精品成熟老女人| 日韩美脚连裤袜丝袜在线| 久久久久久久久久久综合| 久久99精品一区二区三区| 久久亚洲AV无码专区成人国产| 欧美色另类天堂2015| 色噜噜在线播放| 午夜伦理精品一区| 福利在线一区| 精品少妇人欧美激情在线观看| 国产乱码一区二区三区| 欧美另类videoxo高潮| 欧美美女bb生活片| 调教视频免费在线观看| 国产日本欧美在线观看| 日韩av在线中文字幕| 欧美成人黄色网址| 国产精品免费av| 97在线播放免费观看| 日韩亚洲欧美成人| 成人噜噜噜噜| 久久久久久久久网| 国产电影一区二区三区| 永久免费看黄网站| 精品乱码亚洲一区二区不卡| 日本资源在线| 国产精品裸体一区二区三区| 激情婷婷亚洲| 久久人人妻人人人人妻性色av| 欧美日韩裸体免费视频| 久久av少妇| 欧美孕妇性xx| 国产成人一区| 亚洲成人av免费看| 中文字幕一区二区三区不卡在线| 97精品人妻一区二区三区在线 | 性爽视频在线| 日韩精品久久久| 麻豆精品一区二区av白丝在线| 91精品少妇一区二区三区蜜桃臀| 911精品产国品一二三产区| 午夜伦理在线视频| 好吊色欧美一区二区三区四区| 亚洲在线电影| 国产精品久久久免费看| 日韩三区在线观看| 欧美亚洲日本精品| 台湾成人av| 国产成人三级在线观看| 日本学生初尝黑人巨免费视频| 亚洲欧洲偷拍精品| 国产精品**亚洲精品| 日本十八禁视频无遮挡| 久久久.com| 国产成人毛毛毛片| 91精品成人久久| 日韩综合精品| 亚洲少妇中文字幕| 在线日韩一区二区| 在线观看的网站你懂的| 鲁丝片一区二区三区| 久久成人免费网站| 日本在线视频中文字幕| 一区二区三区亚洲| 亚洲天堂av资源在线观看| 欧美激情国产精品日韩| 中文字幕一区视频| 外国精品视频在线观看 | 日韩av观看网址| 一区二区三区毛片免费| 真人bbbbbbbbb毛片| 3d成人h动漫网站入口| √天堂8资源中文在线| 亚洲欧美精品| 97久久超碰国产精品| aaa国产视频| 人人爽久久涩噜噜噜网站| 综合激情网站| 呻吟揉丰满对白91乃国产区|