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

冷飯新炒:理解布隆過濾器算法的實現原理

開發 前端 算法
布隆過濾器是「一種空間高效概率性的數據結構」(百科中原文是a space-efficient probabilistic data structure),該數據結構于1970年由Burton Howard Bloom提出,「作用是測試一個元素是否某個集合的一個成員」。

[[385658]]

 

 

本文會翻炒一個用途比較廣的算法 - 「布隆過濾器算法」。

布隆過濾器的一些概念主要包括:

  • 簡介
  • 算法
  • 參數
  • 優勢和劣勢

布隆過濾器簡介

布隆過濾器是「一種空間高效概率性的數據結構」(百科中原文是a space-efficient probabilistic data structure),該數據結構于1970年由Burton Howard Bloom提出,「作用是測試一個元素是否某個集合的一個成員」。布隆過濾器是可能出現false positive(這個是專有名詞"假陽性",可以理解為誤判的情況,下文如果用到這個名詞會保留英文單詞使用)匹配的,換言之,布隆過濾器在使用的時候有可能返回結果"可能存在于集合中"或者"必定不存在于集合中"。

布隆過濾器算法描述

在場景復雜的網絡爬蟲中,爬取到的網頁URL依賴有可能成環,例如在URL-1頁面中展示了URL-2,然后又在URL-2中的頁面展示了URL-1,這個時候需要一種方案記錄和判斷歷史訪問過的URL。這個時候可能會想到下面的方案:

  • 方案一:使用數據庫存儲已經訪問過的URL,例如MySQL表中基于URL建立唯一索引或者使用Redis的SET數據類型
  • 方案二:使用HashSet(其實這里不局限于HashSet,鏈表、樹和散列表等數據結構都能滿足)存儲已經訪問過的URL
  • 方案三:基于方案一和方案二進行優化,存儲URL的摘要,使用摘要算法如MD5、SHA-n算法針對URL字符串生成摘要
  • 方案四:使用Hash函數處理對應的URL生成一個哈希碼,再把哈希碼通過一個映射函數映射到一個固定容量的BitSet中的某一個比特

對于方案一、方案二和方案三,在歷史訪問URL數據量極大的情況下,會消耗巨大的存儲空間(磁盤或者內存),對于方案四,如果URL有100億個,那么要把沖突幾率降低到1%,那么BitSet的容量需要設置為10000億。

 

所以上面的四種方案都有明顯的不足之處,而布隆過濾器算法的基本思路跟方案四差不多,最大的不同點就是方案四中只提到使用了一個散列函數,而布隆過濾器中使用了k(k >= 1)個相互獨立的高效低沖突的散列函數。

一個初始化的布隆過濾器是一個所有比特都設置為0的長度為m的比特數組,也就是認知中的Bit Array、Bit Set或者Redis中的Bit Map概念。然后需要引入k個不同的散列函數,某個新增元素通過這k個散列函數處理之后,映射到比特數組m個比特中的k個,并且把這些命中映射的k個比特位設置為1,產生一個均勻的隨機分布。通常情況下,k的一個較小的常數,取決于所需的誤判率,而布隆過濾器容量m與散列函數個數k和需要添加元素數量呈正相關。

 

當需要新增的所有元素都添加到布隆過濾器之后,那么比特數組中的很多比特都被設置為1。這個時候如果需要判斷一個元素是否存在于布隆過濾器中,只需要通過k個散列函數處理得到比特數組的k個下標,然后判斷比特數組對應的下標所在比特是否為1。如果這k個下標所在比特中「至少存在一個0,那么這個需要判斷的元素必定不在布隆過濾器代表的集合中」;如果這k個下標所在比特全部都為1,那么那么這個需要判斷的元素「可能存在于」布隆過濾器代表的集合中或者剛好是一個False Positive,至于誤差率分析見下文的「布隆過濾器的相關參數」一節。False Positive出現的情況可以見下圖:

 

當添加到布隆過濾器的元素數量比較大,并且布隆過濾器的容量設置不合理(過小),容易出現多個元素通過k個散列函數,映射到相同的k個位(如上圖的下標1、3、9所在的位),這個時候就無法準確判斷這k個位由具體那個元素映射而來。其實可以極端一點思考:假設布隆過濾器容量為24,散列函數只有一個,那么添加最多25個不同元素,必定有兩個不同的元素的映射結果落在同一個位。

