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

手撕 Golang 高性能內(nèi)存緩存庫 bigcache!

存儲 存儲架構
bigcache 的開發(fā)者是 allegro,是波蘭的一個電商網(wǎng)站,參考資料中給出了他們的技術博客的原文,文中詳細描述了他們問題的背景以及思考,值得研究。

1. 前言

你好哇!我是小翔。之前寫了三篇 #Golang 并發(fā)編程 的文章了,這次來換換口味,開個 手撕源碼 的新坑!一起來扒一扒 Go 語言高性能 local cache 庫 bigcache,看看能不能把開源大佬們的騷操作帶到項目里去裝一裝(?)

2. 為什么要學習開源項目

個人認為學習開源項目的收益:

  • 跟進社區(qū),不做井底之蛙 看到一個開源項目,可以思考下:大佬們最近都在解決哪些問題?他們用到了哪些開源工具?我能拿到項目里用嗎?這玩意有 bug 嗎?要不要提個 issue 或者提個 PR 呢?
  • 面向原理編程 我們在實際項目中會用上很多開源庫/框架,你是否好奇過它們的實現(xiàn)機制呢?理解用到的庫的實現(xiàn)機制,能幫我們避開很多坑,堪稱降維打擊
  • 學習優(yōu)秀的設計 優(yōu)秀的開源項目經(jīng)過了成千上萬開發(fā)者的 review,質量一般會比公司趕進度趕出來的質量高得多得多,從中學習優(yōu)秀的設計,再在實際項目中多用用,同事會感嘆:

3. bigcache 簡介

3.1 本地緩存與分布式緩存

緩存是系統(tǒng)提升并發(fā)能力、降低時延的利器,根據(jù)存儲介質和使用場景,我們一般又會使用本地緩存與分布式緩存兩種手段。本地緩存一般是在進程內(nèi)的,最簡單的,用 go 的 sync.Map 就能實現(xiàn)一個簡單的并發(fā)安全的本地緩存了。常見的,將一些靜態(tài)的、配置類的數(shù)據(jù)放置在本地緩存中,能有效降低到下游存儲的壓力。分布式緩存一般會用 redis 或 memcached 等分布式內(nèi)存數(shù)據(jù)庫來實現(xiàn),能做到分布式、無狀態(tài)。這次先研究下 bigcache 后續(xù)有機會再挖一挖這里。

3.2 bigcache 誕生背景

bigcache 的開發(fā)者是 allegro,是波蘭的一個電商網(wǎng)站,參考資料中給出了他們的技術博客的原文,文中詳細描述了他們問題的背景以及思考,值得研究。他們的需求主要是:

  • 用 HTTP 協(xié)議處理 GET POST 請求,body 不大
  • 10k rps(requests per second) 5k 讀 5k 寫
  • 緩存至少 10 分鐘
  • 低延時:平均 5ms ,P99 < 10ms,P999 < 400ms總結一下,他們需要一個快速、支持過期淘汰、支持 RESTful api 的字典服務

開發(fā)團隊經(jīng)過了一番對比,選擇了 go 語言(高并發(fā)度、帶內(nèi)存管理安全性比 C/C++ 好),拋棄了分布式緩存組件(redis/memcached/couchbase),主要理由是多一跳網(wǎng)絡開銷。這里我表示懷疑,P999 400ms 的時延其實不至于擔心到 redis 網(wǎng)絡那點時間,分布式環(huán)境下 local cache 不同機器間的數(shù)據(jù)不一致帶來的 cache miss 可能更蛋疼。 最終開發(fā)團隊選擇了實現(xiàn)一個支持以下特性的內(nèi)存緩存庫:

  • 百萬級緩存項時響應速度也很快
  • 并發(fā)安全
  • 支持設置過期時間

4. 關鍵設計

4.1 并發(fā)與 sharding

設計上如何做到并發(fā)安全呢?最簡單的思路就是給 map 上一把 sync.RWMutex 即讀寫鎖。然而當緩存項過多時,并發(fā)請求會造成鎖沖突,因此需要降低鎖粒度。bigcache 采用了分布式系統(tǒng)里常用的 sharding 思路,即將一個大 map 拆分成 N 個小 map,我們稱為一個 shard(分片)

