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

這波操作看麻了!一億行數據,從71s到1.7s的優化之路

大數據 數據分析
當時看到這個成績的瞬間,我人都是麻的,第一個疑問是:我靠,13G 的文件啊?1.5s 內完成了讀取、解析、計算的過程?這不可能啊,光是讀取 13G 大小的文件,也需要一點時間吧?

你好呀,我是歪歪。

春節期間關注到了一個關于 Java 方面的比賽,很有意思。由于是開源的,我把項目拉下來試圖學(白)習(嫖)別人的做題思路,在這期間一度讓我產生了一個自我懷疑:

他們寫的 Java 和我會的 Java 是同一個 Java 嗎?

不能讓我一個人懷疑,所以這篇文章我打算帶你盤一下這個比賽,并且試圖讓你也產生懷疑。

賽題

在 2024 年 1 月 1 日,一個叫做 Gunnar Morling 的帥哥,發了這樣一篇文章:

https://www.morling.dev/blog/one-billion-row-challenge/

文章的標題叫做《The One Billion Row Challenge》,一億行挑戰,簡稱就是 1BRC,挑戰的時間是一月份整個月。

賽題的內容非常簡單,你只需要看懂這個文件就行了:

圖片圖片

文件的每一行記錄的是一個氣象站的溫度值。氣象站和溫度分號分隔,溫度值只會保留一位小數。

參賽者只需要解析這個文件,然后并計算出每個氣象站的最小、最大和平均溫度。按照字典序的格式輸出就行了:

圖片圖片

出題人還配了一個簡圖:

圖片圖片

需求非常明確、簡單,對不對?

為了讓你徹底明白,我再給你舉一個具體的例子。

假設文件中的內容是這樣的:

chengdu;12.0
guangzhou;7.2;
chengdu;6.3
beijing;-3.6;
chengdu;23.0
shanghai;9.8;
chengdu;24.3
beijing;17.8;

那么 chengdu (成都)的最低氣溫是 6.3,最高氣溫是 24.3,平均氣溫是(12.0+6.3+23.0+24.3)/4=16.4,就是這么樸實無華的計算方式。

最終結果輸出的時候,再注意一下字典序就行。

這有啥好挑戰的呢?

難點在于出題人給出的這個文件有 10 億行數據。

在我的垃圾電腦上,光是跑出題人提供的數據生成的腳本,就跑了 20 分鐘:

圖片圖片

跑出來之后文件大小都有接近 13G,記事本打都打不開:

圖片圖片

所以挑戰點就在于“一億行”數據。

具體的一些規則描述和細節補充,都在 github 上放好了:

https://github.com/gunnarmorling/1brc

針對這個挑戰,出題人還提供了一個基線版本:

https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_baseline.java

首先封裝了一個 MeasurementAggregator 對象,里面放的就是要記錄的最小溫度、最大溫度、總溫度和總數。

圖片圖片

整個核心代碼就二三十行,使用了流式編程:

圖片圖片

首先是一行行的讀取文本,接著每一行都按照分號進行拆分,取出對應的氣象站和溫度值。

然后按照氣象站維度進行 groupingBy 聚合,并且計算最大值、最小值和平均值。

在計算平均值的時候,為了避免浮點計算,還特意將溫度乘 10,轉換為 int 類型。

最后用 TreeMap 按字典序輸出各個氣象站的溫度數據。

這個基線版本官方的數據是在跑分環境下,2 分鐘內可以運行完畢。

而在我的電腦上跑了接近 14 分鐘:

很正常,畢竟人家的測評環境配置都是很高的:

Results are determined by running the program on a Hetzner AX161 dedicated server (32 core AMD EPYC? 7502P (Zen2), 128 GB RAM).

參加挑戰的各路大神,最終拿出的 TOP 10 成績是這樣的:

圖片圖片

當時看到這個成績的瞬間,我人都是麻的,第一個疑問是:我靠,13G 的文件啊?1.5s 內完成了讀取、解析、計算的過程?這不可能啊,光是讀取 13G 大小的文件,也需要一點時間吧?

但是需要注意的是,歪師傅有這個想法是走入了一個小誤區,就是我以為這 13G 的文件一次性加載不完成,怎么快速的從硬盤把文件讀取到內存中也是一個考點。

后來發現是我多慮了,人家直接就說了,不用考慮這一點,跑分成績運行的時候,文件直接就在內存中:

圖片圖片