布隆過濾器的相關參數

在算法描述一節已經提到過,布隆過濾器主要有下面的參數:

初始化比特數組容量m

散列函數個數k

誤判率ε(數學符號Epsilon,代表False Positive Rate)

需要添加到布隆過濾器的元素數量n

考慮到篇幅原因,這里不做這幾個值的關系推導,直接整理出結果和關系式。

誤判率ε的估算值為:[1 - e^(-kn/m)]^k

最優散列函數數量k的推算值:對于給定的m和n,當k = m/n * ln2的時候,誤判率ε最低

推算初始化比特容量m的值,當k = m/n * ln2的時候,m >= n * log2(e) * log2(1/ε)

這里貼一個參考資料中m/n、k和False Positive Rate之間的關系圖:


 

 

這里可以推算一下表格中最大參數所需要的空間極限,假設n為10億,m/n = 32,那么m為320億,而k為24,此時的誤判率為2.17e-07(0.000000217),需要空間3814.69727m。一般規律是:

當k固定的時候,m/n越大,誤判率越小

當m/n固定的時候,k越大,誤判率越大

通常情況下,k需要固定,而n是無法確定準確值,最好要評估增長趨勢預先計算一個比較大的m值去降低誤判率,當然也要權衡m值過大導致空間消耗過大的問題。

