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

動手實(shí)現(xiàn)一個Localcache-實(shí)現(xiàn)篇

開發(fā) 前端
使用二維數(shù)組存儲數(shù)據(jù)的相比于bigcache的優(yōu)勢在于可以直接根據(jù)索引刪除對應(yīng)的數(shù)據(jù),雖然也會有蟲洞的問題,但是我們可以記錄下來蟲洞的索引,不斷填充。

前言

哈嘍,大家好,我是asong,經(jīng)過了前面兩篇的介紹,我們已經(jīng)基本了解該如何設(shè)計一個本地緩存了,本文就是這個系列的終結(jié)篇,自己動手實(shí)現(xiàn)一個本地緩存,接下來且聽我細(xì)細(xì)道來!!!

本文代碼已經(jīng)上傳到github:https://github.com/asong2020/go-localcache

現(xiàn)在這一版本算是一個1.0,后續(xù)會繼續(xù)進(jìn)行優(yōu)化和迭代。

第一步:抽象接口

第一步很重要,以面向接口編程為原則,我們先抽象出來要暴露給用戶的方法,給用戶提供簡單易懂的方法,因此我抽象出來的結(jié)果如下:

  1. // ICache abstract interface 
  2. type ICache interface { 
  3.  // Set value use default expire timedefault does not expire. 
  4.  Set(key string, value []byte) error 
  5.  // Get value if find it. if value already expire will delete
  6.  Get(key string) ([]byte, error) 
  7.  // SetWithTime set value with expire time 
  8.  SetWithTime(key string, value []byte, expired time.Duration) error 
  9.  // Delete manual removes the key 
  10.  Delete(key string) error 
  11.  // Len computes number of entries in cache 
  12.  Len() int 
  13.  // Capacity returns amount of bytes store in the cache. 
  14.  Capacity() int 
  15.  // Close is used to signal a shutdown of the cache when you are done with it. 
  16.  // This allows the cleaning goroutines to exit and ensures references are not 
  17.  // kept to the cache preventing GC of the entire cache. 
  18.  Close() error 
  19.  // Stats returns cache's statistics 
  20.  Stats() Stats 
  21.  // GetKeyHit returns key hit 
  22.  GetKeyHit(key string) int64 
  • Set(key string, value []byte):使用該方法存儲的數(shù)據(jù)使用默認(rèn)的過期時間,如果清除過期的異步任務(wù)沒有enable,那么就永不過期,否則默認(rèn)過期時間為10min。
  • Get(key string) ([]byte, error):根據(jù)key獲取對象內(nèi)容,如果數(shù)據(jù)過期了會在這一步刪除。
  • SetWithTime(key string, value []byte, expired time.Duration):存儲對象是使用自定義過期時間
  • Delete(key string) error:根據(jù)key刪除對應(yīng)的緩存數(shù)據(jù)
  • Len() int:獲取緩存的對象數(shù)量
  • Capacity() int:獲取當(dāng)前緩存的容量
  • Close() error:關(guān)閉緩存
  • Stats() Stats:緩存監(jiān)控數(shù)據(jù)
  • GetKeyHit(key string) int64:獲取key的命中率數(shù)據(jù)

第二步:定義緩存對象

第一步我們抽象好了接口,下面就要定義一個緩存對象實(shí)例實(shí)現(xiàn)接口,先看定義結(jié)構(gòu):

  1. type cache struct { 
  2.  // hashFunc represents used hash func 
  3.  hashFunc HashFunc 
  4.  // bucketCount represents the number of segments within a cache instance. value must be a power of two. 
  5.  bucketCount uint64 
  6.  // bucketMask is bitwise AND applied to the hashVal to find the segment id. 
  7.  bucketMask uint64 
  8.  // segment is shard 
  9.  segments []*segment 
  10.  // segment lock 
  11.  locks    []sync.RWMutex 
  12.  // close cache 
  13.  close chan struct{} 
  • hashFunc:分片要用的哈希函數(shù),用戶可以自行定義,實(shí)現(xiàn)HashFunc接口即可,默認(rèn)使用fnv算法。
  • bucketCount:分片的數(shù)量,一定要是偶數(shù),默認(rèn)分片數(shù)為256。
  • bucketMask:因?yàn)榉制瑪?shù)是偶數(shù),所以可以分片時可以使用位運(yùn)算代替取余提升性能效率,hashValue % bucketCount == hashValue & bucketCount - 1。
  • segments:分片對象,每個分片的對象結(jié)構(gòu)我們在后面介紹。
  • locks:每個分片的讀寫鎖
  • close:關(guān)閉緩存對象時通知其他goroutine暫停