所以,最終的成績中不包含讀取文件的時間。

但是也很牛逼了啊,畢竟有一億條數據。

第一名

我嘗試著看了一下第一名的代碼:

https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_thomaswue.java

過于硬核,實在是看不懂。我只能通過作者寫的一點注釋、方法名稱、代碼提交記錄去嘗試理解他的代碼。

在他的代碼開頭的部分,有這樣的一段描述:

圖片圖片

這是他的破題思路,結合了這些信息之后再去看代碼,稍微好一點,但是我發現他里面還是有非常多的微操、太多針對性的優化導致代碼可讀性較差,雖然他的代碼加上注釋一共也才 400 多行,然而我看還是看不懂。

我隨便截個代碼片段吧:

圖片圖片

問 GPT 這個哥們,他也是能說個大概出來:

圖片圖片

所以我放棄了理解第一名的代碼,開始去看第二名,發現也是非常的晦澀難懂,再到第三名...

最后,我產生了文章開始時的疑問:他們寫的 Java 和我會的 Java 是同一個 Java 嗎?

但是有一說一,雖然我看不懂他們的某些操作,但是會發現他們整體的思路都幾乎是一致。

雖然我沒有看懂第一名的代碼,但是我還是專門列出了這一個小節,給你指個路,有興趣你可以去看看。

另外,獲得第一名的老哥,其實是一個巨佬:

圖片圖片

是 GraalVM 項目的負責人之一:

圖片圖片

巨人肩膀

在官方的 github 項目的最后,有這樣的一個部分:

圖片圖片

其中最后一篇文章,是一個叫做 Marko Topolnik 的老哥寫的。

我看了一下,這個哥們的官方成績是 2.332 秒,榜單第九名:

但是按照他自己的描述,在比賽結束后他還繼續優化了代碼,最終可以跑到  1.7s,排名第四。

在他的文章中詳細的描述了他的挑戰過程和思路。

我就站在巨人的肩膀上,帶大家看看這位大佬從 71s 到 1.7s 的破題之道:

https://questdb.io/blog/billion-row-challenge-step-by-step/

最常規的代碼

首先,他給了一個常規實現的代碼,和基線版本的代碼大同小異,只不過是使用了并行流來處理:

https://github.com/mtopolnik/billion-row-challenge/blob/main/src/Blog1.java

圖片圖片

平時看到流式編程我是有點頭疼的,需要稍微的反應一下,但是在看了前三名的最終代碼后再看這個代碼,我覺得很親切。

根據作者的描述,這段代碼:

  • 使用并行 Java 流,將所有 CPU 核心都用起來了。
  • 也不會陷入任何已知的性能陷阱,比如 Java 正則表達式

在一臺裝有 OpenJDK 21.0.2 的 Hetzner CCX33 機器上,跑完需要的時間為 71 秒。

第 0 版優化:換個好的 JVM

叫做第 0 版優化的原因是作者對于代碼其實啥也沒動,只是換了一個 JVM:

圖片圖片

默認使用 GraalVM 之后,最常規的代碼,運行時間從 71s 到了 66s,相當于白撿了 5s,我問就你香不香。

同時作者還提到一句話:

When we get deeper into optimizing and bring down the runtime to 2-3 seconds, eliminating the JVM startup provides another 150-200ms in relief. That becomes a big deal.

當我們把程序優化到運行時間只需要 2-3 秒的時候,使用 GraalVM,會消除 JVM 的啟動時間,從而提供額外的 150-200ms 的提升。

到那個時候,這個就變得非常重要了。

數據指標很重要

在正式進入優化之前,作者先介紹了他使用到的三個非常重要的工具:

圖片圖片

關于工具我就不過多介紹了,這里單獨提一嘴主要是想表達一個貫穿整個優化過程的中心思想:數據指標很重要。

你只有收集到了當前程序足夠多的運行指標,才能對你進行下一步優化時提供直觀的、優化方向上的指導。

工欲善其事必先利其器,就是這個道理。

第一版優化:并行 I/O 搞起來

通過查看當前代碼對應的火焰圖:https://questdb.io/html/blog/profile-blog1

通過火焰圖以及觀察 GC 情況,作者發現當前耗時的地方注意是這三個地方:

圖片圖片

  1. BufferedReader 將每行文本輸出為字符串
  2. 處理每一行的字符串
  3. 垃圾收集 (GC):使用 VisualGC 可以看到,差不多每秒要 GC 10 次甚至更多。