既然參數的關系式都已經有推導結果,可以基于關系式寫一個參數生成器:

  1. import java.math.BigDecimal; 
  2. import java.math.RoundingMode; 
  3.  
  4. public class BloomFilterParamGenerator { 
  5.  
  6.     public BigDecimal falsePositiveRate(int m, int n, int k) { 
  7.         double temp = Math.pow(1 - Math.exp(Math.floorDiv(-k * n, m)), k); 
  8.         return BigDecimal.valueOf(temp).setScale(10, RoundingMode.FLOOR); 
  9.     } 
  10.  
  11.     public BigDecimal kForMinFalsePositiveRate(int m, int n) { 
  12.         BigDecimal k = BigDecimal.valueOf(Math.floorDiv(m, n) * Math.log(2)); 
  13.         return k.setScale(10, RoundingMode.FLOOR); 
  14.     } 
  15.  
  16.     public BigDecimal bestM(int n, double falsePositiveRate) { 
  17.         double temp = log2(Math.exp(1) + Math.floor(1 / falsePositiveRate)); 
  18.         return BigDecimal.valueOf(n).multiply(BigDecimal.valueOf(temp)).setScale(10, RoundingMode.FLOOR); 
  19.     } 
  20.  
  21.     public double log2(double x) { 
  22.         return Math.log(x) / Math.log(2); 
  23.     } 
  24.  
  25.     public static void main(String[] args) { 
  26.         BloomFilterParamGenerator generator = new BloomFilterParamGenerator(); 
  27.         System.out.println(generator.falsePositiveRate(2, 1, 2));  // 0.3995764008 
  28.         System.out.println(generator.kForMinFalsePositiveRate(32, 1)); // 22.1807097779 
  29.         System.out.println(generator.bestM(1, 0.3995764009)); // 2.2382615950 
  30.     } 

這里的計算沒有考慮嚴格的進位和截斷,所以和實際的結果可能有偏差,只提供一個參考的例子。

布隆過濾器的優勢和劣勢

布隆過濾器的優勢:

  • 布隆過濾器相對于其他數據結構在時空上有巨大優勢,占用內存少,查詢和插入元素的時間復雜度都是O(k)
  • 可以準確判斷元素不存在于布隆過濾器中的場景
  • 散列函數可以獨立設計
  • 布隆過濾器不需要存儲元素本身,適用于某些數據敏感和數據嚴格保密的場景

布隆過濾器的劣勢:

  • 不能準確判斷元素必定存在于布隆過濾器中的場景,存在誤判率,在k和m固定的情況下,添加的元素越多,誤判率越高
  • 沒有存儲全量的元素,對于一些準確查詢或者準確統計的場景不適用
  • 原生的布隆過濾器無法安全地刪除元素

這里留一個很簡單的問題給讀者:為什么原生的布隆過濾器無法安全地刪除元素?(可以翻看之前的False Positive介紹)

布隆過濾器算法實現

著名的Java工具類庫Guava中自帶了一個beta版本的布隆過濾器實現,這里參考其中的源碼實現思路和上文中的算法描述進行一次布隆過濾器的實現。先考慮設計散列函數,簡單一點的方式就是參考JavaBean的hashCode()方法的設計:

  1. // 下面的方法來源于java.util.Arrays#hashCode 
  2. public static int hashCode(Object a[]) { 
  3.     if (a == null
  4.         return 0; 
  5.     int result = 1; 
  6.     for (Object element : a) 
  7.         result = 31 * result + (element == null ? 0 : element.hashCode()); 
  8.     return result; 

上面方法的31可以作為一個輸入的seed,每個散列函數設計一個獨立的seed,并且這個seed值選用素數基于字符串中的每個char進行迭加就能實現計算出來的結果是相對獨立的:

  1. import java.util.Objects; 
  2.  
  3. public class HashFunction { 
  4.  
  5.     /** 
  6.      * 布隆過濾器容量 
  7.      */ 
  8.     private final int m; 
  9.  
  10.     /** 
  11.      * 種子 
  12.      */ 
  13.     private final int seed; 
  14.  
  15.     public HashFunction(int m, int seed) { 
  16.         this.m = m; 
  17.         this.seed = seed; 
  18.     } 
  19.  
  20.     public int hash(String element) { 
  21.         if (Objects.isNull(element)) { 
  22.             return 0; 
  23.         } 
  24.         int result = 1; 
  25.         int len = element.length(); 
  26.         for (int i = 0; i < len; i++) { 
  27.             result = seed * result + element.charAt(i); 
  28.         } 
  29.         // 這里確保計算出來的結果不會超過m 
  30.         return (m - 1) & result; 
  31.     } 

接著實現布隆過濾器:

  1. public class BloomFilter { 
  2.  
  3.     private static final int[] K_SEED_ARRAY = {5, 7, 11, 13, 31, 37, 61, 67}; 
  4.  
  5.     private static final int MAX_K = K_SEED_ARRAY.length; 
  6.  
  7.     private final int m; 
  8.  
  9.     private final int k; 
  10.  
  11.     private final BitSet bitSet; 
  12.  
  13.     private final HashFunction[] hashFunctions; 
  14.  
  15.     public BloomFilter(int m, int k) { 
  16.         this.k = k; 
  17.         if (k <= 0 && k > MAX_K) { 
  18.             throw new IllegalArgumentException("k = " + k); 
  19.         } 
  20.         this.m = m; 
  21.         this.bitSet = new BitSet(m); 
  22.         hashFunctions = new HashFunction[k]; 
  23.         for (int i = 0; i < k; i++) { 
  24.             hashFunctions[i] = new HashFunction(m, K_SEED_ARRAY[i]); 
  25.         } 
  26.     } 
  27.  
  28.     public void addElement(String element) { 
  29.         for (HashFunction hashFunction : hashFunctions) { 
  30.             bitSet.set(hashFunction.hash(element), true); 
  31.         } 
  32.     } 
  33.  
  34.     public boolean contains(String element) { 
  35.         if (Objects.isNull(element)) { 
  36.             return false
  37.         } 
  38.         boolean result = true
  39.         for (HashFunction hashFunction : hashFunctions) { 
  40.             result = result && bitSet.get(hashFunction.hash(element)); 
  41.         } 
  42.         return result; 
  43.     } 
  44.  
  45.     public int m() { 
  46.         return m; 
  47.     } 
  48.  
  49.     public int k() { 
  50.         return k; 
  51.     } 
  52.  
  53.     public static void main(String[] args) { 
  54.         BloomFilter bf = new BloomFilter(24, 3); 
  55.         bf.addElement("throwable"); 
  56.         bf.addElement("throwx"); 
  57.         System.out.println(bf.contains("throwable"));  // true 
  58.     } 

這里的散列算法和有限的k值不足以應對復雜的場景,僅僅為了說明如何實現布隆過濾器,總的來說,原生布隆過濾器算法是比較簡單的。對于一些復雜的生產場景,可以使用一些現成的類庫如Guava中的布隆過濾器API、Redis中的布隆過濾器插件或者Redisson(Redis高級客戶端)中的布隆過濾器API。

布隆過濾器應用

主要包括:

  • Guava中的API
  • Redisson中的API
  • 使用場景

使用Guava中的布隆過濾器API

引入Guava的依賴:

  1. <dependency> 
  2.     <groupId>com.google.guava</groupId> 
  3.     <artifactId>guava</artifactId> 
  4.     <version>30.1-jre</version> 
  5. </dependency> 

使用布隆過濾器:

  1. import com.google.common.hash.BloomFilter; 
  2. import com.google.common.hash.Funnels; 
  3.  
  4. import java.nio.charset.StandardCharsets; 
  5.  
  6. public class GuavaBloomFilter { 
  7.  
  8.     @SuppressWarnings("UnstableApiUsage"
  9.     public static void main(String[] args) { 
  10.         BloomFilter<CharSequence> bloomFilter = BloomFilter.create(Funnels.stringFunnel(StandardCharsets.US_ASCII), 10000, 0.0444D); 
  11.         bloomFilter.put("throwable"); 
  12.         bloomFilter.put("throwx"); 
  13.         System.out.println(bloomFilter.mightContain("throwable")); 
  14.         System.out.println(bloomFilter.mightContain("throwx")); 
  15.     } 

構造BloomFilter的最多參數的靜態工廠方法是BloomFilter create(Funnel funnel, long expectedInsertions, double fpp, BloomFilter.Strategy strategy),參數如下:

  • funnel:主要是把任意類型的數據轉化成HashCode,是一個頂層接口,有大量內置實現,見Funnels
  • expectedInsertions:期望插入的元素個數
  • fpp:猜測是False Positive Percent,誤判率,小數而非百分數,默認值0.03
  • strategy:映射策略,目前只有MURMUR128_MITZ_32和MURMUR128_MITZ_64(默認策略)

參數可以參照上面的表格或者參數生成器的指導,基于實際場景進行定制。

使用Redisson中的布隆過濾器API

高級Redis客戶端Redisson已經基于Redis的bitmap數據結構做了封裝,屏蔽了復雜的實現邏輯,可以開箱即用。引入Redisson的依賴:

  1. <dependency> 
  2.     <groupId>org.redisson</groupId> 
  3.     <artifactId>redisson</artifactId> 
  4.     <version>3.15.1</version> 
  5. </dependency> 

使用Redisson中的布隆過濾器API:

  1. import org.redisson.Redisson; 
  2. import org.redisson.api.RBloomFilter; 
  3. import org.redisson.api.RedissonClient; 
  4. import org.redisson.config.Config; 
  5.  
  6. public class RedissonBloomFilter { 
  7.  
  8.     public static void main(String[] args) { 
  9.         Config config = new Config(); 
  10.         config.useSingleServer() 
  11.                 .setAddress("redis://127.0.0.1:6379"); 
  12.         RedissonClient redissonClient = Redisson.create(config); 
  13.         RBloomFilter<String> bloomFilter = redissonClient.getBloomFilter("ipBlockList"); 
  14.         // 第一個參數expectedInsertions代表期望插入的元素個數,第二個參數falseProbability代表期望的誤判率,小數表示 
  15.         bloomFilter.tryInit(100000L, 0.03D); 
  16.         bloomFilter.add("127.0.0.1"); 
  17.         bloomFilter.add("192.168.1.1"); 
  18.         System.out.println(bloomFilter.contains("192.168.1.1")); // true 
  19.         System.out.println(bloomFilter.contains("192.168.1.2")); // false 
  20.     } 

Redisson提供的布隆過濾器接口RBloomFilter很簡單:

 

常用的方法有tryInit()(初始化)、add()(添加元素)和contains()(判斷元素是否存在)。相對于Guava的內存態的布隆過濾器實現,Redisson提供了基于Redis實現的「分布式布隆過濾器」,可以滿足分布式集群中布隆過濾器的使用。

布隆過濾器使用場景

其實布隆過濾器的使用場景可以用百科中的一張示意圖來描述:

基于上圖具體化的一些場景列舉如下:

  • 網站爬蟲應用中進行URL去重(不存在于布隆過濾器中的URL必定是未爬取過的URL)
  • 防火墻應用中IP黑名單判斷(不局限于IP黑名單,通用的黑名單判斷場景基本都可以使用布隆過濾器,不存在于布隆過濾器中的IP必定是白名單)
  • 用于規避緩存穿透(不存在于布隆過濾器中的KEY必定不存在于后置的緩存中)

布隆過濾器變體

布隆過濾器的變體十分多,主要是為了解決布隆過濾器算法中的一些缺陷或者劣勢。常見的變體如下:

 

變體名稱 變體描述
Counting Bloom Filter 把原生布隆過濾器每個位替換成一個小的計數器(Counter),所謂計數器其實就是一個小的整數
Compressed Bloom Filter 對位數組進行壓縮
Hierarchical Bloom Filters 分層,由多層布隆過濾器組成
Spectral Bloom Filters CBF的擴展,提供查詢集合元素的出現頻率功能
Bloomier Filters 存儲函數值,不僅僅是做位映射
Time-Decaying Bloom Filters 計數器數組替換位向量,優化每個計數器存儲其值所需的最小空間
Space Code Bloom Filter -
Filter Banks -
Scalable Bloom filters -
Split Bloom Filters -
Retouched Bloom filters -
Generalized Bloom Filters -
Distance-sensitive Bloom filters -
Data Popularity Conscious Bloom Filters -
Memory-optimized Bloom Filter -
Weighted Bloom filter -
Secure Bloom filters -

這里挑選Counting Bloom Filter(簡稱CBF)變體稍微展開一下。原生布隆過濾器的基礎數據結構是位向量,CBF擴展原生布隆過濾器的基礎數據結構,底層數組的每個元素使用4位大小的計數器存儲添加元素到數組某個下標時候映射成功的頻次,在插入新元素的時候,通過k個散列函數映射到k個具體計數器,這些命中的計數器值增加1;刪除元素的時候,通過k個散列函數映射到k個具體計數器,這些計數器值減少1。使用CBF判斷元素是否在集合中的時候:

  • 某個元素通過k個散列函數映射到k個具體計數器,所有計數器的值都為0,那么元素必定不在集合中
  • 某個元素通過k個散列函數映射到k個具體計數器,至少有1個計數器的值大于0,那么元素可能在集合

 

小結一句話簡單概括布隆過濾器的基本功能:「不存在則必不存在,存在則不一定存在?!?/p>

在使用布隆過濾器判斷一個元素是否屬于某個集合時,會有一定的誤判率。也就是有可能把不屬于某個集合的元素誤判為屬于這個集合,這種錯誤稱為False Positive,但不會把屬于某個集合的元素誤判為不屬于這個集合(相對于False Positive,"假陽性",如果屬于某個集合的元素誤判為不屬于這個集合的情況稱為False Negative,"假陰性")。False Positive,也就是錯誤率或者誤判率這個因素的引入,是布隆過濾器在設計上權衡空間效率的關鍵。

參考資料:

  • Bloom filter
  • Guava相關源碼
  • Bloom Filters - the math

(本文完 c-1-w e-a-20210306)

本文轉載自微信公眾號「Throwable」,可以通過以下二維碼關注。轉載本文請聯系Throwable公眾號。

 

責任編輯:武曉燕 來源: Throwable
相關推薦

2024-01-05 09:04:35

隆過濾器數據結構哈希函數

2021-02-19 08:20:42

JWT網絡原理

2024-03-15 11:21:22

布隆過濾器數據庫數據

2024-11-04 08:45:48

布隆過濾器元數據指紋值

2021-01-29 08:33:39

JDK底層UUID

2020-10-29 07:16:26

布隆過濾器場景

2022-03-21 08:31:07

布隆過濾器Redis過濾器原理

2024-09-18 10:08:37

2025-04-30 08:47:41

2024-09-25 17:44:08

2024-10-09 15:54:38

布隆過濾器函數

2025-02-08 17:30:00

布隆過濾器數據結構

2023-01-31 08:19:53

二進制元素數量

2025-01-23 00:00:00

Java布隆過濾器

2023-04-26 08:32:45

Redis布隆過濾器

2019-03-22 15:15:25

Redis緩存擊穿雪崩效應

2021-09-03 06:33:24

布隆過濾器高并發

2025-01-22 00:00:00

布隆過濾器二進制

2020-08-28 13:02:17

布隆過濾器算法

2024-03-04 10:24:34

布隆過濾器C#代碼
點贊
收藏

51CTO技術棧公眾號

日韩精品一区二区三区老鸭窝 | 日韩专区第三页| 国产av精国产传媒| 一本色道久久综合一区| 国产香蕉97碰碰久久人人| 免费成年人高清视频| 视频在线观看入口黄最新永久免费国产| 国产成人鲁色资源国产91色综| 国模叶桐国产精品一区| 99在线视频免费| 97视频一区| 欧美性猛交xxxxxx富婆| 日韩一级片一区二区| 好男人免费精品视频| 国产乱国产乱300精品| 欧美在线性爱视频| 美女福利视频在线观看| 精品国产精品久久一区免费式| 欧美一区二区日韩一区二区| 亚洲精品乱码久久久久久自慰| 国产美女福利在线| 久久久精品日韩欧美| 91久久爱成人| 中文字幕在线播放av| 日韩香蕉视频| 九九精品在线观看| 美国美女黄色片| 美女一区二区在线观看| 91精品免费在线| 网站一区二区三区| 手机在线理论片| 一区二区三区丝袜| 亚洲欧美久久234| 水中色av综合| 成人av在线资源网站| 亚洲一区二区三| 一级片在线免费播放| 免费看的黄色欧美网站| 久久人人看视频| 国产大学生自拍| 四季av在线一区二区三区| 亚洲欧美资源在线| 亚洲精品乱码久久久久久久| 国产区精品视频在线观看豆花| 91精品国产福利在线观看 | 成人免费看黄| 精品福利在线观看| 国产精品久久中文字幕| 色黄网站在线观看| 一区二区三区中文字幕| 老汉色影院首页| 日本不卡不卡| 日韩毛片在线免费观看| 伊人久久婷婷色综合98网| 成年午夜在线| 国产精品午夜久久| 午夜精品一区二区在线观看| 国产黄色在线播放| 欧美国产国产综合| 一本色道婷婷久久欧美| 在线观看免费版| 国产精品理伦片| 一区二区三区四区五区视频| 又爽又大又黄a级毛片在线视频| 欧美激情一区二区三区不卡| 五月婷婷一区| 欧美激情视频在线播放| 中文字幕一区视频| 国产成人三级视频| 在线观看wwwxxxx| 亚洲国产aⅴ天堂久久| 久久久久久免费看| 中文字幕资源网在线观看免费 | 97激碰免费视频| 国产免费观看av| 日韩电影免费在线看| 国产精品久久一区| 国产av无码专区亚洲av| 丁香六月久久综合狠狠色| 国产在线视频欧美一区二区三区| 人成在线免费视频| 国产精品区一区二区三区| 中文字幕第50页| 678在线观看视频| 精品久久久久久久久国产字幕| 国产午夜伦鲁鲁| 国产一区二区主播在线| 欧美一区二区三区系列电影| 北京富婆泄欲对白| 狠狠做六月爱婷婷综合aⅴ| 日韩视频免费大全中文字幕| 精品肉丝脚一区二区三区| 午夜综合激情| 亚洲精品欧美一区二区三区| 日本aaa在线观看| 国产精品久久午夜夜伦鲁鲁| 黄色三级中文字幕| 日韩一区精品| 精品久久久久久久久久久久包黑料| 魔女鞋交玉足榨精调教| 久久久久蜜桃| 日本亚洲精品在线观看| 国产99久一区二区三区a片| 久久久不卡影院| 日本美女爱爱视频| 日韩免费va| 亚洲成人免费在线视频| 免费看一级黄色| 亚洲欧美日本日韩| 97在线资源站| 日本高清视频在线观看| 欧美午夜视频在线观看| 精产国品一区二区三区| 日本欧美国产| 青青精品视频播放| 亚洲第一精品网站| 亚洲欧美自拍偷拍| 免费看a级黄色片| 理论片一区二区在线| 欧美成人亚洲成人| 亚洲字幕av一区二区三区四区| jvid福利写真一区二区三区| 影音先锋欧美在线| 妞干网免费在线视频| 91精品欧美久久久久久动漫| 少妇饥渴放荡91麻豆| 亚洲va在线| 国产精品久久久久久久午夜| 粉嫩小泬无遮挡久久久久久| 亚洲国产精品精华液ab| 成 年 人 黄 色 大 片大 全| 美女久久精品| 伊人伊成久久人综合网站| 国产成人无码精品久在线观看| 国产米奇在线777精品观看| 日韩激情久久| 亚洲女同志freevdieo| 日韩欧美一二区| 91香蕉国产视频| 水蜜桃久久夜色精品一区的特点| 久久国产精品一区二区三区| 永久免费网站在线| 欧美日韩色综合| 日韩丰满少妇无码内射| 国产日产高清欧美一区二区三区| 亚洲自拍偷拍福利| 污的网站在线观看| 欧美一区二区精品在线| 中日韩一级黄色片| 91极品视频在线| 日韩国产第一页| 久久蜜桃资源一区二区老牛| 国产女主播视频一区二区| 青青草视频国产| 中文成人激情娱乐网| 亚洲色图在线观看| 国产69精品久久久久久久久久| 国产成人精品亚洲777人妖| 国产在线欧美日韩| 黑人巨大亚洲一区二区久| 日韩精品999| 欧美成人精品欧美一级乱黄| 成人少妇影院yyyy| 成人在线国产视频| 88久久精品| 午夜免费日韩视频| 日韩一级片免费观看| 午夜一区二区三区视频| 伦理片一区二区| 亚洲激情亚洲| 成人影片在线播放| 中文字幕在线官网| 在线国产精品播放| 中文字幕永久在线观看| 亚洲欧洲在线观看av| 国产女同无遮挡互慰高潮91| 欧美在线黄色| 国产精品theporn88| av影院在线| 亚洲人午夜精品免费| 在线不卡免费视频| 玉足女爽爽91| 丰满少妇在线观看资源站| 日韩精品视频网| 中文字幕日韩精品久久| 日韩在线观看一区二区三区| 欧美激情一区二区久久久| 欧美一级特黄aaaaaa| 色嗨嗨av一区二区三区| 日韩在线一卡二卡| 国产a区久久久| 日本毛片在线免费观看| 激情婷婷综合| 国产免费一区二区三区香蕉精| 四虎影视成人| 亚洲欧美一区二区三区情侣bbw | 国产成人美女视频| 欧美激情亚洲| 欧美精品一区二区三区在线看午夜 | 久久福利视频网| 无码精品在线观看| 91麻豆精品91久久久久久清纯| 免费在线视频一区二区| 久久综合视频网| 青青草原播放器| 模特精品在线| 97超碰在线人人| 精品日产免费二区日产免费二区| 69堂成人精品视频免费| 在线观看的黄色| 久久影视免费观看| 污视频软件在线观看| 91麻豆精品国产91久久久| 国产91精品一区| 亚洲美女在线国产| 亚洲专区区免费| 精品午夜一区二区三区在线观看| 色欲av无码一区二区人妻| 亚洲精品91| 精品国产欧美日韩不卡在线观看 | 欧美日韩亚洲免费| www.久久久久爱免| 3344国产精品免费看| 午夜激情视频在线观看| 亚洲三级av在线| 亚洲精品久久久蜜桃动漫| 欧美午夜精品电影| 日韩欧美视频在线免费观看| 国产91丝袜美女在线播放| 老牛影视一区二区三区| 神马午夜伦理影院| 奇米777国产一区国产二区| 亚洲一区二区三区乱码aⅴ蜜桃女| 国产精品迅雷| 欧美精品aaa| 麻豆网站视频在线观看| 日韩在线高清视频| 精品无码m3u8在线观看| 国产欧美视频一区二区三区| 国产伦精品一区二区三区精品 | 奇米影视亚洲色图| 日韩在线精品| 日韩免费三级| 性欧美lx╳lx╳| 日本美女黄色一级片| 欧美日韩免费观看一区=区三区| 欧美成人免费在线| 大型av综合网站| 不卡一区二区三区视频| 午夜视频一区二区在线观看| 91精品久久久久久久| 成人黄页网站视频| 国产精品久久久久久久久久久久| 裤袜国产欧美精品一区| 夜夜嗨av一区二区三区网页| 三级电影在线看| av在线播放不卡| 国产 xxxx| 99久久er热在这里只有精品15 | 偷拍视频一区二区三区| 日本最新高清不卡中文字幕| 午夜久久中文| 青青草国产精品一区二区| 涩涩av在线| 国产91色在线播放| 96sao精品免费视频观看| 91青草视频久久| 日韩欧美中文字幕一区二区三区| 亚洲自拍偷拍在线| 一区二区三区四区高清视频| 久久人人九九| 国产欧美日韩精品一区二区三区| 欧美一区二区在线视频观看| 蜜臀av免费一区二区三区| 欧美日韩大片一区二区三区| 99久久亚洲精品蜜臀| 国产又爽又黄ai换脸| 真实国产乱子伦精品一区二区三区| 欧美性受黑人性爽| 狠狠噜噜久久| 999在线免费视频| 久久se这里有精品| 久久黄色一级视频| 99久久精品国产观看| 偷拍夫妻性生活| 国产欧美一区二区精品仙草咪| 99re6热在线精品视频| 亚洲精品国产精华液| 日本熟妇毛耸耸xxxxxx| 欧美色国产精品| www.97av.com| 亚洲精品一区久久久久久| 9i精品一二三区| 精品国产一区二区三区久久狼5月| 丁香高清在线观看完整电影视频| 奇米4444一区二区三区| 久久天堂影院| 国产精品xxxx| 黑人操亚洲人| aa在线观看视频| 久久99精品一区二区三区| 亚洲av熟女高潮一区二区| 国产日韩精品一区二区三区在线| 麻豆精品一区二区三区视频| 欧美性极品少妇精品网站| 91片黄在线观看喷潮| 亚洲成在人线av| 成人好色电影| 97超级碰在线看视频免费在线看 | 欧美在线日韩在线| 玖玖玖电影综合影院| 另类视频在线观看+1080p| 中文字幕午夜精品一区二区三区| 农村妇女精品一二区| 国内精品视频666| av在线播放中文字幕| 精品久久久久久中文字幕一区奶水 | 欧美激情性爽国产精品17p| 欧美综合在线观看视频| 国产91精品久久久久久久网曝门| jizzjizz日本少妇| 欧美日韩国产麻豆| 国产av无码专区亚洲a∨毛片| 一区二区三区亚洲| 狂野欧美性猛交xxxxx视频| 91久久国产综合久久91精品网站| 久久综合影院| 精品国产av无码一区二区三区| 久久66热re国产| 网站永久看片免费| 在线免费观看视频一区| 五月婷婷综合久久| 久久久中精品2020中文| 91精品国产自产精品男人的天堂| 亚洲一区三区| 久久一综合视频| 久久无码人妻精品一区二区三区 | 一区二区三区在线视频111| 国产女优一区| 制服丝袜第一页在线观看| 亚洲美女在线国产| jizz国产在线| 中文字幕9999| 国产私拍福利精品视频二区| 免费影院在线观看一区| 亚洲精品人人| 18禁裸乳无遮挡啪啪无码免费| 亚洲国产精品一区二区久久| 精品人妻aV中文字幕乱码色欲| xxxxxxxxx欧美| 亚洲3区在线| 欧美 亚洲 视频| 国产精品18久久久久久久久 | 亚洲欧美二区三区| 91丨porny丨在线中文 | 久久99欧美| 国产欧美精品久久| 亚洲久久久久久| 91久久精品日日躁夜夜躁欧美| 久草在现在线| 国产成人一区二区三区小说| 欧洲杯什么时候开赛| 国产男女激情视频| 久久久91精品国产一区二区三区| 一本一本久久a久久综合精品| 2019日韩中文字幕mv| 国产精品一区二区果冻传媒| 极品久久久久久| 日韩一区二区三区在线视频| 欧美日韩经典丝袜| 国产三区精品| 国产精品一二| 一区二区黄色片| 91精品欧美综合在线观看最新| 午夜影院免费在线| 国产一区二区三区色淫影院| 在线亚洲自拍| 国产婷婷精品av在线| 91porny在线| 亚洲欧美日韩精品久久奇米色影视| 欧美电影h版| 一级二级三级欧美| 成人一区二区三区视频| 中日韩黄色大片| 国产亚洲精品91在线| 亚洲国产天堂| 女人喷潮完整视频| 欧美激情一区二区三区四区| 一区二区三区午夜| 欧美高清自拍一区| 国产真实有声精品录音| 久久6免费视频| 欧美丝袜美女中出在线| 日韩黄色影院| 精品一区二区国产| 美国十次了思思久久精品导航| 欧美精品99久久久| 亚洲精品一区久久久久久| 综合欧美亚洲| 91在线视频观看免费|