接下來我們來寫cache對象的構(gòu)造函數(shù):

  1. // NewCache constructor cache instance 
  2. func NewCache(opts ...Opt) (ICache, error) { 
  3.  options := &options{ 
  4.   hashFunc: NewDefaultHashFunc(), 
  5.   bucketCount: defaultBucketCount, 
  6.   maxBytes: defaultMaxBytes, 
  7.   cleanTime: defaultCleanTIme, 
  8.   statsEnabled: defaultStatsEnabled, 
  9.   cleanupEnabled: defaultCleanupEnabled, 
  10.  } 
  11.  for _, each := range opts{ 
  12.   each(options) 
  13.  } 
  14.  
  15.  if !isPowerOfTwo(options.bucketCount){ 
  16.   return nil, errShardCount 
  17.  } 
  18.  
  19.   if options.maxBytes <= 0 { 
  20.   return nil, ErrBytes 
  21.  } 
  22.    
  23.  segments := make([]*segment, options.bucketCount) 
  24.  locks := make([]sync.RWMutex, options.bucketCount) 
  25.  
  26.  maxSegmentBytes := (options.maxBytes + options.bucketCount - 1) / options.bucketCount 
  27.  for index := range segments{ 
  28.   segments[index] = newSegment(maxSegmentBytes, options.statsEnabled) 
  29.  } 
  30.  
  31.  c := &cache{ 
  32.   hashFunc: options.hashFunc, 
  33.   bucketCount: options.bucketCount, 
  34.   bucketMask: options.bucketCount - 1, 
  35.   segments: segments, 
  36.   locks: locks, 
  37.   close: make(chan struct{}), 
  38.  } 
  39.     if options.cleanupEnabled { 
  40.   go c.cleanup(options.cleanTime) 
  41.  } 
  42.   
  43.  return c, nil 

這里為了更好的擴(kuò)展,我們使用Options編程模式,我們的構(gòu)造函數(shù)主要做三件事:

  • 前置參數(shù)檢查,對于外部傳入的參數(shù),我們還是要做基本的校驗(yàn)
  • 分片對象初始化
  • 構(gòu)造緩存對象

這里構(gòu)造緩存對象時我們要先計算每個分片的容量,默認(rèn)整個本地緩存256M的數(shù)據(jù),然后在平均分到每一片區(qū)內(nèi),用戶可以自行選擇要緩存的數(shù)據(jù)大小。

第三步:定義分片結(jié)構(gòu)

每個分片結(jié)構(gòu)如下:

  1. type segment struct { 
  2.  hashmap map[uint64]uint32 
  3.  entries buffer.IBuffer 
  4.  clock   clock 
  5.  evictList  *list.List 
  6.  stats IStats 
  • hashmp:存儲key所對應(yīng)的存儲索引
  • entries:存儲key/value的底層結(jié)構(gòu),我們在第四步的時候介紹,也是代碼的核心部分。
  • clock:定義時間方法
  • evicList:這里我們使用一個隊列來記錄old索引,當(dāng)容量不足時進(jìn)行刪除(臨時解決方案,當(dāng)前存儲結(jié)構(gòu)不適合使用LRU淘汰算法)
  • stats:緩存的監(jiān)控數(shù)據(jù)。

接下來我們再來看一下每個分片的構(gòu)造函數(shù):

  1. func newSegment(bytes uint64, statsEnabled bool) *segment { 
  2.  if bytes == 0 { 
  3.   panic(fmt.Errorf("bytes cannot be zero")) 
  4.  } 
  5.  if bytes >= maxSegmentSize{ 
  6.   panic(fmt.Errorf("too big bytes=%d; should be smaller than %d", bytes, maxSegmentSize)) 
  7.  } 
  8.  capacity := (bytes + segmentSize - 1) / segmentSize 
  9.  entries := buffer.NewBuffer(int(capacity)) 
  10.  entries.Reset() 
  11.  return &segment{ 
  12.   entries: entries, 
  13.   hashmap: make(map[uint64]uint32), 
  14.   clock:   &systemClock{}, 
  15.   evictList: list.New(), 
  16.   stats: newStats(statsEnabled), 
  17.  } 

這里主要注意一點(diǎn):

我們要根據(jù)每個片區(qū)的緩存數(shù)據(jù)大小來計算出容量,與上文的緩存對象初始化步驟對應(yīng)上了。

第四步:定義緩存結(jié)構(gòu)

緩存對象現(xiàn)在也構(gòu)造好了,接下來就是本地緩存的核心:定義緩存結(jié)構(gòu)。

bigcache、fastcache、freecache都使用字節(jié)數(shù)組代替map存儲緩存數(shù)據(jù),從而減少GC壓力,所以我們也可以借鑒其思想繼續(xù)保持使用字節(jié)數(shù)組,這里我們使用二維字節(jié)切片存儲緩存數(shù)據(jù)key/value;畫個圖表示一下:

使用二維數(shù)組存儲數(shù)據(jù)的相比于bigcache的優(yōu)勢在于可以直接根據(jù)索引刪除對應(yīng)的數(shù)據(jù),雖然也會有蟲洞的問題,但是我們可以記錄下來蟲洞的索引,不斷填充。

每個緩存的封裝結(jié)構(gòu)如下:

基本思想已經(jīng)明確,接下來看一下我們對存儲層的封裝:

  1. type Buffer struct { 
  2.  array [][]byte 
  3.  capacity int 
  4.  index int 
  5.  // maxCount = capacity - 1 
  6.  count int 
  7.  // availableSpace If any objects are removed after the buffer is full, the idle index is logged. 
  8.  // Avoid array "wormhole" 
  9.  availableSpace map[int]struct{} 
  10.  // placeholder record the index that buffer has stored. 
  11.  placeholder map[int]struct{} 
  • array [][]byte:存儲緩存對象的二維切片
  • capacity:緩存結(jié)構(gòu)的最大容量
  • index:索引,記錄緩存所在的位置的索引
  • count:記錄緩存數(shù)量
  • availableSpace:記錄"蟲洞",當(dāng)緩存對象被刪除時記錄下空閑位置的索引,方便后面容量滿了后使用"蟲洞"
  • placeholder:記錄緩存對象的索引,迭代清除過期緩存可以用上。

向buffer寫入數(shù)據(jù)的流程(不貼代碼了):

第五步:完善向緩存寫入數(shù)據(jù)方法

上面我們定義好了所有需要的結(jié)構(gòu),接下來就是填充我們的寫入緩存方法就可以了:

  1. func (c *cache) Set(key string, value []byte) error  { 
  2.  hashKey := c.hashFunc.Sum64(key
  3.  bucketIndex := hashKey&c.bucketMask 
  4.  c.locks[bucketIndex].Lock() 
  5.  defer c.locks[bucketIndex].Unlock() 
  6.  err := c.segments[bucketIndex].set(key, hashKey, value, defaultExpireTime) 
  7.  return err 
  8.  
  9. func (s *segment) set(key string, hashKey uint64, value []byte, expireTime time.Duration) error { 
  10.  if expireTime <= 0{ 
  11.   return ErrExpireTimeInvalid 
  12.  } 
  13.  expireAt := uint64(s.clock.Epoch(expireTime)) 
  14.  
  15.  if previousIndex, ok := s.hashmap[hashKey]; ok { 
  16.   if err := s.entries.Remove(int(previousIndex)); err != nil{ 
  17.    return err 
  18.   } 
  19.   delete(s.hashmap, hashKey) 
  20.  } 
  21.  
  22.  entry := wrapEntry(expireAt, key, hashKey, value) 
  23.  for { 
  24.   index, err := s.entries.Push(entry) 
  25.   if err == nil { 
  26.    s.hashmap[hashKey] = uint32(index
  27.    s.evictList.PushFront(index
  28.    return nil 
  29.   } 
  30.   ele := s.evictList.Back() 
  31.   if err := s.entries.Remove(ele.Value.(int)); err != nil{ 
  32.    return err 
  33.   } 
  34.   s.evictList.Remove(ele) 
  35.  } 

流程分析如下:

根據(jù)key計算哈希值,然后根據(jù)分片數(shù)獲取對應(yīng)分片位置

如果當(dāng)前緩存中存在相同的key,則先刪除,在重新插入,會刷新過期時間

封裝存儲結(jié)構(gòu),根據(jù)過期時間戳、key長度、哈希大小、緩存對象進(jìn)行封裝

將數(shù)據(jù)存入緩存,如果緩存失敗,移除最老的數(shù)據(jù)后再次重試

第六步:完善從緩存讀取數(shù)據(jù)方法

第一步根據(jù)key計算哈希值,再根據(jù)分片數(shù)獲取對應(yīng)的分片位置:

  1. func (c *cache) Get(key string) ([]byte, error)  { 
  2.  hashKey := c.hashFunc.Sum64(key
  3.  bucketIndex := hashKey&c.bucketMask 
  4.  c.locks[bucketIndex].RLock() 
  5.  defer c.locks[hashKey&c.bucketMask].RUnlock() 
  6.  entry, err := c.segments[bucketIndex].get(key, hashKey) 
  7.  if err != nil{ 
  8.   return nil, err 
  9.  } 
  10.  return entry,nil 

第二步執(zhí)行分片方法獲取緩存數(shù)據(jù):

  • 先根據(jù)哈希值判斷key是否存在于緩存中,不存返回key沒有找到
  • 從緩存中讀取數(shù)據(jù)得到緩存中的key判斷是否發(fā)生哈希沖突
  • 判斷緩存對象是否過期,過期刪除緩存數(shù)據(jù)(可以根據(jù)業(yè)務(wù)優(yōu)化需要是否返回當(dāng)前過期數(shù)據(jù))
  • 在每個記錄緩存監(jiān)控數(shù)據(jù)
  1. func (s *segment) getWarpEntry(key string, hashKey uint64) ([]byte,error) { 
  2.  index, ok := s.hashmap[hashKey] 
  3.  if !ok { 
  4.   s.stats.miss() 
  5.   return nil, ErrEntryNotFound 
  6.  } 
  7.  entry, err := s.entries.Get(int(index)) 
  8.  if err != nil{ 
  9.   s.stats.miss() 
  10.   return nil, err 
  11.  } 
  12.  if entry == nil{ 
  13.   s.stats.miss() 
  14.   return nil, ErrEntryNotFound 
  15.  } 
  16.  
  17.  if entryKey := readKeyFromEntry(entry); key != entryKey { 
  18.   s.stats.collision() 
  19.   return nil, ErrEntryNotFound 
  20.  } 
  21.  return entry, nil 
  22.  
  23. func (s *segment) get(key string, hashKey uint64) ([]byte, error) { 
  24.  currentTimestamp := s.clock.TimeStamp() 
  25.  entry, err := s.getWarpEntry(key, hashKey) 
  26.  if err != nil{ 
  27.   return nil, err 
  28.  } 
  29.  res := readEntry(entry) 
  30.  
  31.  expireAt := int64(readExpireAtFromEntry(entry)) 
  32.  if currentTimestamp - expireAt >= 0{ 
  33.   _ = s.entries.Remove(int(s.hashmap[hashKey])) 
  34.   delete(s.hashmap, hashKey) 
  35.   return nil, ErrEntryNotFound 
  36.  } 
  37.  s.stats.hit(key
  38.  
  39.  return res, nil 

第七步:來個測試用例體驗(yàn)一下

先來個簡單的測試用例測試一下:

  1. func (h *cacheTestSuite) TestSetAndGet() { 
  2.  cache, err := NewCache() 
  3.  assert.Equal(h.T(), nil, err) 
  4.  key := "asong" 
  5.  value := []byte("公眾號:Golang夢工廠"
  6.  
  7.  err = cache.Set(key, value) 
  8.  assert.Equal(h.T(), nil, err) 
  9.  
  10.  res, err := cache.Get(key
  11.  assert.Equal(h.T(), nil, err) 
  12.  assert.Equal(h.T(), value, res) 
  13.  h.T().Logf("get value is %s", string(res)) 

運(yùn)行結(jié)果:

  1. === RUN   TestCacheTestSuite 
  2. === RUN   TestCacheTestSuite/TestSetAndGet 
  3.     cache_test.go:33: get value is 公眾號:Golang夢工廠 
  4. --- PASS: TestCacheTestSuite (0.00s) 
  5.     --- PASS: TestCacheTestSuite/TestSetAndGet (0.00s) 
  6. PASS 

大功告成,基本功能通了,剩下就是跑基準(zhǔn)測試、優(yōu)化、迭代了(不在文章贅述了,可以關(guān)注github倉庫最新動態(tài))。

參考文章

  • https://github.com/allegro/bigcache
  • https://github.com/VictoriaMetrics/fastcache
  • https://github.com/coocood/freecache
  • https://github.com/patrickmn/go-cache

總結(jié)

實(shí)現(xiàn)篇到這里就結(jié)束了,但是這個項(xiàng)目的編碼仍未結(jié)束,我會繼續(xù)以此版本為基礎(chǔ)不斷迭代優(yōu)化,該本地緩存的優(yōu)點(diǎn):

  • 實(shí)現(xiàn)簡單、提供給用戶的方法簡單易懂
  • 使用二維切片作為存儲結(jié)構(gòu),避免了不能刪除底層數(shù)據(jù)的缺點(diǎn),也在一定程度上避免了"蟲洞"問題。
  • 測試用例齊全,適合作為小白的入門項(xiàng)目

待優(yōu)化點(diǎn):

  • 沒有使用高效的緩存淘汰算法,可能會導(dǎo)致熱點(diǎn)數(shù)據(jù)被頻繁刪除
  • 定時刪除過期數(shù)據(jù)會導(dǎo)致鎖持有時間過長,需要優(yōu)化
  • 關(guān)閉緩存實(shí)例需要優(yōu)化處理方式
  • 根據(jù)業(yè)務(wù)場景進(jìn)行優(yōu)化(特定業(yè)務(wù)場景)

迭代點(diǎn):

  • 添加異步加載緩存功能
  • ...... (思考中)

本文代碼已經(jīng)上傳到github:https://github.com/asong2020/go-localcache

 

好啦,本文到這里就結(jié)束了,我是asong,我們下期見。

 

責(zé)任編輯:武曉燕 來源: Golang夢工廠
相關(guān)推薦

2021-12-08 07:31:40

設(shè)計Localcache緩存

2024-12-06 09:58:09

2017-02-14 10:20:43

Java Class解析器

2021-09-07 07:34:42

CSS 技巧代碼重構(gòu)

2021-08-21 15:40:24

CPU計算機(jī)電子領(lǐng)域

2023-10-10 13:28:44

Pythonpygame

2022-07-13 15:31:29

手繪板canvas鴻蒙

2020-09-24 11:46:03

Promise

2022-08-02 14:21:20

滑動驗(yàn)證碼鴻蒙

2022-07-28 14:20:44

懸浮球鴻蒙

2017-12-12 15:24:32

Web Server單線程實(shí)現(xiàn)

2015-08-25 14:25:54

objc_msgsen

2017-03-02 13:31:02

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

2011-07-20 10:02:01

Xcode cocoa 窗口

2023-02-26 01:37:57

goORM代碼

2023-05-22 09:10:53

CSSloading 效

2023-03-01 09:39:40

調(diào)度系統(tǒng)

2011-03-28 09:56:03

存儲增刪操作

2022-08-01 14:07:26

canvas繪畫板

2022-11-29 17:34:43

虛擬形象系統(tǒng)
點(diǎn)贊
收藏

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

欧美日韩高清在线观看| 色综合久久久久综合体桃花网| 成人激情综合网| 欧美卡一卡二卡三| 国产精品巨作av| 欧美丝袜一区二区| 亚洲欧美综合一区| 午夜精品久久久久久久99老熟妇| 国产欧美日本| www.日韩视频| 日本黄色免费观看| 中文字幕在线看片| 久久久久9999亚洲精品| 国产中文字幕亚洲| 国产精品乱子伦| 66视频精品| 亚洲欧洲高清在线| 超碰影院在线观看| 日本美女在线中文版| 北条麻妃一区二区三区| 国产精品久久久久久影视| 免费毛片一区二区三区| 日韩专区精品| 亚洲精品视频在线观看视频| www.日本久久| www.一区| 欧美午夜精品在线| 日韩精品一区二区在线视频| 91露出在线| 久久网站最新地址| 国产免费一区| 99热这里只有精品5| 日本不卡在线视频| 日本精品视频在线观看| 福利一区二区三区四区| 在线看片不卡| xxx欧美精品| 国产肥白大熟妇bbbb视频| 99re热精品视频| 91精品国产欧美一区二区成人 | 欧美18一19xxx性| 91麻豆福利精品推荐| 国产经品一区二区| www.久久伊人| 国产精品综合在线视频| 91精品国产综合久久男男| 国模私拍一区二区| 视频一区二区欧美| 情事1991在线| 免费观看一区二区三区毛片| 伊人久久综合| 海角国产乱辈乱精品视频| 欧美日韩在线视频免费播放| 一区二区三区国产精华| 日韩中文字幕在线精品| 91ts人妖另类精品系列| 91中文字幕精品永久在线| 中文字幕在线精品| 手机看片福利视频| 欧美日韩精品一区二区视频| 亚洲欧美制服第一页| 国产中文字幕一区二区| 亚洲国产国产| 亚洲无av在线中文字幕| 女人黄色一级片| 久久视频精品| 久久久国产91| 妺妺窝人体色www在线下载| 国产一区久久| 97久久超碰福利国产精品…| 精品人妻无码一区二区性色| 久久一综合视频| 国产精品香蕉在线观看| 99国产精品久久久久99打野战| 国内精品不卡在线| 国产 高清 精品 在线 a| 性插视频在线观看| 国产欧美日韩精品一区| 在线国产精品网| 怡红院在线播放| 调教+趴+乳夹+国产+精品| 免费无码av片在线观看| 精品美女一区| 欧美成人猛片aaaaaaa| 变态另类丨国产精品| 经典一区二区| 久久av在线播放| 日韩精品一区二区av| 久久亚洲不卡| 91亚洲永久免费精品| 四虎免费在线观看| 国产精品免费免费| 欧美一级免费播放| 成人国产一区二区三区精品麻豆| 91精品国产麻豆国产自产在线| 91超薄肉色丝袜交足高跟凉鞋| 亚洲综合福利| 久久国产精品久久久久| 色av性av丰满av| 国产乱子伦视频一区二区三区 | 91免费综合在线| 成人午夜免费福利| 国产网红主播福利一区二区| 国产一区一区三区| 国模套图日韩精品一区二区| 9191精品国产综合久久久久久| 中文字幕人妻一区二区三区| 欧美日韩中字| 91精品国产免费久久久久久| 一级黄色小视频| 久久综合视频网| 看一级黄色录像| 日本一区二区三区视频在线| 精品成a人在线观看| 国产精品久久国产精麻豆96堂| 亚洲精品四区| 91精品久久久久久蜜桃| www.在线视频.com| 精品美女久久久久久免费| 婷婷中文字幕在线观看| 精品视频国产| 欧美中文字幕精品| 人妻视频一区二区三区| 亚洲精品视频在线观看免费| 污污的网站18| 国产精品手机在线播放| 97久久精品在线| 丰满人妻妇伦又伦精品国产| 亚洲欧美另类图片小说| 一区二区三区视频在线观看免费| 久久久久观看| 久久久伊人欧美| 精品国产18久久久久久| 国产精品久久久久久久裸模| 99色精品视频| 美女少妇全过程你懂的久久| 91精品国产免费久久久久久 | 亚洲人成毛片在线播放| 国产成人亚洲欧洲在线| 丁香天五香天堂综合| 青青草免费在线视频观看| 久久爱.com| 伊人伊人伊人久久| 日本欧美www| 日本一区二区三区国色天香| 超碰影院在线观看| 国内亚洲精品| 国产精品xxx视频| 国产日产精品久久久久久婷婷| 日韩欧美亚洲成人| 亚洲AV无码国产成人久久| 亚欧美中日韩视频| 欧美一区激情视频在线观看| 欧美7777| 色综久久综合桃花网| 亚洲最大成人在线视频| 亚洲同性同志一二三专区| 日本网站在线看| 欧美日韩伊人| 精品久久一区二区三区蜜桃| 国产美女精品写真福利视频| 精品网站999www| 国产精品久久久久久人| 国产日产欧美一区| 美女网站色免费| 天天色综合色| 成人xxxxx色| 男女羞羞在线观看| 国产性猛交xxxx免费看久久| 91精品国自产| 一区二区三区精品视频在线| 午夜视频在线观看国产| 男人的天堂亚洲| 亚洲精品国产精品国自产观看 | 91精品国产色综合久久| 国产一级特黄a高潮片| 97精品电影院| 色片在线免费观看| 欧美va天堂在线| 久久久久久a亚洲欧洲aⅴ| 日本综合视频| 欧美大成色www永久网站婷| 色欲av永久无码精品无码蜜桃| 在线日韩一区二区| 顶臀精品视频www| 91丝袜呻吟高潮美腿白嫩在线观看| 欧美精品第三页| 一区二区三区四区日韩| 久久国产精品 国产精品| 成人黄色免费网站| 久久久久久久影院| 69xxxx欧美| 亚洲精品www| 一级黄色大片免费观看| 午夜精品在线看| 在线免费看视频| 成人avav影音| 国产无色aaa| 亚洲欧美日韩国产| www亚洲国产| 国产精品欧美三级在线观看| 999久久久| se69色成人网wwwsex| 欧美激情亚洲自拍| 最新97超碰在线| 日韩成人av一区| 国产黄色美女视频| 欧美日韩在线播放三区| 久久国产视频播放| 樱花影视一区二区| 久久精品色妇熟妇丰满人妻| 91免费国产在线| 国产精品二区视频| 蜜桃精品视频在线| 成人综合视频在线| 狠狠色综合网| 国产又爽又黄ai换脸| 久久最新网址| 国严精品久久久久久亚洲影视| 不卡的国产精品| 国产精品aaa| 中国字幕a在线看韩国电影| 久久国产精品影片| 免费黄色网页在线观看| 在线成人一区二区| 男女污视频在线观看| 亚洲第一福利在线观看| www国产在线| 777a∨成人精品桃花网| 自拍偷拍第八页| 色婷婷av一区| 五月婷婷中文字幕| 福利视频第一区| 国产精品成人av久久| 亚洲综合色噜噜狠狠| 欧美成人精品一区二区免费看片| 国产精品女人毛片| av黄色在线免费观看| 久久视频一区二区| 9.1成人看片| 91视频在线观看免费| 懂色av粉嫩av蜜乳av| 久久综合九色综合久久久精品综合| 最新日本中文字幕| 成人黄色一级视频| 捆绑凌虐一区二区三区| 91网站在线观看视频| 精品中文字幕在线播放| 99re热这里只有精品免费视频| 久久性爱视频网站| caoporen国产精品视频| 欧美黑人欧美精品刺激| 久久久久久久久99精品| 午夜在线观看一区| 日本一区二区三区在线观看| 中文天堂资源在线| 中文字幕在线视频一区| 欧美黄色aaa| 一区二区三区四区不卡在线| 久久久久性色av无码一区二区| 亚洲国产欧美在线人成| 免费日韩一级片| 色综合天天综合给合国产| 五月婷婷六月婷婷| 欧美日韩国产一级| 99热这里只有精品5| 亚洲国产天堂久久综合| 九色视频在线播放| 日韩视频精品在线| 黑人极品ⅴideos精品欧美棵| 91精品国产亚洲| 性欧美1819sex性高清| 国产色视频一区| 天堂va在线高清一区| 噜噜噜噜噜久久久久久91| 精品久久成人| 裸体裸乳免费看| 亚洲三级网站| 天天插天天操天天射| 国产不卡在线视频| av在线网站观看| 1区2区3区精品视频| 免看一级a毛片一片成人不卡| 欧美日韩中文字幕在线视频| 中文字幕在线网站| 精品国产乱码久久久久久老虎 | 动漫av一区| 欧美精品久久| 亚洲五月综合| 茄子视频成人免费观看| 激情成人综合网| 中文字幕丰满孑伦无码专区| 一区在线观看免费| 国产情侣自拍av| 欧美一区二区三区视频免费播放| 日本精品久久久久久| 日韩中文字幕视频| 天堂av在线| 99re视频在线| 99九九热只有国产精品| 久久精品国产精品亚洲色婷婷| 国内精品伊人久久久久av影院| 少妇精品一区二区| 亚洲人成精品久久久久| av片免费观看| 亚洲国产高潮在线观看| 麻豆av在线导航| 欧美中文字幕在线| 欧美成年网站| 亚洲国产精品一区二区第四页av| 最新国产乱人伦偷精品免费网站| 日日干夜夜操s8| 久久久五月婷婷| 日本熟妇乱子伦xxxx| 91麻豆精品国产91久久久久久久久 | 国产亚洲精品bv在线观看| 五月天六月丁香| 国产精品天美传媒沈樵| 久久国产精品免费看| 日韩女同互慰一区二区| 免费在线看黄色| 国产精品九九九| 尤物tv在线精品| 国产白丝袜美女久久久久| 国产精品一品视频| 色欲一区二区三区精品a片| 91黄视频在线| 你懂的免费在线观看| 91精品国产91久久久久久不卡| 欧美成人一级| 国产高清免费在线| 久久99精品国产麻豆婷婷洗澡| 99在线视频免费| 色激情天天射综合网| 青青青免费视频在线2| 久久久久这里只有精品| 国产精品成人**免费视频| 亚洲资源在线网| 麻豆一区二区三区| 青青青视频在线播放| 欧美综合天天夜夜久久| 国产在线视频网| 国产激情999| 国产欧美日韩| 99视频免费播放| 国产欧美日韩另类视频免费观看| 青青国产在线视频| 一区二区欧美久久| 高清欧美日韩| 热这里只有精品| 国产乱码精品一区二区三区忘忧草| 亚洲天堂一级片| 日韩一级完整毛片| 九色91在线| 国外成人在线视频网站| 国产精品日本欧美一区二区三区| 国产精品无码网站| 91国在线观看| 色开心亚洲综合| 91久久国产综合久久蜜月精品| 国内精品久久久久久久97牛牛| 亚洲美女在线播放| 精品美女久久久久久免费| 黄色网址在线播放| 国产综合久久久久| 一二三区不卡| 日本国产在线视频| 色综合久久久网| 成人无遮挡免费网站视频在线观看| 91久久精品久久国产性色也91| 极品av少妇一区二区| 欧美黑人欧美精品刺激| 欧美日韩一级二级| 青青草原av在线| 日本在线成人一区二区| 久久成人av少妇免费| 国产一级视频在线观看| 亚洲午夜久久久久久久| 国产日韩在线观看视频| 成年人午夜视频在线观看| 国产欧美一区二区精品仙草咪| 国产精品无码久久久久成人app| crdy在线观看欧美| 日韩高清国产精品| 国产一区二区三区香蕉| 国产小视频在线免费观看| 国产一区二区三区视频免费| 成人在线啊v| 精品国产免费av| 亚洲欧美色图小说| 欧洲毛片在线| 亚洲自拍在线观看| 美女视频一区免费观看| 免费在线黄色网| 亚洲视频999| 91成人福利| 日本黄大片一区二区三区| 亚洲一区二区四区蜜桃| av网在线观看| 国产一区二区高清视频|