可以發現 BufferedReader 占用了大量的性能,因為當前讀取文件還是一行行讀取的嘛,性能很差。

于是大多數人意識到的第一件事就是采用并行化 I/O。

所以,我們需要把待處理的文件分塊。分多少塊呢?

有多少個線程就分成多少個塊,每個線程各自處理一個塊,這樣性能就上去了。

文件分塊讀取,大家自然而然的就想到了 mmap 相關的方法。

mmap 可以用 ByteBuffer API 來搞事情,但是使用的索引是 int 類型,所以可映射的大小有 2GB 的限制。

前面說了,在這個挑戰中,光是文件大小就有 13G,所以 2GB 是捉襟見肘的。

但是在 JDK 21 中,支持一個叫做 MemorySegment 的東西,也可以干 mmap  一樣的事情,但是它的索引使用的是 long,相當于沒有內存限制了。

除了使用 MemorySegment 外,還有一些細節的處理,比如找到正確的分割文件的位置、啟動線程、等待線程處理完成等等。

處理這些細節會導致這一版的代碼從最初的 17 行增加到了 120 行。

這是優化后的代碼地址:

https://github.com/mtopolnik/billion-row-challenge/blob/main/src/Blog2.java

在這個賽題下,我們肯定是需要再循環中進行數據的解析和處理的,所以循環就是非常重要的一個點。

我們可以關注一下代碼中的循環部分,這里面有一個小細節:

這個循環是每個線程在按塊讀取文件大小,里面用到了 findByte 方法和 stringAt 方法。

在第一個版本中,我們是用的 BufferedReader 把一行內容以字符串的形式讀進來,然后按照分號分隔,并生成城市和溫度兩個字符串。

這個過程就涉及到三個字符串了。

但是這個哥們的思路是啥?

自定義一個 findByte 方法,先找到分號的位置,然后把下標返回回去。

再用自定義的 stringAt 方法,結合前面找到的下標,直接解析出“城市和溫度”這兩個字符串,減少了整行讀取的內存消耗。

相當于少了一億個字符串,在字符串處理和 GC 方面取得了不錯的表現。

這一波操作下來,處理時間直接從 66s 下降到了 17s:

圖片圖片

然后再看火焰圖:

https://questdb.io/html/blog/profile-blog2-variant1

圖片圖片

可以發現 GC 的時間幾乎消失了。

CPU 現在大部分時間都花在自定義的 stringAt 上。還有相當多的時間花在 Map.computeIfAbsent 方法 、Double.parseDouble 方法和 findByte 方法

其中 Double.parseDouble 方法是解析溫度用的。

作者打算先把這個地方給攻下來。

第二版優化:優化溫度解析方法

在這版優化中,作者直接將溫度解析為整數。

首先,目前的做法是,首先分配一個字符串,然后對其調用 parseDouble() 方法,最后轉換為整數以進行高效的存儲和計算。

但是,其實我們應該直接創建整數出來,沒必要走字符串繞一圈。

同時我們知道,溫度的取值范圍是 [-99.9,99.9],所以針對這個范圍,我們搞個自定義方法就行了:

private int parseTemperature(long semicolonPos) {
    long off = semicolonPos + 1;
    int sign = 1;
    byte b = chunk.get(JAVA_BYTE, off++);
    if (b == '-') {
        sign = -1;
        b = chunk.get(JAVA_BYTE, off++);
    }
    int temp = b - '0';
    b = chunk.get(JAVA_BYTE, off++);
    if (b != '.') {
        temp = 10 * temp + b - '0';
        // we found two integer digits. The next char is definitely '.', skip it:
        off++;
    }
    b = chunk.get(JAVA_BYTE, off);
    temp = 10 * temp + b - '0';
    return sign * temp;
}

這波操作下來,處理時間又減少了 6s,來到了 11s:

圖片圖片

再看對應火焰圖:

https://questdb.io/html/blog/profile-blog2-variant2

圖片圖片

溫度解析部分的耗時占比從 21.43% 降低到 6%,說明是一次正確的優化。

接下來,可以再搞一搞 stringAt 方法了。

第三版優化:自定義哈希表

首先,要優化 stringAt 方法,我們得知道它是干啥的。

我們看一眼代碼:

圖片圖片

在經歷了上一波優化之后,stringAt 目前在代碼中的唯一作用就是為了獲取氣象站的名稱。

