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

一篇帶給你Go并發編程Singleflight

開發 前端
這篇文章從使用場景,到使用方法,再到源碼分析和可能存在的坑給大家介紹了 singleflight,希望你能有所收獲,沒事看看官方的代碼還是很有收獲的,這次又學到了一個騷操作,用雙重 defer 來避免死鎖.

[[389247]]

 這一篇文章的內容是在 Week05: 評論系統架構設計 當中的可用性設計當中提到的,但是這個屬于 Go 官方擴展同步包 (golang.org/x/sync/singleflight) 的一個庫,為了讓內容統一就放到這里了。

SingleFlight

為什么我們需要 SingleFlight(使用場景)?

一般情況下我們在寫一寫對外的服務的時候都會有一層 cache 作為緩存,用來減少底層數據庫的壓力,但是在遇到例如 redis 抖動或者其他情況可能會導致大量的 cache miss 出現。

如下圖所示,可能存在來自桌面端和移動端的用戶有 1000 的并發請求,他們都訪問的獲取文章列表的接口,獲取前 20 條信息,如果這個時候我們服務直接去訪問 redis 出現 cache miss 那么我們就會去請求 1000 次數據庫,這時可能會給數據庫帶來較大的壓力(這里的 1000 只是一個例子,實際上可能遠大于這個值)導致我們的服務異常或者超時。

這時候就可以使用 singleflight 庫了,直譯過來就是單飛,這個庫的主要作用就是將一組相同的請求合并成一個請求,實際上只會去請求一次,然后對所有的請求返回相同的結果。如下圖所示,使用 singleflight 之后,我們在一個請求的時間周期內實際上只會向底層的數據庫發起一次請求大大減少對數據庫的壓力。

SingleFlight 包怎么用(使用教程)?

函數簽名

主要是一個 Group 結構體,三個方法,具體信息看下方注釋

  1. type Group 
  2.     // Do 執行函數, 對同一個 key 多次調用的時候,在第一次調用沒有執行完的時候 
  3.  // 只會執行一次 fn 其他的調用會阻塞住等待這次調用返回 
  4.  // v, err 是傳入的 fn 的返回值 
  5.  // shared 表示是否真正執行了 fn 返回的結果,還是返回的共享的結果 
  6.     func (g *Group) Do(key string, fn func() (interface{}, error)) (v interface{}, err error, shared bool) 
  7.  
  8.  // DoChan 和 Do 類似,只是 DoChan 返回一個 channel,也就是同步與異步的區別 
  9.  func (g *Group) DoChan(key string, fn func() (interface{}, error)) <-chan Result 
  10.  
  11.     // Forget 用于通知 Group 刪除某個 key 這樣后面繼續這個 key 的調用的時候就不會在阻塞等待了 
  12.  func (g *Group) Forget(key string) 

使用示例

