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

實戰:用取消參數使 Go net/http 服務更靈活

開發 前端
超時既難以捉摸,卻又真實地存在于我們生活的由網絡連接的世界中。在我寫這篇文章的同時,隔壁兩個同事正在用他們的智能手機打字,也許是在跟與他們相距萬里的人聊天。網絡使這一切變為可能。

關于超時,可以把開發者分為兩類:一類是了解超時多么難以捉摸的人,另一類是正在感受超時如何難以捉摸的人。

超時既難以捉摸,卻又真實地存在于我們生活的由網絡連接的世界中。在我寫這篇文章的同時,隔壁兩個同事正在用他們的智能手機打字,也許是在跟與他們相距萬里的人聊天。網絡使這一切變為可能。

[[349023]]

這里要說的是網絡及其復雜性,作為寫網絡服務的我們,必須掌握如何高效地駕馭它們,并規避它們的缺陷。

閑話少說,來看看超時和它們是如何影響我們的 net/http 服務的。

服務超時 — 基本原理

web 編程中,超時通常分為客戶端和服務端超時兩種。我之所以要研究這個主題,是因為我自己遇到了一個有意思的服務端超時的問題。這也是本文我們將要重點討論服務側超時的原因。

先解釋下基本術語:超時是一個時間間隔(或邊界),用來標識在這個時間段內要完成特定的行為。如果在給定的時間范圍內沒有完成操作,就產生了超時,這個操作會被取消。