而獲取到這個名稱的唯一目的是看看當前的 HashMap 中有沒有這個氣象站的數據,如果沒有就新建一個 StationStats 對象,如果有就把之前的 StationStats 對象拿出來進行數據維護。

此外,在賽題中還有這樣的一個信息,雖然有一億行數據,但是只有 413 個氣象站:

圖片圖片

既然 key 的大小是可控的,那基于這個條件,作者想了一個什么樣的騷操作呢?

他直接不用 HashMap 了,自定義了一個哈希表,長這樣的:

https://github.com/mtopolnik/billion-row-challenge/blob/main/src/Blog3.java

圖片圖片

主要看一下代碼中的 findAcc 方法,你就能明白它是干啥的了:

圖片圖片

通過 hash 方法計算出指定字符串,即氣象站名稱的 hash 值之后,從自定義的 hashtable 中取出該位置的數據。

首先標號為 ① 的地方,如果沒有取到數據,則說明沒有這個氣象站的數據,新建一個放好,返回就完事。

如果取到了數據,來到標號為 ② 的地方,看看取到的數據和當前要放的數據對應的氣象站名稱是不是一樣的。

如果是則說明已經有了,取出來,然后返回。

如果不是,說明啥情況?

說明 hash 沖突了,來到標號為 ③ 的地方進行下標加一的動作。

然后再次進行循環。

來,你告訴我,這是什么手法?

這不就是開放尋址來解決 hash 沖突嗎?

所以 findAcc 方法,就可以替代 computeIfAbsent 方法。

通過自定義的 StatsAcc 哈希表來代替原生的 HashMap。

而且前面說了,key 的大小是可控的,如果自定義 hash 表的初始化大小控制的合適,那么整個 hash 沖突的情況也不會非常嚴重。

這一波組合拳下來,運行時間來到了 6.6s,火焰圖變成了這樣:

https://questdb.io/html/blog/profile-blog3

圖片圖片

大量的時間花在了前面分析的 findAcc 方法上。

同時作者提到了這樣一句話:

圖片圖片

同樣的代碼,如果放到 OpenJDK 上跑需要運行 9.6s,比 GraalVM 慢了 3.3s。

我滴個乖乖,這就是一個 45% 的性能提升啊。

第四版優化:使用 Unsafe 和 SWAR

在這一版優化開始之前,作者先寫了這樣一段話:

圖片圖片

大概意思就是說,到目前為止,我們用到的都是常規且有效的解決方案,并且是 Java 標準、安全的用法。

即使止步于此也能學到很多優化技巧,可以在實際的項目中進行使用。

如果你繼續往下探索,那么:

Readability and maintainability also take a big hit, while providing diminishing returns in performance. But, a challenge is a challenge, and the contestants pressed on without looking back!
可讀性和可維護性也會受到重創,同時性能的收益會遞減。但是,挑戰就是挑戰,參賽者們繼續努力,沒有回頭!

簡單來說,作者的意思就是打個預防針:接下來就要開始上強度了。

所以,在這個版本中,作者應用一些排名靠前的選上都在用的方案:

  • 使用 sun.misc.Unsafe 而不是 MemorySegment,來避免邊界檢查
  • 避免重新讀取相同的輸入字節:重復使用加載的值進行哈希和分號搜索
  • 每次處理 8 個字節的數據,使用 SWAR 技術找到分號分隔符。
  • 使用 merykitty 老哥提供的牛逼的 SWAR(SIMD Within A Register)代碼解析溫度。

這是這一版的代碼:https://github.com/mtopolnik/billion-row-challenge/blob/main/src/Blog4.java

比如其中關于循環處理數據的部分,看起來就很之前很不一樣了:

圖片圖片

然后你再看里面 semicolonMatchBits、nameLen、maskWord、dotPos、parseTemperature 這些方法的調用,直接就是一個懵逼的狀態,看著頭都大了:

圖片圖片

但是你仔細看,你會發現這幾個方法是作者從其他人那邊學來的:

圖片圖片

比如這個叫做 merykitty 的老哥,提供了解析溫度的代碼,雖然作者加入了大量的注釋說明,但是我也只是大概就看懂了不到三層吧。

這里面大量的使用了位運算的技巧,同時你仔細看:幾乎沒有 if 判斷的存在。這是重點,用直接的位運算替換了分支指令,從而減少了分支預測錯誤的成本。