接下來我們看看實際上我們是怎么使用的,先使用一個普通的例子,這時一個獲取文章詳情的函數,我們在函數里面使用一個 count 模擬不同并發下的耗時的不同,并發越多請求耗時越多

  1. func getArticle(id int) (article string, err error) { 
  2.  // 假設這里會對數據庫進行調用, 模擬不同并發下耗時不同 
  3.  atomic.AddInt32(&count, 1) 
  4.  time.Sleep(time.Duration(count) * time.Millisecond) 
  5.  
  6.  return fmt.Sprintf("article: %d", id), nil 

我們使用 singleflight 的時候就只需要 new(singleflight.Group) 然后調用一下相對應的 Do 方法就可了,是不是很簡單

  1. func singleflightGetArticle(sg *singleflight.Group, id int) (string, error) { 
  2.  v, err, _ := sg.Do(fmt.Sprintf("%d", id), func() (interface{}, error) { 
  3.   return getArticle(id) 
  4.  }) 
  5.  
  6.  return v.(string), err 

效果測試

光說不練假把式,寫一個簡單的測試代碼,下面我們啟動 1000 個 Goroutine 去并發調用這兩個方法

  1. var count int32 
  2.  
  3. func main() { 
  4.  time.AfterFunc(1*time.Second, func() { 
  5.   atomic.AddInt32(&count, -count
  6.  }) 
  7.  
  8.  var ( 
  9.   wg  sync.WaitGroup 
  10.   now = time.Now() 
  11.   n   = 1000 
  12.   sg  = &singleflight.Group{} 
  13.  ) 
  14.  
  15.  for i := 0; i < n; i++ { 
  16.   wg.Add(1) 
  17.   go func() { 
  18.    // res, _ := singleflightGetArticle(sg, 1) 
  19.    res, _ := getArticle(1) 
  20.    if res != "article: 1" { 
  21.     panic("err"
  22.    } 
  23.    wg.Done() 
  24.   }() 
  25.  } 
  26.  
  27.  wg.Wait() 
  28.  fmt.Printf("同時發起 %d 次請求,耗時: %s", n, time.Since(now)) 

可以看到這個是調用 getArticle 方法的耗時,花費了 1s 多

  1. # 直接調用的請求耗時 
  2. ❯ go run ./1.go 
  3. 同時發起 1000 次請求,耗時: 1.0022831s 

而使用 singleflight 的方法,花費了不到 3ms

  1. # 使用 singleflight 的請求耗時 
  2. ❯ go run ./1.go 
  3. 同時發起 1000 次請求,耗時: 2.5119ms 

當然每個庫都有自己的使用場景,軟件領域里面沒有銀彈,如果我們用的不太好的話甚至可能會得到適得其反的效果,而多看源碼不僅能夠幫助我們進行學習,也可以盡量少踩坑

它是如何實現的(源碼分析)?

本文基于 [https://pkg.go.dev/golang.org/x/sync@v0.0.0-20210220032951-036812b2e83c/singleflight](https://pkg.go.dev/golang.org/x/sync@v0.0.0-20210220032951-036812b2e83c/singleflight) 進行分析,這個庫的實現很簡單,但是功能很強大,還有一些小技巧,非常值得學習

Group

  1. type Group struct { 
  2.  mu sync.Mutex       // protects m 
  3.  m  map[string]*call // lazily initialized 

Group 結構體由一個互斥鎖和一個 map 組成,可以看到注釋 map 是懶加載的,所以 Group 只要聲明就可以使用,不用進行額外的初始化零值就可以直接使用。call 保存了當前調用對應的信息,map 的鍵就是我們調用 Do 方法傳入的 key

  1. type call struct { 
  2.  wg sync.WaitGroup 
  3.  
  4.  // 函數的返回值,在 wg 返回前只會寫入一次 
  5.  val interface{} 
  6.  err error 
  7.  
  8.  // 使用調用了 Forgot 方法 
  9.  forgotten bool 
  10.  
  11.     // 統計調用次數以及返回的 channel 
  12.  dups  int 
  13.  chans []chan<- Result 

Do

  1. func (g *Group) Do(key string, fn func() (interface{}, error)) (v interface{}, err error, shared bool) { 
  2.  g.mu.Lock() 
  3.  
  4.     // 前面提到的懶加載 
  5.     if g.m == nil { 
  6.   g.m = make(map[string]*call) 
  7.  } 
  8.  
  9.     // 會先去看 key 是否已經存在 
  10.  if c, ok := g.m[key]; ok { 
  11.         // 如果存在就會解鎖 
  12.   c.dups++ 
  13.   g.mu.Unlock() 
  14.  
  15.         // 然后等待 WaitGroup 執行完畢,只要一執行完,所有的 wait 都會被喚醒 
  16.   c.wg.Wait() 
  17.  
  18.         // 這里區分 panic 錯誤和 runtime 的錯誤,避免出現死鎖,后面可以看到為什么這么做 
  19.   if e, ok := c.err.(*panicError); ok { 
  20.    panic(e) 
  21.   } else if c.err == errGoexit { 
  22.    runtime.Goexit() 
  23.   } 
  24.   return c.val, c.err, true 
  25.  } 
  26.  
  27.     // 如果我們沒有找到這個 key 就 new call 
  28.  c := new(call) 
  29.  
  30.     // 然后調用 waitgroup 這里只有第一次調用會 add 1,其他的都會調用 wait 阻塞掉 
  31.     // 所以這要這次調用返回,所有阻塞的調用都會被喚醒 
  32.  c.wg.Add(1) 
  33.  g.m[key] = c 
  34.  g.mu.Unlock() 
  35.  
  36.     // 然后我們調用 doCall 去執行 
  37.  g.doCall(c, key, fn) 
  38.  return c.val, c.err, c.dups > 0 

doCall

這個方法的實現有點意思,使用了兩個 defer 巧妙的將 runtime 的錯誤和我們傳入 function 的 panic 區別開來避免了由于傳入的 function panic 導致的死鎖

  1. func (g *Group) doCall(c *call, key string, fn func() (interface{}, error)) { 
  2.  normalReturn := false 
  3.  recovered := false 
  4.  
  5.     // 第一個 defer 檢查 runtime 錯誤 
  6.  defer func() { 
  7.  
  8.  }() 
  9.  
  10.     // 使用一個匿名函數來執行 
  11.  func() { 
  12.   defer func() { 
  13.    if !normalReturn { 
  14.                 // 如果 panic 了我們就 recover 掉,然后 new 一個 panic 的錯誤 
  15.                 // 后面在上層重新 panic 
  16.     if r := recover(); r != nil { 
  17.      c.err = newPanicError(r) 
  18.     } 
  19.    } 
  20.   }() 
  21.  
  22.   c.val, c.err = fn() 
  23.  
  24.         // 如果 fn 沒有 panic 就會執行到這一步,如果 panic 了就不會執行到這一步 
  25.         // 所以可以通過這個變量來判斷是否 panic 了 
  26.   normalReturn = true 
  27.  }() 
  28.  
  29.     // 如果 normalReturn 為 false 就表示,我們的 fn panic 了 
  30.     // 如果執行到了這一步,也說明我們的 fn  recover 住了,不是直接 runtime exit 
  31.  if !normalReturn { 
  32.   recovered = true 
  33.  } 

再來看看第一個 defer 中的代碼

  1. defer func() { 
  2.  // 如果既沒有正常執行完畢,又沒有 recover 那就說明需要直接退出了 
  3.  if !normalReturn && !recovered { 
  4.   c.err = errGoexit 
  5.  } 
  6.  
  7.  c.wg.Done() 
  8.  g.mu.Lock() 
  9.  defer g.mu.Unlock() 
  10.  
  11.        // 如果已經 forgot 過了,就不要重復刪除這個 key 了 
  12.  if !c.forgotten { 
  13.   delete(g.m, key
  14.  } 
  15.  
  16.  if e, ok := c.err.(*panicError); ok { 
  17.   // 如果返回的是 panic 錯誤,為了避免 channel 死鎖,我們需要確保這個 panic 無法被恢復 
  18.   if len(c.chans) > 0 { 
  19.    go panic(e) 
  20.    select {} // Keep this goroutine around so that it will appear in the crash dump. 
  21.   } else { 
  22.    panic(e) 
  23.   } 
  24.  } else if c.err == errGoexit { 
  25.   // 已經準備退出了,也就不用做其他操作了 
  26.  } else { 
  27.   // 正常情況下向 channel 寫入數據 
  28.   for _, ch := range c.chans { 
  29.    ch <- Result{c.val, c.err, c.dups > 0} 
  30.   } 
  31.  } 
  32. }() 

DoChan

Do chan 和 Do 類似,其實就是一個是同步等待,一個是異步返回,主要實現上就是,如果調用 DoChan 會給 call.chans 添加一個 channel 這樣等第一次調用執行完畢之后就會循環向這些 channel 寫入數據

  1. func (g *Group) DoChan(key string, fn func() (interface{}, error)) <-chan Result { 
  2.  ch := make(chan Result, 1) 
  3.  g.mu.Lock() 
  4.  if g.m == nil { 
  5.   g.m = make(map[string]*call) 
  6.  } 
  7.  if c, ok := g.m[key]; ok { 
  8.   c.dups++ 
  9.   c.chans = append(c.chans, ch) 
  10.   g.mu.Unlock() 
  11.   return ch 
  12.  } 
  13.  c := &call{chans: []chan<- Result{ch}} 
  14.  c.wg.Add(1) 
  15.  g.m[key] = c 
  16.  g.mu.Unlock() 
  17.  
  18.  go g.doCall(c, key, fn) 
  19.  
  20.  return ch 

Forget

forget 用于手動釋放某個 key 下次調用就不會阻塞等待了

  1. func (g *Group) Forget(key string) { 
  2.  g.mu.Lock() 
  3.  if c, ok := g.m[key]; ok { 
  4.   c.forgotten = true 
  5.  } 
  6.  delete(g.m, key
  7.  g.mu.Unlock() 

有哪些注意事項(避坑指南)?

單飛雖好但也不要濫用哦,還是存在一些坑的

1. 一個阻塞,全員等待

使用 singleflight 我們比較常見的是直接使用 Do 方法,但是這個極端情況下會導致整個程序 hang 住,如果我們的代碼出點問題,有一個調用 hang 住了,那么會導致所有的請求都 hang 住

還是之前的例子,我們加一個 select 模擬阻塞

  1. func singleflightGetArticle(sg *singleflight.Group, id int) (string, error) { 
  2.  v, err, _ := sg.Do(fmt.Sprintf("%d", id), func() (interface{}, error) { 
  3.   // 模擬出現問題,hang 住 
  4.   select {} 
  5.   return getArticle(id) 
  6.  }) 
  7.  
  8.  return v.(string), err 

執行就會發現死鎖了

  1. fatal error: all goroutines are asleep - deadlock! 
  2.  
  3. goroutine 1 [select (no cases)]: 

這時候我們可以使用 DoChan 結合 select 做超時控制

  1. func singleflightGetArticle(ctx context.Context, sg *singleflight.Group, id int) (string, error) { 
  2.  result := sg.DoChan(fmt.Sprintf("%d", id), func() (interface{}, error) { 
  3.   // 模擬出現問題,hang 住 
  4.   select {} 
  5.   return getArticle(id) 
  6.  }) 
  7.  
  8.  select { 
  9.  case r := <-result: 
  10.   return r.Val.(string), r.Err 
  11.  case <-ctx.Done(): 
  12.   return "", ctx.Err() 
  13.  } 

調用的時候傳入一個含 超時的 context 即可,執行時就會返回超時錯誤

  1. ❯ go run ./1.go 
  2. panic: context deadline exceeded 

2. 一個出錯,全部出錯

這個本身不是什么問題,因為 singleflight 就是這么設計的,但是實際使用的時候 如果我們一次調用要 1s,我們的數據庫請求或者是 下游服務可以支撐 10rps 的請求的時候這會導致我們的錯誤閾提高,因為實際上我們可以一秒內嘗試 10 次,但是用了 singleflight 之后只能嘗試一次,只要出錯這段時間內的所有請求都會受影響

這種情況我們可以啟動一個 Goroutine 定時 forget 一下,相當于將 rps 從 1rps 提高到了 10rps

  1. go func() { 
  2.        time.Sleep(100 * time.Millisecond) 
  3.        // logging 
  4.        g.Forget(key
  5.    }() 

總結

這篇文章從使用場景,到使用方法,再到源碼分析和可能存在的坑給大家介紹了 singleflight,希望你能有所收獲,沒事看看官方的代碼還是很有收獲的,這次又學到了一個騷操作,用雙重 defer 來避免死鎖,你學廢了么?

我們下一篇會開啟一個新的系列,Go 可用性,敬請期待!

文章博客地址:https://lailin.xyz 

 

責任編輯:姜華 來源: mohuishou
相關推薦

2021-06-24 06:35:00

Go語言進程

2021-04-30 09:04:11

Go 語言結構體type

2021-07-12 06:11:14

SkyWalking 儀表板UI篇

2021-04-09 10:38:59

Go 語言數組與切片

2021-04-06 10:19:36

Go語言基礎技術

2020-11-24 09:53:38

Shell

2022-04-29 14:38:49

class文件結構分析

2021-04-08 11:00:56

CountDownLaJava進階開發

2021-07-21 09:48:20

etcd-wal模塊解析數據庫

2022-02-17 08:53:38

ElasticSea集群部署

2021-03-12 09:21:31

MySQL數據庫邏輯架構

2021-06-21 14:36:46

Vite 前端工程化工具

2021-04-01 10:51:55

MySQL鎖機制數據庫

2021-01-28 08:55:48

Elasticsear數據庫數據存儲

2021-04-14 14:16:58

HttpHttp協議網絡協議

2024-06-13 08:34:48

2022-03-22 09:09:17

HookReact前端

2023-03-29 07:45:58

VS編輯區編程工具

2021-07-08 07:30:13

Webpack 前端Tree shakin

2023-03-13 09:31:04

點贊
收藏

51CTO技術棧公眾號

538国产精品视频一区二区| 欧洲视频一区二区| 狠狠综合久久av| 精品国产xxx| 一区二区国产在线| 日韩国产欧美精品在线| 亚洲一区日韩精品| 1024在线看片你懂得| 91麻豆免费观看| 成人妇女淫片aaaa视频| 国产精品18p| 99成人超碰| 日韩精品在线第一页| 成人黄色一级大片| 亚洲精品中文字幕| 一区二区三区精品在线| 亚洲v欧美v另类v综合v日韩v| 国产视频精品免费| 精品丝袜久久| 欧美男女性生活在线直播观看| 欧美伦理一区二区| 精品人妻伦一二三区久久| 水野朝阳av一区二区三区| 欧美成人精品一区二区三区| 国产一二三四区在线| 精品三级av在线导航| 在线电影院国产精品| 国产xxxxx视频| 999福利在线视频| 亚洲精品视频免费看| 亚洲不卡1区| 亚洲 国产 欧美 日韩| 国产综合久久久久久久久久久久| 成人97在线观看视频| 成人精品在线观看视频| 99精品在免费线中文字幕网站一区| 午夜久久久久久| 久久99国产精品一区| 国产理论电影在线观看| 91免费观看视频| 国产精品日本一区二区| 国产日韩欧美中文字幕| 老司机午夜精品| 国产精品国产亚洲伊人久久| 国产一级片毛片| 黄色日韩在线| 国外成人免费在线播放| 久久精品99国产精| 狠狠爱综合网| 欧美激情亚洲视频| 国产一级大片在线观看| 中文在线播放一区二区| 欧美成人精品在线观看| 一级免费黄色录像| 97精品国产| 久久精品国产v日韩v亚洲| 黄色片网站在线播放| 成人精品中文字幕| 日韩在线视频二区| 加勒比婷婷色综合久久| 亚洲五月综合| 欧美国产日韩免费| 久久精品免费av| 夜夜夜久久久| 日本亚洲欧洲色α| 中文字幕免费视频观看| 久久精品久久久精品美女| 国产综合久久久久| 精品国产九九九| gogogo免费视频观看亚洲一| 精品国产一区二区三区四区vr| 一区二区不卡视频在线观看| 激情综合色播激情啊| 91九色在线免费视频| 精品国自产拍在线观看| av激情综合网| 日韩一区不卡| a级影片在线| 五月天久久比比资源色| 91看片就是不一样| 日韩国产大片| 欧美mv日韩mv亚洲| 37p粉嫩大胆色噜噜噜| japanese国产精品| 毛片精品免费在线观看| 精品91久久久| 麻豆一区二区三区| 国产精品区一区二区三在线播放| 国产成人麻豆精品午夜在线| av电影在线观看一区| 神马一区二区影院| 国产盗摄一区二区| 色综合色狠狠天天综合色| www.这里只有精品| 久久精品国产亚洲5555| 爽爽爽爽爽爽爽成人免费观看| 欧美双性人妖o0| 成人vr资源| 欧美激情在线播放| 欧美日韩 一区二区三区| 久久精品99久久久| 精品国产综合久久| 超碰在线最新| 欧洲另类一二三四区| 亚洲欧美日韩中文字幕在线观看| 久久综合偷偷噜噜噜色| 亚洲欧美另类在线观看| 欧美色图亚洲天堂| 青青草一区二区三区| 国产精品美女诱惑| 国产原厂视频在线观看| 欧美中文字幕久久| 国产又黄又粗又猛又爽的视频| 亚洲日本va中文字幕| 亚洲人成免费电影| 九九精品在线观看视频| 国产一区观看| 亚洲mm色国产网站| 高清在线观看av| 午夜国产精品一区| 被黑人猛躁10次高潮视频| 成人羞羞动漫| 91产国在线观看动作片喷水| 精品人妻aV中文字幕乱码色欲 | 国产精品自拍视频在线| 欧美巨大xxxx| 欧美精品免费在线| 一个人看的www日本高清视频| 韩国欧美国产1区| 日韩电影大全在线观看| 最新欧美色图| 亚洲精品电影在线观看| 国产精品99无码一区二区| 精品一区精品二区高清| 亚洲视频在线观看日本a| 另类图片综合电影| 国产婷婷色综合av蜜臀av| 日韩免费视频网站| 不卡欧美aaaaa| 无码人妻少妇伦在线电影| 亚洲精品黑牛一区二区三区| 日韩中文字幕在线播放| 中文字幕在线播出| 国产精品全国免费观看高清| 九九九在线观看视频| 国产一区二区亚洲| 国产精品入口免费视| 国产爆初菊在线观看免费视频网站| 自拍偷拍国产精品| 国产三级生活片| 婷婷激情综合| 91精品天堂| 国内小视频在线看| 亚洲第一二三四五区| 国产精品1234区| 91美女视频网站| 欧美三级午夜理伦三级| 国产一区二区三区天码| 国产精品在线看| 中日韩高清电影网| 亚洲国产成人久久| 黄色在线免费观看| 国产精品网站在线| 九一精品久久久| 国产精品s色| 国产一区二区三区高清视频| 625成人欧美午夜电影| 国产一区二区三区视频在线观看| 九九热国产精品视频| 床上的激情91.| 无码aⅴ精品一区二区三区浪潮| 国产一区二区在线观| 欧美日本在线视频中文字字幕| 天天爽夜夜爽人人爽| 久久九九影视网| 爱爱爱爱免费视频| 亚洲精品午夜av福利久久蜜桃| 国产精品激情av在线播放| 欧美a在线看| 精品国产一区二区三区四区四| 性の欲びの女javhd| 国内精品伊人久久久久av一坑 | 日本欧美一二三区| 在线观看国产原创自拍视频| 日韩欧美成人一区| 亚洲日本视频在线观看| 1000部国产精品成人观看| 亚洲精品激情视频| 日韩成人dvd| 国产成人一二三区| 国产欧美高清视频在线| 成人免费视频97| 亚洲性色av| 欧美大成色www永久网站婷| 网站黄在线观看| 91精品在线观看入口| 青青草免费观看视频| 亚洲天堂中文字幕| 97伦伦午夜电影理伦片| 国产伦精一区二区三区| 最近免费中文字幕中文高清百度| 免费av一区二区三区四区| 成人信息集中地欧美| www成人免费观看| 久久精品久久久久| 你懂的在线视频| 精品日韩在线观看| 伊人网视频在线| 色偷偷88欧美精品久久久| 破处女黄色一级片| 国产婷婷色一区二区三区| 午夜视频在线免费看| 免费av网站大全久久| 很污的网站在线观看| 久久亚洲国产| 日韩一区免费观看| 小说区图片区色综合区| 国产区一区二区三区| 激情综合婷婷| 国产日韩欧美中文在线播放| 成人片免费看| 午夜精品久久久久久久99热浪潮| 天堂√在线中文官网在线| 欧美成人猛片aaaaaaa| 中文字幕一区二区三区人妻四季| 亚洲欧美国产高清| 亚洲一区二区三区日韩| 91在线精品一区二区三区| 亚洲天堂小视频| 国内精品免费**视频| 亚洲欧美久久久久| 日韩黄色片在线观看| 国内外免费激情视频| 美女尤物久久精品| 亚洲色成人一区二区三区小说| 色喇叭免费久久综合网| 久久综合给合久久狠狠色| 久久动漫网址| 久久久久久99| 色狼人综合干| 日本高清一区| 国产亚洲一区| 亚洲欧美国产精品桃花| 日产午夜精品一线二线三线| 水蜜桃亚洲一二三四在线| 精品一区av| 午夜免费电影一区在线观看| 欧美色图国产精品| 无码免费一区二区三区免费播放 | 99re66热这里只有精品4| 欧美最顶级丰满的aⅴ艳星| 欧美私密网站| 国产91在线播放精品91| 日韩在线观看不卡| 国产精品日韩在线观看| 日韩专区视频网站| 99re在线视频观看| 国产suv精品一区| 久久99蜜桃综合影院免费观看| 精品国产亚洲一区二区三区| 91精品在线观看视频| 视频一区在线| 国产无套精品一区二区| 免费一区二区三区视频导航| 免费在线观看一区二区| 精品国产美女| 日本黄网站色大片免费观看| 亚洲人体偷拍| 亚洲视频在线观看一区二区三区| 亚洲清纯自拍| 爆乳熟妇一区二区三区霸乳| 免费观看日韩电影| 99热这里只有精品2| av一区二区久久| 女女互磨互喷水高潮les呻吟| eeuss鲁片一区二区三区在线观看| 日本 片 成人 在线| 国产精品一二二区| 日本护士做爰视频| 国产精品免费丝袜| 久久久久97国产| 日本韩国欧美一区二区三区| 国产尤物在线观看| 日韩av在线免播放器| 日本中文字幕在线播放| 久久久久久久久91| 日本一区免费网站| 91久久精品视频| 日本精品影院| 丰满女人性猛交| 久久精品人人做人人爽电影蜜月| 91猫先生在线| 精品一区二区三区不卡| 国产一级二级视频| 亚洲欧美在线观看| 天天干在线播放| 日韩一级高清毛片| 黄色视屏网站在线免费观看| 欧美精品在线观看| 成人黄色免费观看| 精品久久一区二区三区蜜桃| 欧美国产小视频| 日本wwww视频| 成人黄色av电影| 免费成人深夜夜行网站| 欧美午夜影院在线视频| 国产精品伦理一区| 亚洲情综合五月天| 里番在线播放| 成人精品久久一区二区三区| 免费一区二区| 波多野结衣综合网| 福利电影一区二区三区| 亚洲精品一区二区三区在线播放| 国产精品你懂的| 中文字幕精品无码一区二区| 欧美一卡二卡在线观看| 欧美午夜电影一区二区三区| 日韩暖暖在线视频| 日韩精选在线| 给我免费播放片在线观看| 韩日欧美一区二区三区| 超碰人人干人人| 色婷婷久久久综合中文字幕| 天堂中文在线资源| 久久久久久999| 一区二区亚洲视频| 久久久成人精品一区二区三区| 欧美精品1区| 天堂av.com| 1区2区3区国产精品| 五月婷婷激情五月| 国产亚洲精品久久久久久| 亚洲最新无码中文字幕久久| 国产精品日韩一区二区| 亚洲日本激情| 野战少妇38p| 亚洲成av人片观看| 高清一区二区三区四区| 久久久久久18| silk一区二区三区精品视频| 国产欧美久久久久| 国产白丝网站精品污在线入口| 人妻熟女aⅴ一区二区三区汇编| 欧美激情中文不卡| 欧美日韩一二三四区| 亚洲精品中文字幕女同| 六月婷婷综合| 亚洲国产精品123| 免费人成网站在线观看欧美高清| 国产av一区二区三区传媒| 夜夜嗨av一区二区三区中文字幕| 黄色av网站免费观看| 一本一本久久a久久精品综合小说| 最新超碰在线| 国产精品国产精品国产专区蜜臀ah | 亚洲深夜影院| 在线免费观看日韩av| 欧美系列一区二区| 欧美18hd| 亚洲xxxx在线| 亚洲第一区色| 尤物视频最新网址| 欧美日韩高清在线| 欧美激情成人动漫| 久久手机视频| 麻豆精品在线观看| 妺妺窝人体色www在线下载| 亚洲精品国精品久久99热一| 亚洲精品一级二级| 99久久久无码国产精品性色戒| 水蜜桃久久夜色精品一区的特点| 91亚洲一区二区| 亚洲人午夜精品天堂一二香蕉| 一级片在线观看免费| 在线国产精品播放| 日韩中文字幕在线一区| 国产黄页在线观看| 国产欧美日韩亚州综合| 99久久精品日本一区二区免费| 丝袜美腿亚洲一区二区| 一区二区在线免费播放| 免费无遮挡无码永久视频| 国产精品蜜臀av| 欧美视频xxx| 国产精品久久久久久亚洲调教 | 成人免费的视频| 日本黄色一级视频| 欧美国产日本高清在线 | 麻豆网站免费在线观看| 午夜免费电影一区在线观看| 成人免费视频caoporn| 中文字幕av片| 97在线免费观看视频| 91精品综合久久久久久久久久久| 久久撸在线视频| 午夜av区久久| 怡红院红怡院欧美aⅴ怡春院| 国产这里只有精品| 夜夜嗨网站十八久久|