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

Kotlin 云端差分緩存技術

移動開發
本篇文章我們來具體闡述下 BuildInfra 團隊自研的解決方案 - Kotlin 云端差分方案的原理和技術實現。

本文由字節跳動 Buildinfra 團隊出品。

在我們的工程上線 Monorepo 全源碼后,Kotlin 編譯成了整個編譯中最耗時的步驟,全源碼過程中大量的 BuildCache Miss 導致我們的編譯數據落后原來多倉二進制時代很多,且業界沒有相關的解決方案。本篇文章我們來具體闡述下 BuildInfra 團隊自研的解決方案 - Kotlin 云端差分方案的原理和技術實現。

一、Monorepo 中的噩夢

在 2022-2023 年,我們的頭部業務開始慢慢地從原來的多倉二進制模式,遷移到全新 Monorepo 方案。

在多倉二進制時代,由于 Maven 的加持,大部分時候我們的都不需要直接編譯代碼,而是復用 Maven 的『緩存』。

在工程進入 Monorepo 時代之后,我們花了大量的精力建設 BuildCache,來試圖抹平 Monorepo 與二進制的構建速度差異,但遺憾的是,盡管我們已經做了很多的努力,但由于 Gradle 脆弱的 BuildCache 設計,導致很多時候改動一行代碼就會全局 miss,不得不重新編譯一遍所有的源碼。這很不環保(

  • 本地編譯:首次編譯/更新代碼/切分支等場景,非常容易觸發整個工程的重新編譯,動輒 20min+。
  • CI 編譯:從原來多倉二進制時代的 25min 劣化到了 40min+

并且,90 分位的構建劣化更是飆升到不可控的地步,它直接決定了本地開發、CI 合碼的體驗。

在可預見的將來,隨著代碼的快速增長、更多子倉的合入,僅靠 BuildCache 已經完全無法支撐大型 Monorepo 工程的開發。

二、分析

如果想優化 Kotlin 的全量編譯,如果從計算機通用優化角度來看,不外乎以下幾種方案:

  • 更高效的實現
  • 并發
  • 緩存

更高效的實現:語言編譯是一個龐大且復雜的系統,涉及前后端編譯,目前針對前后端編譯流程進行優化實施起來難度較大,是一個長期且艱巨的任務。但它并不和其他優化方案有沖突。

并發:如果是相互之間沒有復雜依賴關系的多 Module,那么 Gradle 已經保證了模塊之間的并行度;只要你的項目依賴足夠 flat,那么就可以充分利用計算機并發資源,在 CI 場景會獲得非常大的提升,所以從工程角度可以進行依賴的優化來提升并行度。但這也不是一個通用的方案,非常依賴于業務方的改造。

緩存:Kotlin 目前使用的是 Gradle 的緩存,眾所周知,Gradle 為了保證正確性,有著一套極其嚴格的 Cache key 生成策略,很多「可能」不影響 kotlin 編譯正確性的變化(比如編譯插件的 classpath)卻會讓整個 BuildCache 崩盤,全部 Task 全部 Cache Miss。

在 kotlin 中,不僅是 classpath 這些變動會導致 cache miss,kotlin 的 sourceset(即源碼)也會作為 cache key 的計算輸入。這意味著,只要代碼里有一個字符不一樣,就會導致 cache miss,整個模塊就需要重新編譯,那么這塊是否有優化空間呢?

綜合來看,從緩存角度入手,可以以比較低成本來實現較大的收益。

為此,我們提出了一套創新性的方案:

通過云端模糊匹配緩存來將全量編譯轉化為增量編譯,來減少全量編譯的耗時。

三、核心原理

我們通過改造 Kotlin Gradle Plugin 入手,當 Kotlin Task 由于各種原因不能命中 Build Cache 時,就會 fallback 到我們的『Kotlin 差分編譯系統』。通過云端模糊匹配緩存來將全量編譯轉化為增量編譯,來將本來動輒 10min+ 的全量編譯轉化成 10s 內的增量編譯。

云端緩存模糊匹配

常規編譯構建緩存方案如 Gradle Build Cache 采用的是 kv 一對一匹配。

對于 Kotlin 來說,即通過對源碼文件、依賴 Jar 包,編譯參數等信息算出一個緩存 key 之后,唯一匹配出一個緩存。當匹配到緩存后,緩存包的內容就是 Kotlin 的最終產物,然后就可以跳過 Kotlin Task,直接進入下一步。

由于精確匹配需要達成的條件較多,比如只要修改了一個 .kt文件,就無法匹配到緩存

因此可以考慮實現一套模糊匹配的機制:

  • 先根據一些必要參數匹配一組可能符合要求的緩存
  • 然后從這一組緩存中尋找與當前場景最接近的緩存包來進行使用

全量轉增量

最接近的緩存包,也只是最接近的,是不能直接拿來用的。

那我們是不是可以將這個緩存包對應的源碼與當前源碼做 diff,然后將全量轉增量呢?

比如,某個模塊有 A.kt,B.kt,我們基于某個 Commit 打出來了一個云端緩存包。

有一天,我們新增了一個 C.kt,改動了 B.kt,這時候,我們找到之前打出來的緩存包,對他們對應的源碼做一次 diff,那么我們可以得到這組變動:

[
   changed: ["B.kt"],
   added: ["C.kt"]
]

我們只需要將這個 Diff 輸入給 kotlin 編譯器,kotlin 就會自動幫我們完成耗時較低的增量編譯

基于 #1#2 的兩個核心原理,我們設計了一套『Kotlin 差分編譯系統』,整體架構圖如下,有四個重要的角色:

  • 客戶端:Hook Kotlin Compiler,負責將全量編譯轉為增量編譯。
  • 服務端:基于客戶端的請求匹配最佳緩存。
  • 種子節點:基于 develop 分支,定時打包,上傳緩存。
  • 分布式緩存:我們內部使用的緩存系統,主要通過 K-V 的形式來存儲我們的緩存包。

圖片圖片

四、方案詳解

客戶端方案

客戶端的核心邏輯:對 kotlin 編譯流程進行 hook,構造/加載緩存包,將全量編譯轉換為增量編譯,轉換的關鍵在于增量編譯與全量編譯的差異部分:

  1. 增量編譯環境中有上次編譯好的編譯產物、增量追蹤文件(符號引用關系,abi 信息等)。
  2. 增量編譯相比于上次編譯有哪些輸入文件產生了修改的文件 diff 信息。

圖片圖片

緩存包內容

為了能夠在全量編譯時順利還原出一個正確的增量編譯現場,要求加載的緩存包中應該包含的內容有:

  1. 編譯產物 (減少不必要的源文件重新編譯耗時)
  2. metadata 包括 kt 、java、layout 文件等 源文件信息,包括這些文件在項目中的相對路徑以及 hash 值,在還原編譯現場時,根據這些內容還原為源文件的 diff 信息 ( add, remove ,modify)
  3. 編譯器信息:編譯器參數,編譯器 JAR 包的 hash 信息等。
  4. 增量中間產物:涉及到一系列追蹤文件,這些文件包含了kotlin 編譯器在增量編譯時 用來計算 dirty file (需要重新編譯的源文件)的關鍵信息,包括符號引用關系、abi 信息、源文件與編譯產物的對應關系等。

圖片圖片

緩存匹配

如前文中的『核心原理』章節所描述,我們采取以下方案來進行緩存的匹配。

  • 先根據一些精準參數匹配一組可能符合要求的緩存
  • 然后從這一組緩存中尋找與當前場景最接近的緩存包來進行使用

其中以下參數會參與精確參數(unique_hash)的計算

  • Kotlin 版本
  • Kotlin Compiler Plugin (KCP)
  • Kotlin 編譯器參數

我們通過將這些參數組合到一起組成一個 hash 值:unique_hash。

在之后的流程中,會使用 unique_hash 來篩選出一組緩存。我們再通過服務端的策略來篩選出最佳的緩存。

圖片圖片

編譯流程 hook

拿到了緩存包后,我們就可以進行緩存包的復用了。但是我們在上一個流程中匹配到的僅僅是最優緩存,但是這個緩存和我們當前的包還存在 diff,比如代碼、模塊依賴信息 等的差異。

我們需要計算出拉到的緩存包和當前編譯的 diff,然后將 diff 傳給 kotlin 編譯器,并將全量編譯轉成增量編譯。

為了能夠實現增量編譯的轉換,需要在編譯流程的三個階段進行 hook

  1. 編譯前執行前解析模塊依賴信息。
  2. 在提交編譯參數到編譯器執行前,匹配、下載、校驗、加載緩存包,將全量編譯參數轉換為增量編譯參數。
  3. 編譯完成后構造并上傳緩存包。

圖片圖片

其中,最核心的 Hook 點在于:將全量編譯轉化成增量編譯。

internal fun CallCompilerAsyncOpt.callCompilerAsyncOpt(
    ....
) {
    val icEnv = IncrementalCompilationEnvironment(
            changedFiles,
            classpathChanges,
            workingDir ,
            ...
        )
    val hookedIcEnv = hook(icEnv)

    val environment = GradleCompilerEnvironment(
        incrementalCompilationEnvironment = hookedIcEnv,
        outputFiles,...
    )
    optRunJvmCompilerAsync(..., source, args, environment , ... )
}

我們會 Hook KotlinCompile 中的 callCompilerAsync 方法,將原來的全量 Env 轉換成增量 Env。增量的 InputChanges 來源于我們的緩存包和編譯的 diff (源碼、依賴的變更等)。

而這個關鍵的全量轉增量 Hook 步驟為:

  1. 匹配下載緩存:為了能夠匹配到最接近的緩存包,實現最佳增量編譯效率,需要對這些參數進行比較:
  1. 根據 metadata 中 java/kotlin/layout 文件的 hash 比較源碼文件的 diff (其中包括 layout xml 是因為 KAE 會根據 layout 進行 kotlin 代碼插樁)
  2. 利用 kotlin 1.7+ 的 classpath-snapshot.bin 計算依賴模塊依賴信息的 abi diff
  1. 校驗加載緩存: 基于緩存包中的 metadata ,結合編譯產物、編譯中間產物等,將對應信息加載到對應位置。
  2. 構造增量編譯參數: 將加載的緩存包中的相對路徑轉換為絕對路徑,用絕對路徑的 diff 信息等構造出可用的增量 Env , 并提交給 Kotlin Compiler

預期之外的問題

理論上來講,如果 kotlin 編譯器是能保證增量編譯是完全不出錯的,那么我們的方案肯定不會引入穩定性的問題。

但是這樣的期待或許過高。我們的方案是基于 Kotlin 1.7.21 進行開發的,kotlin 在 1.7+ 引入了新的 kotlin 增量編譯方案,還在一個相對不穩定的階段。實際上,我們也在上線前后遇到了各種奇怪的問題。經過長時間的 debug 和翻閱源碼后得到了解決,目前在抖音項目上已經趨于穩定。

跨端緩存復用問題

問題表現為:OSX 復用 ci 種子節點打包的緩存時,對于部分刪除的源代碼文件,并沒有將其對應的編譯產物刪除

通過一系列的排查發現,該問題是 Kotlin Compiler 自身的 bug ,且在高版本進行了修復,bug 來源于 kotlin 的增量編譯中間產物中,用于追蹤源碼文件與編譯產物關系的信息異常,在涉及到大小寫敏感不一致的系統時,無法正常刪除編譯產物。

解決方案: 對高版本的修復 commit 進行了 cherry-pick

kotlin 修復 https://github.com/JetBrains/kotlin/commit/be71d8841ebc22c79bb6b4bc6f3ad93c147ba9c0

大小寫敏感問題

由于 OSX 不是一個大小寫敏感的操作系統,這意味著,在一個文件夾中,不能同時存在去掉大小寫后字符一樣的兩個文件。比如:

圖片圖片

但是這個行為在 Linux 系統上是允許的。

我們的遇到的問題是,項目中不同文件夾中有兩個包名叫 com.xxx.legoImp ,一個叫com.xxx.legoimp 。這兩個包名會在 Linux 種子節點上進行 Jar 包壓縮,在 mac 上進行解壓 ,由于 Linux 不是 Case Sensitive 的系統,所以 jar 包中,他倆會同時存在,但是在 mac 上解壓時,mac 會自動合并了這兩個包,并且轉換成小寫。這樣就會在運行時崩潰,找不到這個包名。

解決方案:我們提供了一個類似的包名大小寫檢測,幫助業務提前暴露問題,并進行代碼的整改。

方案性能極致優化

加速緩存解壓

在最初的緩存包壓縮中,采用的是 Java ZipFile 中默認的壓縮算法,上線后發現有較多模塊的緩存解壓時間較長,后續參考了Gradle build-cache 方案,將壓縮算法修改為 lz4,大大降低了解壓縮的時間。

降低緩存淘汰率

在本方案中,緩存遠端存儲在我們的分布式緩存服務中,由于分布式緩存空間有限(2TB),超過緩存空間時會根據 LRU 淘汰最近未使用的緩存,這樣就會導致緩存命中率下降,而由于在抖音項目中,生產緩存的種子節點會在每個 MR 合入后進行緩存打包,每次全量打包緩存時,緩存包約1GB+ , 為了減少不必要的緩存上傳,采取了兩個方案:

  1. 與 build-cache 進行關聯,如果種子節點打包時命中 build-cache ,將 kotlin 緩存與 build-cache 進行關聯,而不是重復上 kotlin 緩存
  2. 計算緩存包內容 hash ,如果存在相同的緩存包,將他們關聯到一起,而不是重復上傳緩存。

服務端策略

區別于傳統的 Build Cache 服務端的簡單 K-V 存儲,我們的服務端需要幫助客戶端去存儲產物、匹配產物、選擇最佳產物。客戶端和服務端的通信時序圖如下:

圖片圖片

其中,服務端最核心的邏輯在于匹配最佳產物

每一個 unique hash 都會對應一組產物,我們要從這一組產物里找到一個最優解。

最優解的定義是:這個產物離我們當前的編譯較為接近。我們為這個『接近』,定義了一個記分制度。

data class Diff(val added: List<String>, 
                val removed: List<String>,
                val modified: List<String>)
fun diffScore(): Int {
    return this.diff.removed.size * 3 +
            this.diff.modified.size * 2 +
            this.diff.added.size
}

每個產物和當前編譯都會產生一個 diffdiff 里有 addedremovedmodified

我們定義一個函數 diffScoreremove 記三分,modified 記兩分,added 記一分。

之所以按照這樣的系數,是因為 removed 大概率會引起很多底層依賴的重新編譯,所以我們需要盡可能地減少 removed 的代碼,added 的代碼一般不會引起其它代碼重新編譯,所以我們可以記為一分。modified 介于兩者之間,記兩分。

那么,我們的核心的邏輯就變成了:從一組緩存里,找到 diffScore 最少的產物

但是因為我們的 unique hash 對應的 hash 生成并不復雜,一般來說,除非是升級 kotlin 版本,其它情況這個 unique hash 基本不會變,所以這個緩存的量可能會很大,我們不可能實現找到所有的緩存,并且進行 diffScore 的比較。我們需要篩選出一定范圍內的緩存。

首先,我們的所有的產物生成都是在主干分支上。

那么意味著,對于 feature 分支,與其代碼最接近的 commit 應該是圖中的 base commit

圖片圖片

因為成本的原因,種子任務可能并不會在主干分支的每個節點都打緩存包,可能是定時打包。那么意味著不是所有的 merge commit 都有緩存包。

所以,我們找到這個 commit 的前后一天時間內的 commit。并和表中的所有產物進行取交集

圖片圖片

最后得到所有黃色的點。(黃色的點是打了緩存包的 merge 節點)

我們將所有黃色的點對應的 MetaData 與當前 commit 的 MetaData 進行 diff。

取一個 diffScore 最少的節點,作為最終的產物。

val bestArtifact = artifacts.minOf {
    it.diffScore()
}

這樣我們就可以認為它是和當前 commit 最接近的 commit。對應的產物對于客戶端來說,轉增量編譯的風險最小、速度最快。

五、上線收益

目前項目上線了大部分的字節 Monorepo 項目,穩定運行了半年有余。期間也修復了 kotlin 1.7 上的若干官方增量編譯相關的 bug,最后取得了較為理想的收益。 

抖音從二進制演進到 Mopnorepo 后,Kotlin 部分的編譯時間劣化超過 10m+,我們通過本文的方案,將劣化的部分基本抹平,90 分位下降 60%,大幅提升了開發的體驗和 CI 合碼效率。

六、總結

本文主要闡述了 Kotlin 云端差分方案的技術原理。

實現超大型工程 Monorepo 全源碼的研發模式,僅靠 BuildCache 是無法實現的,Kotlin 云端差分方案對于全源碼起著不可或缺的作用。

通過模糊匹配緩存的方式將全量編譯模擬成增量編譯的思想,可能在其他端上比較容易實現或者就是標準方案,但目前 Android CI 構建領域均采用 clean 編譯,無法復用構建中間產物。該方案的出現也有望實現思想的復用,運用到所有『類似』的任務中,比如 Java Compile、Transform、Dex 等,只要它本身是支持增量、編譯冪等特性的,都可以復用這套方案,從而進一步提升 Android 的構建效率。

在研究云端差分方案期間,我們積累了大量的 Kotlin 編譯器相關的知識,為我們平時排查 kotlin 疑難問題提供了非常多的技術儲備,也發現了很多 kotlin 官方的 bug 和設計上的缺陷,我們也會在將來修復后回饋 kotlin 社區。

歡迎對編譯構建、Kotlin相關技術感興趣的小伙伴找我們進行技術交流與討論!

責任編輯:龐桂玉 來源: 字節跳動技術團隊
相關推薦

2022-04-06 15:58:25

火山引擎差分隱私LDPDC

2015-04-27 14:42:24

技術架構服務器性能

2023-09-03 19:13:29

AndroidKotlin

2012-04-02 16:35:49

網絡緩存

2012-12-26 09:32:55

智能手機移動傳感平臺云端分載GPS

2012-03-13 08:56:39

2023-11-11 19:43:12

緩存數據庫

2015-05-13 13:13:34

2016-01-04 11:04:47

無線技術傳感技術物聯網

2016-02-01 17:17:38

AWS技術峰會AWS Summit2

2011-07-11 10:00:34

PHP緩存技術

2011-12-28 10:44:02

PowerVM虛擬化

2018-08-07 10:44:50

緩存技術瀏覽器

2009-07-29 15:38:01

2010-06-03 15:21:49

服務器虛擬化桌面與應用虛擬化數據中心

2015-06-10 11:47:21

云計算互聯網+O2O

2010-06-01 15:35:32

2021-01-13 12:10:09

物聯網隱私網絡安全

2013-07-11 11:41:31

2013IBM技術峰會移動

2016-12-01 15:03:36

緩存技術客戶端
點贊
收藏

51CTO技術棧公眾號

精品日韩一区二区| 一区二区三区在线视频观看| 国产精品久久久久久久久影视| 国产精品suv一区二区88| 亚洲综合影院| 色综合一个色综合亚洲| 亚洲自拍偷拍一区二区三区| 色屁屁草草影院ccyycom| 久热国产精品| 欧美激情精品久久久久久免费印度| 右手影院亚洲欧美| 久久久久毛片免费观看| 91黄视频在线观看| 精品一区二区三区毛片| 欧美女v视频| 国产福利一区二区三区视频在线| 国产精品久久久av| 日本一级黄色录像| 99久久夜色精品国产亚洲96 | 色777狠狠综合秋免鲁丝| 91成人在线观看喷潮蘑菇| 日韩免费小视频| 亚洲一区二区三区小说| 色噜噜狠狠一区二区三区| 精品国产18久久久久久| 青椒成人免费视频| 91av在线免费观看| 欧美日韩成人免费观看| 久久综合88| 日韩大片免费观看视频播放| 国产91在线免费观看| 国产精品黄色片| 欧美丝袜一区二区| 欧美乱大交xxxxx潮喷l头像| 免费网站成人| 国产日韩影视精品| 麻豆精品蜜桃一区二区三区| 性欧美一区二区三区| 美腿丝袜亚洲三区| 国产国语videosex另类| 亚洲黄色小说图片| 精品电影一区| 久久久久久久999| 农村黄色一级片| 一区二区三区四区日韩| 久久黄色av网站| 精品女人久久久| 日韩中文首页| 色噜噜狠狠狠综合曰曰曰88av| 谁有免费的黄色网址| 中国av一区| 亚洲欧洲成视频免费观看| 麻豆精品国产传媒av| 国产精品丝袜在线播放| 亚洲成人av在线| 国产精品福利导航| 日韩av午夜| 亚洲老头同性xxxxx| 添女人荫蒂视频| 校园春色另类视频| 亚洲人成电影网站色| xxx在线播放| 美女网站一区| 一区二区亚洲欧洲国产日韩| 九九热免费在线| 久久影院100000精品| 毛片精品免费在线观看| 久草视频中文在线| 国产一区91| 国产精品看片资源| 国产又粗又猛又爽又黄的| 久久成人18免费观看| 亚洲tv在线观看| 日本成人动漫在线观看| 久久蜜桃av一区二区天堂 | 亚洲综合av在线播放| 久久99久久久精品欧美| 91麻豆精品国产91久久久更新时间| 91大神免费观看| 国产精品极品在线观看| 亚洲欧洲免费视频| 欧美特黄一级片| 精品91在线| 国产成人精品一区二区| 国产又黄又大又爽| 99视频在线观看一区三区| 日本在线观看一区二区三区| 免费在线观看黄| 天天综合网天天综合色| 三年中国国语在线播放免费| 色妞ww精品视频7777| 亚洲精品美女网站| 亚洲女人毛茸茸高潮| 国产一区激情| 国产精品激情av电影在线观看 | 免费国产亚洲视频| 国产精品swag| www.黄在线观看| 亚洲超碰97人人做人人爱| 少妇激情一区二区三区| 999久久精品| 日韩在线视频免费观看| 日产亚洲一区二区三区| 久久精品国产一区二区三| 国产精品日韩欧美一区二区三区| 国产高清在线| 天天综合网 天天综合色| 天天干天天爽天天射| 青青草久久爱| 欧美第一黄色网| 在线观看视频中文字幕| 99精品欧美一区二区蜜桃免费 | 国产丝袜在线| 91激情五月电影| 东京热av一区| 综合天堂av久久久久久久| 日韩av片永久免费网站| 亚洲成人一级片| ●精品国产综合乱码久久久久| 国产精品50p| 欧美另类中文字幕| 中文字幕亚洲天堂| 日韩免费av网站| 成年人网站91| 欧美大黑帍在线播放| 少妇高潮一区二区三区99| 亚洲欧洲日韩国产| 91蜜桃视频在线观看| 国产成人午夜片在线观看高清观看| 日韩免费电影一区二区| 一区二区三区短视频| 亚洲国产天堂久久国产91 | 日韩欧美在线观看视频| 亚洲精品无码一区二区| 综合激情视频| 亚洲永久在线观看| 中文字幕资源网在线观看| 欧美美女一区二区在线观看| 国精产品视频一二二区| 麻豆精品视频在线观看视频| 日韩欧美在线电影| 日韩久久一区二区三区| 亚洲人成电影在线播放| 日本中文字幕久久| 97久久精品人人爽人人爽蜜臀| 国产九九九九九| 日韩有码一区| 欧美在线观看网址综合| 欧美zozo| 在线观看www91| 丰满的亚洲女人毛茸茸| 奇米精品一区二区三区在线观看一| 日本在线观看一区二区三区| 国产精品亚洲d| 伊人青青综合网站| 亚洲天堂777| 日韩久久一区二区| 日本wwwxx| 夜夜精品视频| 色噜噜一区二区| 99亚洲男女激情在线观看| 中文字幕亚洲欧美日韩高清| 国产精品爽爽久久久久久| 亚洲视频一二三区| 乱码一区二区三区| 99精品视频免费全部在线| 欧美激情第一页在线观看| 日韩经典一区| 欧美丰满老妇厨房牲生活 | 91麻豆精品国产综合久久久| 久久中文字幕一区| 黑人精品一区二区三区| 欧美丝袜一区二区| 亚洲国产精品一区二区久久hs| 激情综合色播五月| 99在线精品免费视频| 欧美女优在线视频| 国产在线久久久| 91超碰免费在线| 中文在线不卡视频| 亚洲AV无码乱码国产精品牛牛| 精品高清一区二区三区| 成人精品一二三区| av激情综合网| 五月婷婷丁香色| 狠久久av成人天堂| 视频一区二区在线观看| 日韩一区二区三区在线看| 91超碰中文字幕久久精品| 色大18成网站www在线观看| 欧美成人精品高清在线播放| 国内自拍视频在线播放| 亚洲天堂免费看| 亚洲国产无码精品| 国产麻豆欧美日韩一区| 成人在线看视频| 欧美日本一区二区视频在线观看 | 欧美性videosxxxxx| 免费在线一区二区三区| 欧美激情资源网| 奇米777第四色| 精品亚洲成a人在线观看| 噜噜噜久久亚洲精品国产品麻豆| 国产精品88久久久久久| 久久超碰亚洲| 奇米一区二区| 国产女精品视频网站免费| 精品三级久久| 九九精品在线观看| 91精品国产综合久久久久久豆腐| 亚洲精品国产精品国自产观看浪潮| 亚洲综合网av| 色婷婷精品大在线视频| 中文字幕一区二区三区精品| 亚洲黄色av一区| 2014亚洲天堂| 中文字幕+乱码+中文字幕一区| 99久久免费看精品国产一区| 国产激情视频一区二区三区欧美 | 懂色av噜噜一区二区三区av| 在线观看免费的av| 日本aⅴ免费视频一区二区三区| 日本韩国欧美在线观看| 欧美日韩国产亚洲一区| 国产手机视频在线观看| 成人亚洲一区| 天天人人精品| 少妇精品久久久| 久久精品国产99精品国产亚洲性色| 97人人澡人人爽91综合色| 91香蕉电影院| 精品一区二区三区免费看| 91精品国产自产在线观看永久| 在线看欧美视频| 国产成人综合精品| 黄色精品视频| 国产精品日韩欧美| 福利一区在线| 国产精品视频99| 欧美日韩va| 成人久久久久久| 粉嫩一区二区三区在线观看| 91在线观看免费观看| 一区二区三区无毛| 91午夜理伦私人影院| 国产高清日韩| 91嫩草国产在线观看| 日韩精品一区国产| 成人免费视频网站入口| av男人一区| 久久精品一二三区| 久久99国产精品视频| 日韩国产伦理| 久久国产精品亚洲人一区二区三区| 亚洲午夜精品久久久久久浪潮| 欧美激情电影| 亚洲色婷婷久久精品av蜜桃| 欧美日韩亚洲一区| 久久国产精品网| 麻豆精品网站| 欧美成年人视频在线观看| 黄网站免费久久| 中国男女全黄大片| 97久久超碰精品国产| 国产精品毛片一区二区| 国产精品色哟哟| 日本妇女毛茸茸| 欧美日韩加勒比精品一区| 伦av综合一区| 欧美精品色综合| 亚洲欧美国产高清va在线播放| 亚洲第一福利网站| 黄色软件在线| 欧美老肥婆性猛交视频| 在线观看爽视频| 成人av番号网| 红杏成人性视频免费看| 日本高清视频一区二区三区| 国产韩国精品一区二区三区| 少妇人妻大乳在线视频| 男女男精品视频| 国产人妻精品午夜福利免费| 久久影院视频免费| 天天鲁一鲁摸一摸爽一爽| 亚洲国产中文字幕在线视频综合| 91porny九色| 日韩欧美亚洲国产另类| 久香视频在线观看| 欧美日本啪啪无遮挡网站| av亚洲一区二区三区| 97夜夜澡人人双人人人喊| 国产探花在线精品| av日韩在线看| 日本中文字幕一区二区有限公司| 国产精品19p| 欧美激情一区二区在线| 国产主播在线播放| 欧美日韩国产小视频在线观看| 女人18毛片水真多18精品| 中文字幕在线观看日韩| 欧美在线极品| 99国精产品一二二线| 欧美一区二区性| 狠狠97人人婷婷五月| 国产精品一区二区三区网站| 成人免费毛片糖心| 五月综合激情网| 国产欧美熟妇另类久久久| 亚洲欧美www| 55av亚洲| 亚洲最大av网| 色琪琪久久se色| www黄色在线| av爱爱亚洲一区| 精品少妇久久久久久888优播| 欧美视频在线一区二区三区| 理论视频在线| 欧美夜福利tv在线| aiai久久| 日本阿v视频在线观看| 国精产品一区一区三区mba视频| 国产成人无码精品久久二区三| 亚洲第一主播视频| 亚洲精品一区二区三区不卡| 久久成年人视频| 亚洲我射av| 亚洲日本精品| 老汉av免费一区二区三区| 色噜噜日韩精品欧美一区二区| 婷婷国产在线综合| 日本美女一级视频| 久久久久久久香蕉网| 我要色综合中文字幕| 成人在线免费高清视频| 国产精品123| 久久久久久久极品内射| 日韩一区二区三区观看| 黄色在线播放网站| 91亚洲永久免费精品| 香港欧美日韩三级黄色一级电影网站| 五月婷婷丁香综合网| 欧美国产综合色视频| 国产在线一级片| 日韩中文有码在线视频| 成人精品在线| 日本国产中文字幕| 成人网在线播放| 日产亚洲一区二区三区| 日韩电视剧在线观看免费网站| 黄在线观看免费网站ktv| 久久久久久国产精品mv| 葵司免费一区二区三区四区五区| 一道本在线观看| 精品视频一区 二区 三区| 欧美性videos| 亚洲一区二区三区sesese| 欧美视频一区| 久久丫精品国产亚洲av不卡| 欧美午夜xxx| h网站在线免费观看| 成人免费激情视频| 午夜激情一区| 超碰97在线资源站| 91福利小视频| 巨大荫蒂视频欧美大片| 成人黄动漫网站免费| 亚洲尤物影院| 国产wwwwxxxx| 精品乱人伦小说| 欧美片第一页| 日韩第一页在线观看| 成人午夜大片免费观看| 精品人妻一区二区三区潮喷在线| 中文字幕av日韩| 哺乳一区二区三区中文视频| 女人天堂av手机在线| 国产精品国产馆在线真实露脸| 精品乱子伦一区二区| 8x拔播拔播x8国产精品| 日韩欧美字幕| 国产精品嫩草av| 4438x亚洲最大成人网| 成人观看网址| 伊人狠狠色丁香综合尤物| 国产91露脸合集magnet| 蜜臀99久久精品久久久久小说| 久久精品人人爽| 台湾色综合娱乐中文网| 人人爽人人爽av| 色综合中文字幕国产| 伊人精品影院| 日韩精品一区二区三区外面| 国产精品69毛片高清亚洲| 丰满少妇xoxoxo视频| 不卡av日日日| 欧洲杯半决赛直播| 亚洲精品第二页| 5月丁香婷婷综合| 韩国精品主播一区二区在线观看| 日韩a级黄色片|