此外,還有很多我第一次見、叫不上名字的奇技淫巧。

通過這一波“我看不懂,但是我大受震撼”的操作搞下來,時間降低到了 2.4s:

圖片圖片

第五版優化:統計學用起來

現在,我們的火焰圖變成了這樣:https://questdb.io/html/blog/profile-blog4

圖片圖片

耗時主要還是在于 findAcc 方法:

圖片圖片

而 findAcc 方法的耗時在于 nameEquals 方法,判斷當前氣象站名稱是否出現過:

圖片

圖片圖片

但是這個方法里面有個 if 判斷,以字節為單位比較兩個字符串的內容,每次比較 8 個字節。

首先,它通過循環逐步比較兩個字符串中的對應字節。在每次迭代中,它使用 getLong 方法從輸入字符串中獲取一個 64 位的長整型值,并與另一個字符串中的相應位置進行比較。如果發現不相等的字節,則返回 false,表示兩個字符串不相等。

如果循環結束后沒有發現不相等的字節,它會繼續檢查是否已經比較了輸入字符串的所有字節,或者最后一個輸入字符串的字節與相應位置的字符串字節相等,那么表示兩個字符串相等,則返回 true。

那么問題就來了?

如果氣象站名稱長度全都是小于 8 個字節,會出現啥情況?

假設有這樣的一個前提條件,是不是我們就不用在 for 循環中進行 if 判斷了,直接一把就比較完成了?

很可惜,沒有這樣一個提前條件。

但是,如果在數據集中,氣象站名稱長度絕大部分都小于 8 個字節那是不是就可以單獨處理一下?

那到底數據分布是怎么樣的呢?

這個問題問題出去的一瞬間,統計學啪的一下就站出來了:這個老子在行,我算算。

所以,作者寫了一個程序來統計分析數據集中氣象站名稱的長度:https://github.com/mtopolnik/billion-row-challenge/blob/main/src/Statistics.java

基于程序運行結果,最終的結論如下:

圖片圖片

圖片圖片

通過分析作者發現,賽題的數據集中氣象站名稱長度幾乎均勻分布在 8 字節以上和 8 字節以下。

運行 Statistics.branchPrediction 方法,當條件是 nameLen > 8 時導致了 50% 的分支預測失敗。

也就是說,一億數據中有一半的數據,都是小于 8 字節的,都是不用特意進行 if 判斷的。

但如果將條件更改為 nameLen > 16,那么預測失敗率將降至 2.5%。

根據這一發現,很明顯,如果要進一步優化代碼,就需要編寫一些特定的代碼來避免在 nameLen > 8 上使用任何 if 判斷,直接使用 nameLen > 16 就行。

這是這一版的最終代碼,可讀性越來越差了:https://github.com/mtopolnik/billion-row-challenge/blob/main/src/Blog5.java

但是最終的成績是 1.8s:

圖片圖片

哦,對了,如果你對于分支預測技術不太清楚,那你可能看得比較懵。

但是分支預測,在性能挑戰中,特別是最后大家比分都咬的非常緊的情況下,每次都是屢立奇功,戰功赫赫,屬于高手間過招殺手锏級別的優化手段。

繼續優化

再后面作者還有這兩個部分。

消除啟動/清理成本:

圖片圖片

使用更小的文件分塊和工作竊取機制:

圖片圖片

這后面就完全是基于這個賽題進行定制化的優化,可移植性不強了,作者就沒有進行詳細描述,再加上一個我也是沒怎么看明白,就不展開講了。

反正這兩個組合拳下來,又搞了 0.1s 的時間下來,最終的成績為 1.7s:

圖片圖片

我實在是學不動了,有興趣的同學可以自己去看看原文的對應部分。

責任編輯:武曉燕 來源: why技術
相關推薦

2024-09-29 08:21:06

2022-06-30 19:40:36

查詢接口索引優化

2025-02-14 09:30:42

2023-05-14 17:16:22

分類樹SpringBoot

2019-06-20 11:20:25

sql優化數據庫

2024-09-26 10:29:56

數據中臺數據飛輪

2023-12-25 08:24:03

雙異步數據庫Excel

2024-01-15 07:05:50

開發大事務數據庫

2021-09-10 08:31:36

技術Prometheus監控

2025-11-11 04:00:00

2021-04-27 16:04:26

人工智能Python 語音識別

2022-09-27 08:40:44

慢查詢MySQL定位優化