從一個 net/http 的服務的初始化中,能看出一些超時的基礎配置:

 

  1. srv := &http.Server{ 
  2.     ReadTimeout:       1 * time.Second
  3.     WriteTimeout:      1 * time.Second
  4.     IdleTimeout:       30 * time.Second
  5.     ReadHeaderTimeout: 2 * time.Second
  6.     TLSConfig:         tlsConfig, 
  7.     Handler:           srvMux, 

http.Server 類型的服務可以用四個不同的 timeout 來初始化:

  • ReadTimeout:讀取包括請求體的整個請求的最大時長
  • WriteTimeout:寫響應允許的最大時長
  • IdleTimetout:當開啟了保持活動狀態(keep-alive)時允許的最大空閑時間
  • ReadHeaderTimeout:允許讀請求頭的最大時長

對上述超時的圖表展示:

 

實戰:用取消參數使 Go net/http 服務更靈活

服務生命周期和超時

當心!不要以為這些就是你所需要的所有的超時了。除此之外還有很多超時,這些超時提供了更小的粒度控制,對于我們的持續運行的 HTTP 處理器不會生效。

請聽我解釋。

timeout 和 deadline

如果我們查看 net/http 的源碼,尤其是看到 `conn` 類型[1] 時,我們會發現conn 實際上使用了 net.Conn 連接,net.Conn 表示底層的網絡連接:

  1. // Taken from: https://github.com/golang/go/blob/bbbc658/src/net/http/server.go#L247 
  2. // A conn represents the server-side of an HTTP connection
  3. type conn struct { 
  4.     // server is the server on which the connection arrived. 
  5.     // Immutable; never nil. 
  6.     server *Server 
  7.  
  8.     // * Snipped * 
  9.  
  10.     // rwc is the underlying network connection
  11.     // This is never wrapped by other types and is the value given out 
  12.     // to CloseNotifier callers. It is usually of type *net.TCPConn or 
  13.     // *tls.Conn. 
  14.     rwc net.Conn 
  15.  
  16.     // * Snipped * 

換句話說,我們的 HTTP 請求實際上是基于 TCP 連接的。從類型上看,TLS 連接是 *net.TCPConn 或 *tls.Conn 。

serve 函數[2]處理每一個請求[3]時調用 readRequest 函數。readRequest使用我們設置的 timeout 值[4]來設置 TCP 連接的 deadline:

 

  1. // Taken from: https://github.com/golang/go/blob/bbbc658/src/net/http/server.go#L936 
  2. // Read next request from connection
  3. func (c *conn) readRequest(ctx context.Context) (w *response, err error) { 
  4.         // *Snipped* 
  5.  
  6.         t0 := time.Now() 
  7.         if d := c.server.readHeaderTimeout(); d != 0 { 
  8.                 hdrDeadline = t0.Add(d) 
  9.         } 
  10.         if d := c.server.ReadTimeout; d != 0 { 
  11.                 wholeReqDeadline = t0.Add(d) 
  12.         } 
  13.         c.rwc.SetReadDeadline(hdrDeadline) 
  14.         if d := c.server.WriteTimeout; d != 0 { 
  15.                 defer func() { 
  16.                         c.rwc.SetWriteDeadline(time.Now().Add(d)) 
  17.                 }() 
  18.         } 
  19.  
  20.         // *Snipped* 

從上面的摘要中,我們可以知道:我們對服務設置的 timeout 值最終表現為 TCP 連接的 deadline 而不是 HTTP 超時。

所以,deadline 是什么?工作機制是什么?如果我們的請求耗時過長,它們會取消我們的連接嗎?

一種簡單地理解 deadline 的思路是,把它理解為對作用于連接上的特定的行為的發生限制的一個時間點。例如,如果我們設置了一個寫的 deadline,當過了這個 deadline 后,所有對這個連接的寫操作都會被拒絕。

盡管我們可以使用 deadline 來模擬超時操作,但我們還是不能控制處理器完成操作所需的耗時。deadline 作用于連接,因此我們的服務僅在處理器嘗試訪問連接的屬性(如對 http.ResponseWriter 進行寫操作)之后才會返回(錯誤)結果。

為了實際驗證上面的論述,我們來創建一個小的 handler,這個 handler 完成操作所需的耗時相對于我們為服務設置的超時更長:

 

  1. package main 
  2.  
  3. import ( 
  4.  "fmt" 
  5.  "io" 
  6.  "net/http" 
  7.  "time" 
  8.  
  9. func slowHandler(w http.ResponseWriter, req *http.Request) { 
  10.  time.Sleep(2 * time.Second
  11.  io.WriteString(w, "I am slow!\n"
  12.  
  13. func main() { 
  14.  srv := http.Server{ 
  15.   Addr:         ":8888"
  16.   WriteTimeout: 1 * time.Second
  17.   Handler:      http.HandlerFunc(slowHandler), 
  18.  } 
  19.  
  20.  if err := srv.ListenAndServe(); err != nil { 
  21.   fmt.Printf("Server failed: %s\n", err) 
  22.  } 

上面的服務有一個 handler,這個 handler 完成操作需要兩秒。另一方面,http.Server 的 WriteTimeout 屬性設為 1 秒。基于服務的這些配置,我們猜測 handler 不能把響應寫到連接。

我們可以用 go run server.go 來啟動服務。使用 curl localhost:8888 來發送一個請求:

 

  1. time curl localhost:8888 
  2. curl: (52) Empty reply from server 
  3. curl localhost:8888  0.01s user 0.01s system 0% CPU 2.021 total 

這個請求需要兩秒來完成處理,服務返回的響應是空的。雖然我們的服務知道在 1 秒之后我們寫不了響應了,但 handler 還是多耗了 100% 的時間(2 秒)來完成處理。

雖然這是個類似超時的處理,但它更大的作用是在到達超時時間時,阻止服務進行更多的操作,結束請求。在我們上面的例子中,handler 在完成之前一直在處理請求,即使已經超出響應寫超時時間(1 秒)100%(耗時 2 秒)。

最根本的問題是,對于處理器來說,我們應該怎么設置超時時間才更有效?

處理超時

我們的目標是確保我們的 slowHandler 在 1s 內完成處理。如果超過了 1s,我們的服務會停止運行并返回對應的超時錯誤。

在 Go 和一些其它編程語言中,組合往往是設計和開發中最好的方式。標準庫的 `net/http` 包[5]有很多相互兼容的元素,開發者可以不需經過復雜的設計考慮就可以輕易將它們組合在一起。

基于此,net/http 包提供了`TimeoutHandler`[6] — 返回了一個在給定的時間限制內運行的 handler。

函數簽名:

  1. func TimeoutHandler(h Handler, dt time.Duration, msg string) Handler 

第一個參數是 Handler,第二個參數是 time.Duration (超時時間),第三個參數是 string 類型,當到達超時時間后返回的信息。

用 TimeoutHandler 來封裝我們的 slowHandler,我們只需要:

 

  1. package main 
  2.  
  3. import ( 
  4.  "fmt" 
  5.  "io" 
  6.  "net/http" 
  7.  "time" 
  8.  
  9. func slowHandler(w http.ResponseWriter, req *http.Request) { 
  10.  time.Sleep(2 * time.Second
  11.  io.WriteString(w, "I am slow!\n"
  12.  
  13. func main() { 
  14.  srv := http.Server{ 
  15.   Addr:         ":8888"
  16.   WriteTimeout: 5 * time.Second
  17.   Handler:      http.TimeoutHandler(http.HandlerFunc(slowHandler), 1*time.Second"Timeout!\n"), 
  18.  } 
  19.  
  20.  if err := srv.ListenAndServe(); err != nil { 
  21.   fmt.Printf("Server failed: %s\n", err) 
  22.  } 

兩個需要留意的地方是:

  • 我們在 http.TimetoutHandler 里封裝 slowHanlder,超時時間設為 1s,超時信息為 “Timeout!”。
  • 我們把 WriteTimeout 增加到 5s,以給予 http.TimeoutHandler 足夠的時間執行。如果我們不這么做,當 TimeoutHandler 開始執行時,已經過了 deadline,不能再寫到響應。

如果我們再啟動服務,當程序運行到 slow handler 時,會有如下輸出:

 

  1. time curl localhost:8888 
  2. Timeout! 
  3. curl localhost:8888  0.01s user 0.01s system 1% CPU 1.023 total 

1s 后,我們的 TimeoutHandler 開始執行,阻止運行 slowHandler,返回文本信息 ”Timeout!“。如果我們設置信息為空,handler 會返回默認的超時響應信息,如下:

  1. <html> 
  2.   <head> 
  3.     <title>Timeout</title> 
  4.   </head> 
  5.   <body> 
  6.    <h1>Timeout</h1> 
  7.   </body> 
  8. </html> 

如果忽略掉輸出,這還算是整潔,不是嗎?現在我們的程序不會有過長耗時的處理;也避免了有人惡意發送導致長耗時處理的請求時,導致的潛在的 DoS 攻擊。

盡管我們設置超時時間是一個偉大的開始,但它仍然只是初級的保護。如果你可能會面臨 DoS 攻擊,你應該采用更高級的保護工具和技術。(可以試試Cloudflare[7] )

我們的 slowHandler 僅僅是個簡單的 demo。但是,如果我們的程序復雜些,能向其他服務和資源發出請求會發生什么呢?如果我們的程序在超時時向諸如 S3 的服務發出了請求會怎么樣?

會發生什么?

未處理的超時和請求取消

我們稍微展開下我們的例子:

 

  1. func slowAPICall() string { 
  2.  d := rand.Intn(5) 
  3.  select { 
  4.  case <-time.After(time.Duration(d) * time.Second): 
  5.   log.Printf("Slow API call done after %s seconds.\n", d) 
  6.   return "foobar" 
  7.  } 
  8.  
  9. func slowHandler(w http.ResponseWriter, r *http.Request) { 
  10.  result := slowAPICall() 
  11.  io.WriteString(w, result+"\n"

我們假設最初我們不知道 slowHandler 由于通過 slowAPICall 函數向 API 發請求導致需要耗費這么長時間才能處理完成,

slowAPICall 函數很簡單:使用 select 和一個能阻塞 0 到 5 秒的 time.After 。當經過了阻塞的時間后,time.After 方法通過它的 channel 發送一個值,返回 "foobar" 。

(另一種方法是,使用 sleep(time.Duration(rand.Intn(5)) * time.Second),但我們仍然使用 select,因為它會使我們下面的例子更簡單。)

如果我們運行起服務,我們預期超時 handler 會在 1 秒之后中斷請求處理。來發送一個請求驗證一下:

 

  1. time curl localhost:8888 
  2. Timeout! 
  3. curl localhost:8888  0.01s user 0.01s system 1% CPU 1.021 total 

通過觀察服務的輸出,我們會發現,它是在幾秒之后打出日志的,而不是在超時 handler 生效時打出:

 

  1. $ Go run server.go 
  2. 2019/12/29 17:20:03 Slow API call done after 4 seconds. 

這個現象表明:雖然 1 秒之后請求超時了,但是服務仍然完整地處理了請求。這就是在 4 秒之后才打出日志的原因。

雖然在這個例子里問題很簡單,但是類似的現象在生產中可能變成一個嚴重的問題。例如,當 slowAPICall 函數開啟了幾個百個協程,每個協程都處理一些數據時。或者當它向不同系統發出多個不同的 API 發出請求時。這種耗時長的的進程,它們的請求方/客戶端并不會使用服務端的返回結果,會耗盡你系統的資源。

所以,我們怎么保護系統,使之不會出現類似的未優化的超時或取消請求呢?

上下文超時和取消

Go 有一個包名為 `context`[8] 專門處理類似的場景。

context 包在 Go 1.7 版本中提升為標準庫,在之前的版本中,以`golang.org/x/net/context`[9] 的路徑作為 Go Sub-repository Packages[10]出現。

這個包定義了 Context 類型。它最初的目的是保存不同 API 和不同處理的截止時間、取消信號和其他請求相關的值。如果你想了解關于 context 包的其他信息,可以閱讀 Golang's blog[11] 中的 “Go 并發模式:Context”(譯注:Go Concurrency Patterns: Context) .

net/http 包中的的 Request 類型已經有 context 與之綁定。從 Go 1.7 開始,Request 新增了一個返回請求的上下文的 `Context` 方法[12]。對于進來的請求,在客戶端關閉連接、請求被取消(HTTP/2 中)或 ServeHTTP 方法返回后,服務端會取消上下文。

我們期望的現象是,當客戶端取消請求(輸入了 CTRL + C)或一段時間后TimeoutHandler 繼續執行然后終止請求時,服務端會停止后續的處理。進而關閉所有的連接,釋放所有被運行中的處理進程(及它的所有子協程)占用的資源。

我們把 Context 作為參數傳給 slowAPICall 函數:

 

  1. func slowAPICall(ctx context.Context) string { 
  2.  d := rand.Intn(5) 
  3.  select { 
  4.  case <-time.After(time.Duration(d) * time.Second): 
  5.   log.Printf("Slow API call done after %d seconds.\n", d) 
  6.   return "foobar" 
  7.  } 
  8.  
  9. func slowHandler(w http.ResponseWriter, r *http.Request) { 
  10.  result := slowAPICall(r.Context()) 
  11.  io.WriteString(w, result+"\n"

在例子中我們利用了請求上下文,實際中怎么用呢?`Context` 類型[13]有個 Done 屬性,類型為 <-chan struct{}。當進程處理完成時,Done 關閉,此時表示上下文應該被取消,而這正是例子中我們需要的。

我們在 slowAPICall 函數中用 select 處理 ctx.Done 通道。當我們通過 Done 通道接收一個空的 struct 時,意味著上下文取消,我們需要讓 slowAPICall 函數返回一個空字符串。

 

  1. func slowAPICall(ctx context.Context) string { 
  2.  d := rand.Intn(5) 
  3.  select { 
  4.  case <-ctx.Done(): 
  5.   log.Printf("slowAPICall was supposed to take %s seconds, but was canceled.", d) 
  6.   return "" 
  7.         //time.After() 可能會導致內存泄漏 
  8.  case <-time.After(time.Duration(d) * time.Second): 
  9.   log.Printf("Slow API call done after %d seconds.\n", d) 
  10.   return "foobar" 
  11.  } 

(這就是使用 select 而不是 time.Sleep -- 這里我們只能用 select 處理 Done 通道。)

在這個簡單的例子中,我們成功得到了結果 -- 當我們從 Done 通道接收值時,我們打印了一行日志到 STDOUT 并返回了一個空字符串。在更復雜的情況下,如發送真實的 API 請求,你可能需要關閉連接或清理文件描述符。

我們再啟動服務,發送一個 cRUL 請求:

 

  1. # The cURL command: 
  2. $ curl localhost:8888 
  3. Timeout! 
  4.  
  5. # The server output
  6. $ Go run server.go 
  7. 2019/12/30 00:07:15 slowAPICall was supposed to take 2 seconds, but was canceled. 

檢查輸出:我們發送了 cRUL 請求到服務,它耗時超過 1 秒,服務取消了 slowAPICall 函數。我們幾乎不需要寫任何代碼。TimeoutHandler 為我們代勞了 -- 當處理耗時超過預期時,TimeoutHandler 終止了處理進程并取消請求上下文。

TimeoutHandler 是在 `timeoutHandler.ServeHTTP` 方法[14] 中取消上下文的:

 

  1. // Taken from: https://github.com/golang/go/blob/bbbc658/src/net/http/server.go#L3217-L3263 
  2. func (h *timeoutHandler) ServeHTTP(w ResponseWriter, r *Request) { 
  3.         ctx := h.testContext 
  4.         if ctx == nil { 
  5.          var cancelCtx context.CancelFunc 
  6.          ctx, cancelCtx = context.WithTimeout(r.Context(), h.dt) 
  7.          defer cancelCtx() 
  8.         } 
  9.         r = r.WithContext(ctx) 
  10.  
  11.         // *Snipped* 

上面例子中,我們通過調用 context.WithTimeout 來使用請求上下文。超時值 h.dt (TimeoutHandler 的第二個參數)設置給了上下文。返回的上下文是請求上下文設置了超時值后的一份拷貝。隨后,它作為請求上下文傳給r.WithContext(ctx)。

context.WithTimeout 方法執行了上下文取消。它返回了 Context 設置了一個超時值之后的副本。當到達超時時間后,就取消上下文。

這里是執行的代碼:

 

  1. // Taken from: https://github.com/golang/go/blob/bbbc6589/src/context/context.go#L486-L498 
  2. func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) { 
  3.  return WithDeadline(parent, time.Now().Add(timeout)) 
  4.  
  5. // Taken from: https://github.com/golang/go/blob/bbbc6589/src/context/context.go#L418-L450 
  6. func WithDeadline(parent Context, d time.Time) (Context, CancelFunc) { 
  7.         // *Snipped* 
  8.  
  9.         c := &timerCtx{ 
  10.          cancelCtx: newCancelCtx(parent), 
  11.          deadline:  d, 
  12.         } 
  13.  
  14.         // *Snipped* 
  15.  
  16.         if c.err == nil { 
  17.          c.timer = time.AfterFunc(dur, func() { 
  18.           c.cancel(true, DeadlineExceeded) 
  19.          }) 
  20.         } 
  21.         return c, func() { c.cancel(true, Canceled) } 

這里我們又看到了截止時間。WithDeadline 函數設置了一個 d 到達之后執行的函數。當到達截止時間后,它調用 cancel 方法處理上下文,此方法會關閉上下文的 done 通道并設置上下文的 timer 屬性為 nil。

Done 通道的關閉有效地取消了上下文,使我們的 slowAPICall 函數終止了它的執行。這就是 TimeoutHandler 終止耗時長的處理進程的原理。

(如果你想閱讀上面提到的源碼,你可以去看 `cancelCtx` 類型[15] 和`timerCtx` 類型[16])

有彈性的 net/http 服務

連接截止時間提供了低級的細粒度控制。雖然它們的名字中含有“超時”,但它們并沒有表現出人們通常期望的“超時”。實際上它們非常強大,但是使用它們有一定的門檻。

另一個角度講,當處理 HTTP 時,我們仍然應該考慮使用 TimeoutHandler。Go 的作者們也選擇使用它,它有多種處理,提供了如此有彈性的處理以至于我們甚至可以對每一個處理使用不同的超時。TimeoutHandler 可以根據我們期望的表現來控制執行進程。

除此之外,TimeoutHandler 完美兼容 context 包。context 包很簡單,包含了取消信號和請求相關的數據,我們可以使用這些數據來使我們的應用更好地處理錯綜復雜的網絡問題。

結束之前,有三個建議。寫 HTTP 服務時,怎么設計超時:

  • 最常用的,到達 TimeoutHandler 時,怎么處理。它進行我們通常期望的超時處理。
  • 不要忘記上下文取消。context 包使用起來很簡單,并且可以節省你服務器上的很多處理資源。尤其是在處理異常或網絡狀況不好時。
  • 一定要用截止時間。確保做了完整的測試,驗證了能提供你期望的所有功能。

 

責任編輯:未麗燕 來源: 今日頭條
相關推薦

2009-05-18 09:12:00

ASON自動交換光網絡

2015-05-04 14:12:43

2023-06-06 19:24:06

KubernetesSpark

2024-11-21 15:48:40

2011-02-23 09:48:00

Python.NET

2011-02-22 10:00:38

.NETc#IronPython

2009-06-03 09:08:20

ScalaJava類型

2017-07-18 06:08:41

2023-11-27 08:21:49

Camera2API,

2012-01-13 10:31:25

ibmdw

2020-09-14 09:33:02

網絡

2025-02-18 00:10:00

2017-02-14 15:37:32

KappaLambda

2024-01-08 08:36:29

HTTPGo代理服務器

2023-12-05 10:25:24

Python類型注解

2015-10-10 10:01:39

VMware數據中心

2012-03-13 10:40:58

Google Go

2013-12-12 10:55:21

2013-11-11 16:20:01

戴爾
點贊
收藏

51CTO技術棧公眾號

91精品动漫在线观看| 精品91久久| 国产成人一级电影| 欧美日本亚洲视频| 冲田杏梨av在线| av资源在线观看免费高清| 麻豆91在线播放免费| 欧美成人午夜激情视频| 97香蕉碰碰人妻国产欧美| 免费电影日韩网站| 中文字幕中文字幕在线一区| 成人国产1314www色视频| 欧美bbbbbbbbbbbb精品| 大片网站久久| 日韩精品一区在线| 成人观看免费完整观看| 在线免费黄色| 91一区在线观看| 欧美一区二区三区四区在线| 手机看片日韩av| 在线观看视频一区二区三区| 色狠狠综合天天综合综合| 一本色道久久综合亚洲二区三区| 性生交生活影碟片| 日韩电影在线免费| 韩国v欧美v日本v亚洲| 久久久久无码精品国产sm果冻| 国产精品一区免费在线| 色噜噜狠狠成人中文综合| mm131午夜| 青青视频在线观| 国产一区不卡在线| 国产激情视频一区| 免费毛片一区二区三区| 91视频综合| 亚洲精品少妇网址| 日本xxxx免费| 伊人亚洲精品| 在线精品国精品国产尤物884a| 国产欧美123| 91露出在线| 91麻豆国产香蕉久久精品| 91传媒视频免费| 亚洲一区在线观| 日本欧美一区二区三区乱码| 91国产视频在线播放| 五月婷婷一区二区| 88国产精品视频一区二区三区| 亚洲欧美日韩中文在线| 少妇被狂c下部羞羞漫画| 成人国产精品一区二区网站| 欧美亚洲愉拍一区二区| 国产免费黄色小视频| 18av在线播放| 日韩美女啊v在线免费观看| 色乱码一区二区三在线看| 神马午夜电影一区二区三区在线观看 | 国产精品美乳在线观看| 亚洲黄色三级视频| 伊人久久大香线蕉综合热线 | 亚洲免费精品| 国内精品久久久久影院 日本资源| 国产高潮流白浆| 天天久久综合| 精品中文字幕在线| 麻豆亚洲av成人无码久久精品| 99精品网站| 日韩亚洲综合在线| 欧美激情精品久久久久久免费 | 337p日本欧洲亚洲大胆色噜噜| 91香蕉视频在线观看视频| 深夜福利亚洲| 日韩一区二区在线观看视频播放| 999热精品视频| 视频二区欧美毛片免费观看| 欧美刺激午夜性久久久久久久| 在线成人免费av| 综合视频一区| 日韩黄在线观看| 自拍偷拍亚洲天堂| 亚洲制服欧美另类| 综合网日日天干夜夜久久| 青娱乐国产视频| 成人网18免费网站| 久久视频在线直播| 久久一级黄色片| 亚洲资源av| 国产精品美乳一区二区免费| 国产免费无遮挡| 波多野结衣91| 日韩欧美视频第二区| 久久日韩视频| 亚洲第一狼人社区| 成年人视频网站免费观看| 国产成人精品亚洲日本在线观看| 欧美视频在线一区| 性生活一级大片| 91丨精品丨国产| 精品久久久久久久久久久久久久久 | 精品人伦一区二区三区蜜桃免费| 久久网站免费视频| 国产美女久久| 亚洲国产成人一区| 性欧美精品男男| 国产精品伦理久久久久久| 欧美成aaa人片在线观看蜜臀| 久草免费在线观看视频| 久久亚洲综合| 成人看片视频| 国产视频福利在线| 亚洲色图第一区| 欧美亚洲日本一区二区三区| 成人国产精选| 337p日本欧洲亚洲大胆色噜噜| 国产精品免费无码| 亚洲乱码精品| 国产精品99一区| 亚洲AV无码精品色毛片浪潮| 久久九九久久九九| www.av蜜桃| 日韩电影精品| 国产视频久久久久| 九九在线观看视频| 美女网站视频久久| 久久久久久国产精品免费免费| 91免费在线| 日韩欧美精品网站| 日本xxxx免费| 久久精品亚洲人成影院| 日韩免费中文字幕| 神马午夜在线观看| 尤物视频一区二区| 国产日韩欧美久久| 在线视频亚洲专区| 久久久久久久久久久久av| 久久久久久无码精品大片| 成人性生交大片免费看中文网站| 亚洲春色在线| 成人午夜视屏| 欧美成人官网二区| www.涩涩爱| 日本美女一区二区三区| 久久久久久九九九九| 直接在线观看的三级网址| 欧美日韩国产123区| 成人精品在线观看视频| 亚洲视频狠狠| 亚洲自拍偷拍视频| a在线免费观看| 欧美日韩在线三级| 亚洲精品国产一区黑色丝袜| 亚洲成人原创| 国产精品18毛片一区二区| 在线免费观看成人短视频| 亚洲精品视频导航| 成人精品影院| 国产精品久久久久久久久久99| 国产日韩精品在线看| 91久久一区二区| 99在线视频免费| 久久99国产精品久久99果冻传媒| 中文字幕在线观看一区二区三区| 超碰国产精品一区二页| 精品中文字幕视频| 午夜性色福利视频| 在线观看日韩一区| 久久av红桃一区二区禁漫| 国产原创一区二区三区| 国产一区二区三区乱码| 亚洲电影一级片| 国产精品入口免费视频一| 日本不卡不卡| 精品免费日韩av| 免费观看成人毛片| 国产精品每日更新在线播放网址| 在线观看中文av| 亚洲欧洲视频| 日韩欧美精品久久| 清纯唯美激情亚洲| 2018国产精品视频| 欧美人xxx| 亚洲成人久久久久| 中文字幕在线日亚洲9| 樱桃国产成人精品视频| 国产视频久久久久久| 青娱乐精品视频在线| 超碰超碰超碰超碰超碰| 婷婷综合一区| 成人在线视频网| 蜜桃视频在线观看免费视频| 一区二区三区在线播放欧美| www.桃色av嫩草.com| 91国模大尺度私拍在线视频| 日韩精品一区二区亚洲av性色| 不卡一区在线观看| 日韩高清第一页| 999亚洲国产精| www.黄色网址.com| 精品国产一区一区二区三亚瑟| 91精品国自产在线观看| 日韩精品影院| 韩剧1988免费观看全集| 含羞草www国产在线视频| 日韩精品在线观看一区| av观看在线免费| 欧美在线影院一区二区| 国产精品成人免费一区二区视频| 中文字幕av一区二区三区高| 国产精品久久久久久在线观看| 久久成人免费网| 欧美黄色一级片视频| 国产精品va| 免费成人深夜夜行网站视频| 精品国产一区二区三区四区| 精品欧美一区二区久久久伦| 色播一区二区| 亚洲一区二区在线| 91伊人久久| 国产经典一区二区| 中文在线8资源库| 久久免费精品视频| 污视频网站免费在线观看| 日韩少妇与小伙激情| 国外av在线| 亚洲男人第一网站| 天堂资源中文在线| 欧美精品一区二区久久婷婷| av中文字幕免费| 欧美一卡2卡3卡4卡| 国产精品无码专区av免费播放| 在线观看91精品国产入口| 天堂中文在线网| 欧美日韩国产精品一区二区三区四区 | 亚洲人成亚洲人成在线观看图片| 国产精久久一区二区三区| 久久欧美一区二区| 亚洲第一香蕉网| 久久综合九色综合久久久精品综合| 私密视频在线观看| 成熟亚洲日本毛茸茸凸凹| www.四虎在线| 成人免费看黄yyy456| 久久精品aⅴ无码中文字字幕重口| 国产福利不卡视频| 性xxxxxxxxx| 成人性生交大片免费看中文| 久久久久久久人妻无码中文字幕爆| 国产精品亚洲一区二区三区在线 | 高潮久久久久久久久久久久久久| 99精品国产一区二区| 成人看片爽爽爽| 韩日午夜在线资源一区二区| 欧美日韩导航| 欧洲国产精品| 久久裸体网站| 亚洲自拍偷拍一区二区三区| 欧美国产激情| 欧洲精品在线播放| 国产伦理一区| 亚洲天堂av线| 国产一区二区在线视频| 美国黄色一级视频| 91首页免费视频| 午夜时刻免费入口| 最新国产成人在线观看| 久久久久久蜜桃| 午夜久久久影院| 亚洲成人av网址| 7777精品伊人久久久大香线蕉经典版下载| 国产精品乱码一区二区| 日韩美女在线视频| 日本中文字幕电影在线观看| 一区二区欧美日韩视频| 岛国成人毛片| 欧美一级bbbbb性bbbb喷潮片| 成人小电影网站| 91精品视频在线| 久久精品色播| 亚洲成人自拍| 激情成人综合| 日本激情综合网| 国产suv精品一区二区883| 成人网站免费观看| 自拍偷拍亚洲综合| 九九热在线视频播放| 欧美日韩午夜影院| 人妻无码一区二区三区久久99 | 91精品国产一区二区三区香蕉| 国产香蕉在线观看| 最近日韩中文字幕中文| 国产盗摄在线视频网站| 国产乱人伦真实精品视频| 99精品在免费线中文字幕网站一区 | 九九久久久久久| 91在线观看免费视频| 国产成人av免费在线观看| 色综合天天综合网天天狠天天| 97超碰中文字幕| 久久电影在线| 国产亚洲午夜高清国产拍精品| 欧美精品一区二区在线播放 | 精品国产乱码久久久久久蜜臀| 涩涩网站在线看| 国产呦萝稀缺另类资源| 中文字幕在线观看的网站| 一色屋精品亚洲香蕉网站| 色播视频在线播放| 337p亚洲精品色噜噜狠狠| 欧美精品久久久久久久久久丰满| 久热精品视频在线观看一区| 午夜精品成人av| 国产精品美女黄网| 久久精品国内一区二区三区水蜜桃| 日韩av资源在线| www.亚洲免费av| 欧美久久久久久久久久久久| 欧美日韩精品一区二区天天拍小说| 熟妇人妻系列aⅴ无码专区友真希 熟妇人妻av无码一区二区三区 | 亚洲欧美中日韩| 怡红院av久久久久久久| 亚洲国产一区二区三区在线观看| 成人在线免费看黄| 国产精品爽爽爽| 国产伦精品一区二区三区视频| 成人免费性视频| 国产精品原创巨作av| 欧美福利在线视频| 欧美伊人久久久久久午夜久久久久| 天天综合天天综合| 国内成人精品一区| 一区二区三区四区精品视频| 欧美xxxx吸乳| 国产很黄免费观看久久| 极品魔鬼身材女神啪啪精品| 欧美卡1卡2卡| 国产激情小视频在线| 成人国产精品一区二区| 日韩一区二区三区免费播放| 污污动漫在线观看| 国产精品福利一区| 一级片免费网站| 久久精品视频在线观看| 色综合久久久| wwwjizzjizzcom| 国产成人精品在线看| 精品一区在线视频| 亚洲福利在线播放| 欧美freesex黑人又粗又大| 久久福利电影| 久久久久久久尹人综合网亚洲| 男人操女人动态图| 欧美日韩国产综合久久| 国产最新在线| 99re在线国产| 国产一区二区三区久久| 精品无码人妻一区| 欧美日韩在线播放一区| 黄色在线视频网站| 超碰97在线资源| 乱码第一页成人| 国产视频精品免费| 欧美成人精品高清在线播放| 三级中文字幕在线观看| 奇米888一区二区三区| 久久国产精品99久久久久久老狼 | 国产综合久久久久久| 欧美一区成人| 超碰男人的天堂| 欧美日韩中文字幕精品| 丝袜美腿av在线| 久久综合婷婷综合| 老司机一区二区| 国产一级一片免费播放放a| 亚洲欧美激情四射在线日| 日韩一级特黄| 男的插女的下面视频| 久久精品无码一区二区三区| 亚洲一线在线观看| 性视频1819p久久| 欧美丝袜激情| 国产女人18毛片水真多18| 91福利小视频| 人人澡人人添人人爽一区二区| 久久精品中文字幕一区二区三区| 人妖欧美一区二区| 久久免费少妇高潮99精品| 亚洲欧美在线磁力| 久久国产精品免费一区二区三区| 国产乱子伦农村叉叉叉| 亚洲欧洲国产日韩| 色播色播色播色播色播在线| 成人a视频在线观看| 免费永久网站黄欧美| 国产一区二区视频在线观看免费| 亚洲毛片在线观看| 亚洲精品黑牛一区二区三区| 亚洲视频在线a| 亚洲福利一区二区| 成人影院在线看| 日韩妆和欧美的一区二区|