如 bigcache.go 的聲明,我們初始化得到的 BigCache,核心實際上是一個 []*cacheShard,緩存的寫入、淘汰等核心邏輯都在 cacheShard 中了

type BigCache struct {
    shards     []*cacheShard
    lifeWindow uint64
    clock      clock
    hash       Hasher
    config     Config
    shardMask  uint64
    close      chan struct{}
}

那么在寫入一個 key value 緩存時,是如何做分片的呢?

func (c *BigCache) Set(key string, entry []byte) error {
    hashedKey := c.hash.Sum64(key)
    shard := c.getShard(hashedKey)
    return shard.set(key, hashedKey, entry)
}

這里會首先進行一次 hash 操作,將 string key hash 到一個 uint64 類型的 key。再根據(jù)這個數(shù)字 key 去做 sharding

func (c *BigCache) getShard(hashedKey uint64) (shard *cacheShard) {
    return c.shards[hashedKey&c.shardMask]
}

這里把取余的操作用位運算來實現(xiàn)了,這也解釋了為什么在使用 bigcache 的時候需要使用 2 的冪來初始化 shard num 了

cache := &BigCache{
    shards:     make([]*cacheShard, config.Shards),
    lifeWindow: uint64(config.LifeWindow.Seconds()),
    clock:      clock,
    hash:       config.Hasher,
    config:     config,
    // config.Shards 必須是 2 的冪
    // 減一后得到一個二進制結果全為 1 的 mask
    shardMask:  uint64(config.Shards - 1),  
    close:      make(chan struct{}),
}

例如使用 1024 作為 shard num 時,mask 值為 1024 - 1 即二進制的 '111111111',使用 num & mask 時,即可獲得 num % mask 的效果

需要注意,這里的 hash 可能是會沖突的,雖然概率極小,當出現(xiàn) hash 沖突時,bigcache 將直接返回結果不存在:

func (s *cacheShard) get(key string, hashedKey uint64) ([]byte, error) {
    s.lock.RLock()
    wrappedEntry, err := s.getWrappedEntry(hashedKey)
    if err != nil {
        s.lock.RUnlock()
        return nil, err
    }
    // 這里會將二進制 buffer 按順序解開
    // 在打包時將 key 打包的作用就體現(xiàn)出來了
    // 如果這次操作的 key 和打包時的 key 不相同
    // 則說明發(fā)生了沖突,不會錯誤地返回另一個 key 的緩存結果
    if entryKey := readKeyFromEntry(wrappedEntry); key != entryKey {
        s.lock.RUnlock()
        s.collision()
        if s.isVerbose {
            s.logger.Printf("Collision detected. Both %q and %q have the same hash %x", key, entryKey, hashedKey)
        }
        return nil, ErrEntryNotFound
    }
    entry := readEntry(wrappedEntry)
    s.lock.RUnlock()
    s.hit(hashedKey)

    return entry, nil
}

4.2 cacheShard 與 bytes queue 設計

bigcache 對每個 shard 使用了一個類似 ringbuffer 的 BytesQueue 結構,定義如下:

type cacheShard struct {
    // hashed key => bytes queue index
    hashmap     map[uint64]uint32
    entries     queue.BytesQueue
    lock        sync.RWMutex
    entryBuffer []byte
    onRemove    onRemoveCallback

    isVerbose    bool
    statsEnabled bool
    logger       Logger
    clock        clock
    lifeWindow   uint64

    hashmapStats map[uint64]uint32
    stats        Stats
}

下圖很好地解釋了 cacheShard 的底層結構~

圖片來自 https://medium.com/codex/our-go-cache-library-choices-406f2662d6b

在處理完 sharding 后,bigcache 會將整個 value 與 key、hashedKey 等信息序列化后存進一個 byte array,這里的設計是不是有點類似網(wǎng)絡協(xié)議里的 header 呢?

// 將整個 entry 打包到當前 shard 的
// byte array 中
w := wrapEntry(currentTimestamp, hashedKey, key, entry, &s.entryBuffer)