2024-10-28 07:00:00

分頁查詢優化索引數據歸檔

2025-06-16 01:00:00

2022-06-29 09:43:14

SQL優化數據庫

2022-07-05 10:50:31

數據庫查詢實戰

2022-09-19 08:41:02

數據查詢分離

2024-05-28 08:47:52

2023-09-27 08:21:00

查詢分離數據API

2023-11-29 08:10:52

類型sql語句
點贊
收藏

51CTO技術棧公眾號

91在线视频九色| 亚洲精品中文字幕女同| 中文字幕中文字幕99| av官网在线观看| 99精品欧美| 色悠悠国产精品| 在线观看一区二区三区四区| 欧美大片免费| 一区二区三区中文字幕在线观看| 精品视频第一区| 亚洲综合网av| 国产亚洲网站| 欧美麻豆久久久久久中文| 人妻丰满熟妇aⅴ无码| 91成人小视频| 一本色道久久综合亚洲91| 一区二区三区视频| 你懂的视频在线免费| 经典一区二区三区| 热久久这里只有精品| avove在线播放| 国产欧美久久一区二区三区| 欧美大片拔萝卜| 久久综合伊人77777麻豆最新章节| 日本伦理一区二区| 国产精品色呦呦| 久久波多野结衣| av天堂一区二区三区| 日韩va欧美va亚洲va久久| 欧美国产日本在线| 中文字幕无码日韩专区免费| 伊人精品一区| 亚洲国产小视频| 中文字幕第22页| 91p九色成人| 欧美日韩一区二区免费视频| 台湾无码一区二区| 色多多视频在线观看| 久久影视一区二区| 国产九区一区在线| 亚洲乱码精品久久久久..| 麻豆国产精品官网| 国产成人精品免费视频| 日本在线观看中文字幕| 国语对白精品一区二区| 久久亚洲私人国产精品va| 国产传媒在线看| 欧美亚洲国产精品久久| 亚洲免费影视第一页| 少妇一级淫片免费放播放| jazzjazz国产精品久久| 欧美一区午夜精品| www.欧美激情.com| 涩涩涩久久久成人精品 | 久久精品国产亚洲AV无码男同| 91亚洲国产高清| 色老头一区二区三区| 免费看91的网站| 成人vr资源| 中文字幕精品网| 国产午夜精品久久久久久久久| 精品理论电影在线| 色哟哟亚洲精品一区二区| 国产一区在线观看免费| 欧美a级成人淫片免费看| 日韩视频在线一区| 欧美另类videoxo高潮| 中文字幕日韩一区二区不卡| 久久亚洲影音av资源网| 激情小说中文字幕| 亚洲激情亚洲| 日韩免费不卡av| 国产精品sm调教免费专区| 免费观看在线综合| 亚洲资源在线看| 国产综合视频在线| www精品美女久久久tv| 污视频在线免费观看一区二区三区| 触手亚洲一区二区三区| 国产精品盗摄一区二区三区| 亚洲色图都市激情| 欧美办公室脚交xxxx| 日韩欧美国产一区二区| 超碰在线97免费| 国产视频网站一区二区三区| 亚洲第一色在线| 实拍女处破www免费看| 日本黄色精品| 久久久久一本一区二区青青蜜月| 国产又黄又爽又色| 麻豆中文一区二区| 国产精品theporn88| 暖暖视频在线免费观看| 自拍偷拍国产精品| 成人免费毛片网| 日韩一区中文| 日韩的一区二区| 国产视频123区| 国产精品videosex极品| 国产精品99久久久久久久久久久久 | 亚洲精品久久久蜜桃动漫| 91麻豆6部合集magnet| 亚洲精品欧美精品| brazzers在线观看| 欧美日韩亚洲综合在线 欧美亚洲特黄一级 | japanese色国产在线看视频| 一本大道av一区二区在线播放| 污视频网址在线观看| 欧美电影在线观看完整版| 最新国产成人av网站网址麻豆| 欧美成欧美va| 日本sm残虐另类| 国产一区二区精品免费| 久久五月精品| 欧美专区日韩专区| 性农村xxxxx小树林| 99精品美女| 人体精品一二三区| 女人18毛片水真多18精品| 亚洲欧洲精品一区二区精品久久久 | 亚洲一区二区三区在线视频| 日本1级在线| 亚洲一区二区欧美| 日韩在线一区视频| 久操国产精品| 97超级碰在线看视频免费在线看 | 精品自拍偷拍视频| 日韩中文欧美在线| 精品国产乱码久久久久久88av | 亚洲人成伊人成综合网小说| 国产又黄又猛视频| 欧美性生活一级片| 久久久亚洲网站| 99国产精品久久久久99打野战| 久久久久国产一区二区三区四区| 国产一区二区四区| 欧美a在线观看| xxxx性欧美| 欧美高清69hd| 欧美激情在线一区二区三区| 成人免费观看视频在线观看| 国产精品videossex| 欧美成人中文字幕| 国产免费av观看| 中文字幕一区二区三区av| 三级在线视频观看| 不卡一区2区| 国产成人精品最新| 国产高清av在线| 在线看国产一区二区| 精品成人av一区二区三区| 亚洲一区日韩| 蜜桃91精品入口| 亚洲优女在线| 亚洲男人天堂古典| 国产污视频网站| 国产欧美一区二区三区沐欲| 成人在线免费播放视频| 亚洲国产精品嫩草影院久久av| 97在线观看免费高清| 天堂中文在线观看视频| 精品久久久久久国产| 国产精品一级黄片| 久热国产精品| 视频一区二区综合| 青青久久精品| 美女视频久久黄| www.99视频| 五月综合激情婷婷六月色窝| av直播在线观看| 日韩成人免费在线| 欧美性受黑人性爽| 香蕉成人app| 午夜美女久久久久爽久久| 蜜桃成人在线视频| 91麻豆精品国产91久久久久久| 538精品在线视频| 成人av动漫在线| 日本黄网站免费| 999国产精品999久久久久久| 亚洲已满18点击进入在线看片| 日本中文字幕中出在线| 亚洲免费电影一区| 国产一区二区在线视频观看| 亚洲高清三级视频| 人妻互换一区二区激情偷拍| 国产激情一区二区三区四区| 欧美色图色综合| 久久亚洲精品中文字幕蜜潮电影| 96久久精品| 免费欧美电影| 欧美老肥婆性猛交视频| 亚洲av成人精品一区二区三区在线播放| 在线观看一区二区视频| 福利所第一导航| 久久人人97超碰com| 91精产国品一二三产区别沈先生| 亚洲第一毛片| 亚洲一区二区三区精品动漫| 电影一区二区在线观看| 国产精品中文字幕久久久| 欧洲一区二区三区| 伊人成人开心激情综合网| 亚洲成人一级片| 欧美性生活一区| 国产无码精品在线观看| 国产精品久久久久四虎| 亚洲av无码一区二区三区观看| 精品一区二区三区的国产在线播放| 成人免费视频91| 91精品一区国产高清在线gif| 久久er99热精品一区二区三区| 国产精品亚洲欧美日韩一区在线| 日本精品中文字幕| 色www永久免费视频首页在线| 一本色道久久综合狠狠躁篇怎么玩 | 四虎影视国产在线视频| 在线观看亚洲区| 五月激情婷婷网| 日韩一区二区三区视频在线| 中国一级特黄视频| 欧美日韩在线观看视频| 精品国产视频在线观看| 欧美国产精品一区二区三区| 日韩免费高清一区二区| 国产成人超碰人人澡人人澡| 欧美丝袜在线观看| 蜜臀91精品一区二区三区| 免费高清在线观看免费| 伊人激情综合| 国产女教师bbwbbwbbw| 欧美+日本+国产+在线a∨观看| 香蕉久久免费影视| 狠狠色狠狠色综合婷婷tag| 激情伦成人综合小说| 亚洲午夜免费| 91在线在线观看| 国产精品一区二区美女视频免费看| 国产精品嫩草影院久久久| 亚洲欧洲美洲av| 欧美在线视频观看免费网站| 啊啊啊久久久| 2020久久国产精品| 在线观看v片| 欧美孕妇毛茸茸xxxx| 手机在线观看av网站| 91黑丝高跟在线| 第一福利在线视频| 91国内免费在线视频| 五月天国产在线| 欧美在线亚洲一区| 欧美人与性动交xxⅹxx| 日韩美女视频中文字幕| 日韩欧美看国产| 国产精品极品美女粉嫩高清在线| 2019年精品视频自拍| 国产精品网站入口| 香蕉久久久久久| 666精品在线| а√中文在线天堂精品| 国产伦精品一区二区三区| 林ゆな中文字幕一区二区| 精品久久精品久久| 综合国产视频| 日本一区视频在线| 天天精品视频| 欧美做暖暖视频| 日韩午夜免费| 午夜免费一区二区| 激情综合网最新| 在线中文字日产幕| 久久久久久免费毛片精品| 91动漫免费网站| 亚洲精品写真福利| 日韩精品一区二区av| 色噜噜狠狠成人中文综合| 这里只有精品9| 精品蜜桃在线看| 欧美成人片在线| 久久亚洲影音av资源网| 黄毛片在线观看| 国产综合色香蕉精品| 成人精品毛片| 色阁综合av| 黄色成人在线网站| 亚洲一区二区蜜桃| 国产不卡视频在线播放| 亚洲最大成人网站| 综合久久久久综合| 西西44rtwww国产精品| 欧美日韩国产影片| 天天操天天干天天干| 日韩在线欧美在线国产在线| 国模私拍视频在线播放| 国产精品久久久久久av福利| 视频在线亚洲| 色吧亚洲视频| 99精品国产在热久久| 91插插插影院| www欧美成人18+| 毛片a片免费观看| 欧美亚洲高清一区二区三区不卡| 成人毛片在线精品国产| 少妇精69xxtheporn| 国产亚洲成av人片在线观看 | 中文字字幕在线观看| 337p日本欧洲亚洲大胆精品| 1区2区3区在线观看| 91精品国产91久久久久| av在线亚洲一区| 日本一区二区三区免费看| 国产一区亚洲| 国产精品自在自线| 久久久久久久久岛国免费| 日本熟妇色xxxxx日本免费看| 4438x成人网最大色成网站| 久久电影视频| 26uuu另类亚洲欧美日本一| 免费一区二区三区在线视频| 亚洲一区二区三区精品在线观看 | 婷婷综合成人| 日韩激情视频一区二区| 精品一区二区三区香蕉蜜桃| 亚洲精品成人av久久| 欧美日韩美女在线观看| 亚洲国产成人在线观看| 日韩在线播放视频| 亚洲电影有码| 日本一区视频在线观看免费| 性娇小13――14欧美| 99re久久精品国产| 亚洲高清中文字幕| 黄色av一区二区三区| 欧美美最猛性xxxxxx| 国产亚洲字幕| 中文字幕中文字幕在线中一区高清 | 国产精品九色蝌蚪自拍| 免费看av在线| 在线a欧美视频| 欧美日韩精品免费观看视完整| 久久精品日产第一区二区三区精品版| 亚洲性感美女99在线| 日韩黄色一区二区| 亚洲国产视频一区二区| 国产高清视频免费| 久久精品欧美视频| 成人豆花视频| 91精品国产毛片武则天| 国产精品一二三在| 久久精品99久久久久久| 精品少妇一区二区三区日产乱码 | 2019中文字幕免费视频| 久草精品视频| 丝袜老师办公室里做好紧好爽| 91麻豆福利精品推荐| 亚洲欧美另类在线视频| 亚洲欧美日韩中文在线| 台湾佬成人网| 亚洲精品日韩成人| 国模无码大尺度一区二区三区| 91麻豆免费视频网站| 亚洲精品在线电影| 在线视频超级| 日韩高清av| 精品无人区卡一卡二卡三乱码免费卡| 五月天av网站| 精品国产一区二区三区久久影院| 国产传媒av在线| 日韩av不卡在线播放| 精品一区二区三区的国产在线播放| 全程偷拍露脸中年夫妇| 亚洲国产日韩一区| 播放一区二区| 女女同性女同一区二区三区按摩| 国产精品1区二区.| 国产精品美女久久久久av爽| 国产午夜精品视频免费不卡69堂| 久久久精品一区二区毛片免费看| 久久久久久久久网| 91在线精品一区二区三区| 中文字幕在线观看精品| 欧美成人精品在线视频| 欧美91在线| 亚洲免费av一区| 精品美女永久免费视频| 草碰在线视频| 国产精品一区二区三区不卡 | 先锋资源久久| 色综合久久五月| 欧美日韩一区二区三区不卡| 秋霞在线视频| 亚洲国产一区二区精品视频 | 不卡视频一区二区三区| 亚洲欧美日韩国产综合精品二区| 男人天堂资源网| 日韩精品视频在线播放| 成人污污视频| 人妻熟女一二三区夜夜爱| 亚洲另类中文字| 成人影视在线播放|