func wrapEntry(timestamp uint64, hash uint64, key string, entry []byte, buffer *[]byte) []byte {
    keyLength := len(key)
    blobLength := len(entry) + headersSizeInBytes + keyLength

    if blobLength > len(*buffer) {
        *buffer = make([]byte, blobLength)
    }
    blob := *buffer

    // 小端字節(jié)序
    binary.LittleEndian.PutUint64(blob, timestamp)
    binary.LittleEndian.PutUint64(blob[timestampSizeInBytes:], hash)
    binary.LittleEndian.PutUint16(blob[timestampSizeInBytes+hashSizeInBytes:], uint16(keyLength))
    copy(blob[headersSizeInBytes:], key)
    copy(blob[headersSizeInBytes+keyLength:], entry)

    return blob[:blobLength]
}

這里存原始的 string key,我理解單純是為了處理 hash 沖突用的。

每一個 cacheShard 底層的緩存數(shù)據(jù)都會存儲在 bytes queue 中,即一個 FIFO 的 bytes 隊列,新進入的 entry 都會 push 到末尾,如果空間不足,則會產(chǎn)生內(nèi)存分配的過程,初始的 queue 的大小,是可以在配置中指定的:

func initNewShard(config Config, callback onRemoveCallback, clock clock) *cacheShard {
    // 1. 初始化指定好大小可以減少內(nèi)存分配的次數(shù)
    bytesQueueInitialCapacity := config.initialShardSize() * config.MaxEntrySize
    maximumShardSizeInBytes := config.maximumShardSizeInBytes()
    if maximumShardSizeInBytes > 0 && bytesQueueInitialCapacity > maximumShardSizeInBytes {
        bytesQueueInitialCapacity = maximumShardSizeInBytes
    }
    return &cacheShard{
        hashmap:      make(map[uint64]uint32, config.initialShardSize()),
        hashmapStats: make(map[uint64]uint32, config.initialShardSize()),
        // 2. 初始化 bytes queue,這里用到了上面讀取的配置
        entries:      *queue.NewBytesQueue(bytesQueueInitialCapacity, maximumShardSizeInBytes, config.Verbose),
        entryBuffer:  make([]byte, config.MaxEntrySize+headersSizeInBytes),
        onRemove:     callback,

        isVerbose:    config.Verbose,
        logger:       newLogger(config.Logger),
        clock:        clock,
        lifeWindow:   uint64(config.LifeWindow.Seconds()),
        statsEnabled: config.StatsEnabled,
    }
}

注意到這點,在初始化時使用正確的配置,就能減少重新分配內(nèi)存的次數(shù)了。

4.3 GC 優(yōu)化

bigcache 本質上就是一個大的哈希表,在 go 里,由于 GC STW(Stop the World) 的存在大的哈希表是非常要命的,看看 bigcache 開發(fā)團隊的博客的測試數(shù)據(jù):

With an empty cache, this endpoint had maximum responsiveness latency of 10ms for 10k rps. When the cache was filled, it had more than a second latency for 99th percentile. Metrics indicated that there were over 40 mln objects in the heap and GC mark and scan phase took over four seconds.

緩存塞滿后,堆上有 4 千萬個對象,GC 的掃描過程就超過了 4 秒鐘,這就不能忍了。

主要的優(yōu)化思路有:

  1. offheap(堆外內(nèi)存),GC 只會掃描堆上的對象,那就把對象都搞到棧上去,但是這樣這個緩存庫就高度依賴 offheap 的 malloc 和 free 操作了
  2. 參考 freecache 的思路,用 ringbuffer 存 entry,繞過了 map 里存指針,簡單瞄了一下代碼,后面有空再研究一下(繼續(xù)挖坑
  3. 利用 Go 1.5+ 的特性:

當 map 中的 key 和 value 都是基礎類型時,GC 就不會掃到 map 里的 key 和 value

最終他們采用了 map[uint64]uint32 作為 cacheShard 中的關鍵存儲。key 是 sharding 時得到的 uint64 hashed key,value 則只存 offset ,整體使用 FIFO 的 bytes queue,也符合按照時序淘汰的需求,非常精巧。

經(jīng)過優(yōu)化,bigcache 在 2000w 條記錄下 GC 的表現(xiàn)

go version go version go1.13 linux/arm64

go run caches_gc_overhead_comparison.go Number of entries:  20000000GC pause for bigcache:  22.382827msGC pause for freecache:  41.264651msGC pause for map:  72.236853ms

效果挺明顯,但是對于低延時的服務來說,22ms 的 GC 時間還是很致命的,對象數(shù)還是盡量能控制住比較好。

5. 小結

認真學完 bigcache 的代碼,我們至少有以下幾點收獲:

  • 可以通過 sharding 來降低資源競爭
  • 可以用位運算來取余數(shù)做 sharding (需要是 2 的整數(shù)冪 - 1)
  • 避免 map 中出現(xiàn)指針、使用 go 基礎類型可以顯著降低 GC 壓力、提升性能
  • bigcache 底層存儲是 bytes queue,初始化時設置合理的配置項可以減少 queue 擴容的次數(shù),提升性能

參考資料

  • https://github.com/allegro/bigcache
  • 《allegro.tech blog - Writing a very fast cache service with millions of entries in Go》https://blog.allegro.tech/2016/03/writing-fast-cache-service-in-go.html
  • 《鳥窩 - 妙到顛毫: bigcache優(yōu)化技巧》https://colobu.com/2019/11/18/how-is-the-bigcache-is-fast/
  • 《Stefanie Lai - Our Go Cache Library Choices》https://medium.com/codex/our-go-cache-library-choices-406f2662d6b
  • 《熊喵君的博客 - Golang 高性能 LocalCache:BigCache 設計與分析》https://pandaychen.github.io/2020/03/03/BIGCACHE-ANALYSIS/
  • https://github.com/coocood/freecache
  • https://github.com/glycerine/offheap 堆外內(nèi)存

本文轉載自微信公眾號「 翔叔架構筆記」,可以通過以下二維碼關注。轉載本文請聯(lián)系翔叔架構筆記公眾號。

責任編輯:武曉燕 來源: 翔叔架構筆記
相關推薦

2024-02-26 11:03:05

golang緩存數(shù)據(jù)庫

2021-05-27 10:02:57

Go緩存數(shù)據(jù)

2021-07-15 14:29:06

LRU算法

2021-09-06 08:13:35

APM系統(tǒng)監(jiān)控

2019-01-02 16:50:30

Golang彈幕

2019-01-02 16:47:46

Golang彈幕

2019-01-02 16:38:37

Golang彈幕

2019-04-08 10:09:04

CPU緩存高性能

2014-07-04 10:41:19

redis數(shù)據(jù)庫緩存

2019-03-14 15:38:19

ReactJavascript前端

2022-12-09 08:40:56

高性能內(nèi)存隊列

2011-04-07 09:25:25

內(nèi)存Java

2011-04-25 14:06:23

java

2025-08-18 01:11:00

String類快手C++

2014-04-09 10:50:01

Squid架構緩存服務器

2025-04-07 00:00:00

CaffeineJava數(shù)據(jù)存取

2024-12-03 16:49:58

2020-09-17 14:04:32

拷貝

2020-09-15 08:55:07

算法數(shù)據(jù)基礎

2023-03-13 07:40:44

高并發(fā)golang
點贊
收藏

51CTO技術棧公眾號

97成人资源| 国产一级18片视频| 欧美性aaa| 专区另类欧美日韩| 国产福利久久精品| 日韩xxx高潮hd| 国产成人精品三级高清久久91| 欧美性高清videossexo| 久久久久久久免费视频| 手机在线不卡av| 石原莉奈在线亚洲二区| 久久久精品电影| 国产一卡二卡三卡四卡| 国产 日韩 欧美一区| 亚洲日穴在线视频| 久久手机视频| 夜夜骚av一区二区三区| 在线免费观看欧美| 最近2019好看的中文字幕免费| 日日夜夜精品视频免费观看| 樱花草涩涩www在线播放| 国产精品不卡在线观看| 精品在线一区| 国产麻豆免费观看| 久久久久在线| 欧美高清视频一区二区| 亚洲天堂岛国片| 精品深夜福利视频| 在线播放91灌醉迷j高跟美女 | 亚洲91精品| 亚洲精品wwwww| 三级黄色片免费看| 成人自拍av| 亚洲国产wwwccc36天堂| 在线观看日韩羞羞视频| 嫩草研究院在线观看| 精品综合久久久久久8888| 热re99久久精品国产66热| 亚洲精品91美女久久久久久久| 国产欧美一区二区精品秋霞影院| 欧美国产日韩精品| 欧美aaa级片| 美女视频亚洲色图| 日韩视频一区二区三区在线播放| 91极品尤物在线播放国产| 手机av在线网| 丰满少妇大力进入| 国产精品久久久久久久久久久久久久久久| 日韩视频一区| 欧美乱妇40p| 小泽玛利亚一区| 成人嫩草影院| 亚洲图片欧美日产| 蜜桃av久久久亚洲精品| 日本一级片免费看| 亚洲午夜在线| 欧美激情免费视频| 欧美色图亚洲视频| 97精品视频在线看| 一区二区国产精品视频| 色噜噜日韩精品欧美一区二区| 福利欧美精品在线| 亚洲第一福利视频| www国产视频| 国产精品白丝av嫩草影院| 精品国产网站在线观看| 美女流白浆视频| 9国产精品午夜| 亚洲国产精品久久久久| 久久久久99人妻一区二区三区| 国内精品视频| 日韩美一区二区三区| 亚洲熟女一区二区三区| 粉嫩av一区二区| 亚洲国产97在线精品一区| 中文字幕第3页| 秋霞蜜臀av久久电影网免费| 亚洲精品一区在线观看香蕉 | 国产一区二区三区日韩| **亚洲第一综合导航网站| 国产成年妇视频| 大尺度一区二区| 久久精品美女| av在线播放网站| 中文字幕综合网| 日韩欧美猛交xxxxx无码| 蜜臀av在线播放| 黑人巨大精品欧美一区免费视频 | 无码少妇精品一区二区免费动态| 精品国产日韩欧美| 精品激情国产视频| 免费又黄又爽又色的视频| 亚洲精品社区| 国产精品九九久久久久久久| 国产剧情精品在线| av在线免费不卡| 神马影院午夜我不卡| 成人黄色网址| 欧美日韩免费在线| 成 人 黄 色 小说网站 s色| 奇米一区二区| 亚洲日本中文字幕| 欧美爱爱免费视频| 国产日本精品| 91啪国产在线| 人成免费电影一二三区在线观看| 国产精品久久久久久久岛一牛影视| 干日本少妇视频| 在线免费看h| 欧美高清www午色夜在线视频| 少妇熟女视频一区二区三区| 国产伦精品一区二区三区千人斩| 久久视频在线观看免费| 日韩久久中文字幕| 国内精品国产三级国产a久久 | www.亚洲黄色| 久久久影院官网| 日本特级黄色大片| 亚洲性受xxx喷奶水| 91精品国产免费久久综合| 一本加勒比北条麻妃| 中文字幕一区二区三三| 日本久久久久久久| 亚洲男人第一天堂| 中文字幕在线一区二区三区| 亚洲v国产v在线观看| 国产高清视频色在线www| 91精选在线观看| 精品无人区无码乱码毛片国产| 欧美喷水视频| 成人免费大片黄在线播放| 韩国三级av在线免费观看| 亚洲午夜一区二区三区| 国产精品久久久久久久99| 精品国产中文字幕第一页| 91精品国产色综合久久不卡98口| 国产一区二区三区视频免费观看 | 亚洲欧美激情一区二区| 午夜日韩视频| 欧美日韩激情在线| jlzzjizz在线播放观看| 亚洲精彩视频| 国产在线久久久| av在线播放网站| 色8久久人人97超碰香蕉987| 亚洲久久久久久| 精品国产乱码一区二区三| 午夜精品一二三区| 久久av老司机精品网站导航| 欧美尤物一区| jizz内谢中国亚洲jizz| 亚洲经典中文字幕| 五月婷婷亚洲综合| 91网站在线播放| 日韩国产一级片| 亚洲精品国产av| 成人免费视频视频| 99久久久精品视频| 日韩在线精品强乱中文字幕| 另类图片亚洲另类| 国产露脸无套对白在线播放| 中文字幕精品一区二区精品绿巨人| 情侣黄网站免费看| 精品一区三区| 国产成人一区二区三区小说| 激情五月婷婷六月| 国产精品久久久久久免费观看| 五月丁香综合缴情六月小说| 婷婷激情成人| 久久精品影视伊人网| 一区二区的视频| 自拍偷在线精品自拍偷无码专区| 激情黄色小视频| 精品一区二区三区中文字幕在线| 国产精品久久久久久久久果冻传媒| 夫妻免费无码v看片| 亚洲第一二三区| 国产精品99导航| 日本视频在线播放| 日韩午夜电影av| 久久亚洲AV无码| 99久久精品国产精品久久| 免费在线观看视频a| 亚洲品质自拍| 成人疯狂猛交xxx| 丝袜在线视频| 国产视频综合在线| 一区二区视频免费| 亚洲精品美腿丝袜| 深夜福利日韩在线看| 国产噜噜噜噜久久久久久久久| 国产又黄又粗又长| 一区二区三区加勒比av| 好男人香蕉影院| 日韩中文字幕亚洲一区二区va在线| 亚洲精品无人区| 欧美电影院免费观看| 69av在线播放| 午夜精品久久久久99蜜桃最新版| 激情久久中文字幕| 欧美在线视频二区| 国产精品99久久免费| 欧美激情视频给我| 国产小视频免费在线网址| 欧美精品丝袜久久久中文字幕| 激情视频在线播放| 久久久久国产精品麻豆ai换脸| 中文字幕亚洲影院| 国产精品久久国产愉拍| 欧美 日韩 国产 在线观看| 成人春色在线观看免费网站| 国产精品女主播视频| 24小时免费看片在线观看| 色琪琪综合男人的天堂aⅴ视频| 男人天堂一区二区| 欧美日韩高清在线| 国产成人无码精品亚洲| 专区另类欧美日韩| 国产精品视频白浆免费视频| 亚洲在线播放电影| 1024在线看片你懂得| 国产亚洲精品久久久久久777| av在线免费在线观看| 色偷偷久久一区二区三区| 欧美日韩免费做爰视频| 国产人成亚洲第一网站在线播放| 老女人性生活视频| 蜜臀va亚洲va欧美va天堂| 5252色成人免费视频| 蜜臀久久久久久999| 欧美日韩电影在线播放| 国产精品久久久久久久久久精爆| 亚洲一卡二卡三卡四卡无卡久久 | 国产亚洲精品一区二555| 亚洲欧美另类一区| 91麻豆精品国产91| 一区二区三区午夜| 欧美性猛交xxxxxxxx| 亚洲欧美一区二区三区在线观看| 亚洲v中文字幕| 波多野结衣亚洲色图| 中文字幕日韩一区| 精品国产aaa| 国产日韩欧美在线一区| 黄色在线观看av| 国产成人免费视频| 国产成人强伦免费视频网站| 久久99这里只有精品| 中文字幕第100页| 蜜桃av噜噜一区二区三区小说| 成人免费无码av| 日韩有码一区二区三区| 久久久免费视频网站| 另类天堂av| 欧美黄色一级片视频| 久久久久国产精品一区二区| 国产在线观看福利| 久久青草久久| 五月天婷婷激情视频| 青青草97国产精品免费观看无弹窗版| 可以在线看的黄色网址| 久久午夜精品一区二区| 久久九九国产视频| 日韩国产欧美在线观看| 男女污污的视频| 麻豆精品一二三| www.国产福利| 国产成人免费在线视频| 国产高清成人久久| 久久影院午夜论| 国产精品久久久久久久av| 国产精品久久免费看| 午夜激情福利网| 亚洲综合图片区| 成年免费在线观看| 在线观看精品一区| 91在线观看喷潮| 精品久久久久久综合日本欧美| 深爱五月激情五月| 亚洲午夜精品视频| 激情在线小视频| 久久久久久久久久久免费精品 | 国产精品99久久久久久人 | 色影院视频在线| 久久夜色精品国产亚洲aⅴ| 女子免费在线观看视频www| **欧美日韩vr在线| 日韩免费在线电影| 国产精品乱子乱xxxx| 中国av一区| 一本—道久久a久久精品蜜桃| 国产精品黄色| 国产97色在线 | 日韩| 国产伦精品一区二区三区免费| 91九色蝌蚪porny| 国产欧美精品一区| 免费中文字幕在线观看| 在线视频一区二区三| 国产av无码专区亚洲av| 亚洲男人天堂2024| a级网站在线播放| 欧洲亚洲免费视频| 欧美日韩黄色| 日本不卡在线观看| 国自产拍偷拍福利精品免费一| 男女av免费观看| 国产乱淫av一区二区三区| 少妇精品一区二区| 国产精品成人午夜| 欧美成人一区二区三区四区| 欧美一区二区视频在线观看2020 | 国产精品一区免费在线观看| 亚洲高清一区二区三区| 亚洲精品在线视频播放| 99re视频精品| 国产一区二区精彩视频| 欧美色播在线播放| 国产夫妻自拍av| 亚洲人成在线播放| 福利在线导航136| 国产综合香蕉五月婷在线| 日韩有码av| 伊人天天久久大香线蕉av色| 国产丝袜在线播放| 国产精品av在线播放| 国产精品极品国产中出| 国产成年人在线观看| 首页欧美精品中文字幕| 人妻 日韩 欧美 综合 制服| ㊣最新国产の精品bt伙计久久| 日本黄色中文字幕| 亚洲精品99久久久久| 男人添女人下部高潮视频在线观看| 国产精品一区二区三区毛片淫片| 亚洲精品合集| 男女猛烈激情xx00免费视频| 国产91精品久久久久久久网曝门| 永久免费看片视频教学| 欧美视频你懂的| 国产精品四虎| 国产97在线视频| 蜜桃视频欧美| 大j8黑人w巨大888a片| 成人免费精品视频| 久久久国产精品人人片| 91精品麻豆日日躁夜夜躁| 色影视在线观看| 成人精品久久一区二区三区| 日韩欧美大片| 亚洲精选在线观看| 妞干网视频在线观看| 综合在线视频| 中文字幕视频三区| 国产精品免费丝袜| 在线播放亚洲精品| 色吧影院999| 青娱乐极品盛宴一区二区| 午夜视频久久久| 美女mm1313爽爽久久久蜜臀| 在线观看天堂av| 欧美精品乱码久久久久久| 国内精品久久久久久久久久久 | 伊人网在线视频观看| 色94色欧美sute亚洲线路一久| 美女做暖暖视频免费在线观看全部网址91| 2019中文字幕在线观看| 伊人久久大香线蕉综合网站 | 免费成人av资源网| 国产一区在线观看免费| 91精品国产综合久久蜜臀| 91cn在线观看| 好吊色欧美一区二区三区四区 | 亚洲性图久久| 国内成人精品视频| 深夜在线视频| 欧美日韩电影一区二区| 日本视频一区二区三区| 二区三区四区视频| 日韩视频免费观看高清在线视频| 四虎影院观看视频在线观看| 国产不卡一区二区三区在线观看 | 霍思燕三级露全乳照| 99久久精品免费看国产免费软件| 亚洲熟妇无码乱子av电影| 色悠悠久久久久| 亚洲精品18| 97成人在线观看视频| 国产精品久久久久天堂| 极品人妻一区二区| 综合激情网...| 色在人av网站天堂精品| 亚洲综合网站| 中文字幕无码不卡免费视频| 中文子幕无线码一区tr| 精品人妻一区二区三区蜜桃 | 日韩高清不卡一区二区三区| 国产激情无码一区二区三区| 精品精品欲导航| 中文另类视频| 国产91沈先生在线播放|