午夜视频免费看_日韩三级电影网站_国产精品久久一级_亚洲一级在线播放_人妻体内射精一区二区三区_91夜夜揉人人捏人人添红杏_91福利在线导航_国产又粗又猛又黄又爽无遮挡_欧美日韩一区在线播放_中文字幕一区二区三区四区不卡 _日日夜夜精品视频免费观看_欧美韩日一区二区三区

主頁 > 知識庫 > Golang 實現Thrift客戶端連接池方式

Golang 實現Thrift客戶端連接池方式

熱門標簽:仙桃400電話辦理 鄭州智能語音電銷機器人價格 重慶慶云企業400電話到哪申請 地圖標注免費定制店 不封卡外呼系統 宿遷便宜外呼系統代理商 上海極信防封電銷卡價格 寧波語音外呼系統公司 湛江crm外呼系統排名

1 前言

閱讀文章之前,請先了解一下thrift相關知識。thrift官方并沒有提供客戶端連接池的實現方案,而我們在實際使用時,thrift客戶端必須復用,來保證較為可觀的吞吐量,并避免在高QPS調用情況下,不斷的創建、釋放客戶端所帶來的機器端口耗盡問題。

本文會詳細講解如何實現一個簡單可靠的thrift客戶端連接池,并通過對照實驗來說明thrift客戶端連接池所帶來的好處。

由于篇幅的原因,本文只粘出關鍵代碼,源代碼請查看Thrift Client Pool Demo

1.1 運行環境

Golang版本: go1.14.3 darwin/amd64

Thrift Golang庫版本: 0.13.0

Thrift IDL編輯器版本: 0.13.0

1.2 .thrift文件

namespace java com.czl.api.thrift.model
namespace cpp com.czl.api
namespace php com.czl.api
namespace py com.czl.api
namespace js com.czl.apixianz
namespace go com.czl.api
struct ApiRequest {
 1: required i16 id;
}
struct ApiResponse{
 1:required string name;
}
// service1
service ApiService1{
 ApiResponse query(1:ApiRequest request)
}
// service2
service ApiService2{
 ApiResponse query(1:ApiRequest request)
}

注:請通過安裝Thrift IDL編譯器,并生成客戶端、服務端代碼。

1.3 對照實驗說明

通過腳本開啟100個協程并發調用rpc服務10分鐘,統計這段時間內,未使用thrift客戶端連接池與使用客戶端連接池服務的平均吞吐量、Thrift API調用平均延遲、機器端口消耗等數據進行性能對比。

實驗一: 未使用thrift客戶端連接池

實驗二: 使用thrift客戶端連接池

2 Thrift客戶端連接池實現

2.1 連接池的功能

首先,我們要明確一下連接池的職責,這里我簡單的總結一下,連接池主要功能是維護連接的創建、釋放,通過緩存連接來復用連接,減少創建連接所帶來的開銷,提高系統的吞吐量,一般連接池還會有連接斷開的重連機制、超時機制等。這里我們可以先定義出大部分連接池都會有的功能,只是定義,可以先不管每個功能的具體實現。每一個空閑Thrift客戶端其實底層都維護著一條空閑TCP連接,空閑Thrift客戶端與空閑連接在這里其實是同一個概念。

......
// Thrift客戶端創建方法,留給業務去實現
type ThriftDial func(addr string, connTimeout time.Duration) (*IdleClient, error)
// 關閉Thrift客戶端,留給業務實現
type ThriftClientClose func(c *IdleClient) error
// Thrift客戶端連接池
type ThriftPool struct {
 // Thrift客戶端創建邏輯,業務自己實現
 Dial ThriftDial
 // Thrift客戶端關閉邏輯,業務自己實現
 Close ThriftClientClose
 // 空閑客戶端,用雙端隊列存儲
 idle list.List
 // 同步鎖,確保count、status、idle等公共數據并發操作安全
 lock *sync.Mutex
 // 記錄當前已經創建的Thrift客戶端,確保MaxConn配置
 count int32
 // Thrift客戶端連接池狀態,目前就open和stop兩種
 status uint32
 // Thrift客戶端連接池相關配置
 config *ThriftPoolConfig
}
// 連接池配置
type ThriftPoolConfig struct {
 // Thrfit Server端地址
 Addr string
 // 最大連接數
 MaxConn int32
 // 創建連接超時時間
 ConnTimeout time.Duration
 // 空閑客戶端超時時間,超時主動釋放連接,關閉客戶端
 IdleTimeout time.Duration
 // 獲取Thrift客戶端超時時間
 Timeout time.Duration
 // 獲取Thrift客戶端失敗重試間隔
 interval time.Duration
}
// Thrift客戶端
type IdleClient struct {
 // Thrift傳輸層,封裝了底層連接建立、維護、關閉、數據讀寫等細節
 Transport thrift.TTransport
 // 真正的Thrift客戶端,業務創建傳入
 RawClient interface{}
}
// 封裝了Thrift客戶端
type idleConn struct {
 // 空閑Thrift客戶端
 c *IdleClient
 // 最近一次放入空閑隊列的時間
 t time.Time
}
// 獲取Thrift空閑客戶端
func (p *ThriftPool) Get() (*IdleClient, error) {
 // 1. 從空閑池中獲取空閑客戶端,獲取到更新數據,返回,否則執行第2步
 // 2. 創建新到Thrift客戶端,更新數據,返回Thrift客戶端
 ......
}
// 歸還Thrift客戶端
func (p *ThriftPool) Put(client *IdleCLient) error {
 // 1. 如果客戶端已經斷開,更新數據,返回,否則執行第2步
 // 2. 將Thrift客戶端丟進空閑連接池,更新數據,返回
 ......
}
// 超時管理,定期釋放空閑太久的連接
func (p *ThriftPool) CheckTimeout() {
 // 掃描空閑連接池,將空閑太久的連接主動釋放掉,并更新數據
 ......
}
// 異常連接重連
func (p *ThriftPool) Reconnect(client *IdleClient) (newClient *IdleClient, err error) {
 // 1. 關閉舊客戶端
 // 2. 創建新的客戶端,并返回
 ......
}
// 其他方法
......

這里有兩個關鍵的數據結構,ThriftPool和IdleClient,ThriftPool負責實現整個連接池的功能,IdleClient封裝了真正的Thrift客戶端。

先看一下ThriftPool的定義:

// Thrift客戶端創建方法,留給業務去實現
type ThriftDial func(addr string, connTimeout time.Duration) (*IdleClient, error)
// 關閉Thrift客戶端,留給業務實現
type ThriftClientClose func(c *IdleClient) error
// Thrift客戶端連接池
type ThriftPool struct {
 // Thrift客戶端創建邏輯,業務自己實現
 Dial ThriftDial
 // Thrift客戶端關閉邏輯,業務自己實現
 Close ThriftClientClose
 // 空閑客戶端,用雙端隊列存儲
 idle list.List
 // 同步鎖,確保count、status、idle等公共數據并發操作安全
 lock *sync.Mutex
 // 記錄當前已經創建的Thrift客戶端,確保MaxConn配置
 count int32
 // Thrift客戶端連接池狀態,目前就open和stop兩種
 status uint32
 // Thrift客戶端連接池相關配置
 config *ThriftPoolConfig
}
// 連接池配置
type ThriftPoolConfig struct {
 // Thrfit Server端地址
 Addr string
 // 最大連接數
 MaxConn int32
 // 創建連接超時時間
 ConnTimeout time.Duration
 // 空閑客戶端超時時間,超時主動釋放連接,關閉客戶端
 IdleTimeout time.Duration
 // 獲取Thrift客戶端超時時間
 Timeout time.Duration
 // 獲取Thrift客戶端失敗重試間隔
 interval time.Duration
}

Thrift客戶端創建與關閉,涉及到業務細節,這里抽離成Dial方法和Close方法。

連接池需要維護空閑客戶端,這里用雙端隊列來存儲。

一般的連接池,都應該支持最大連接數配置,MaxConn可以配置連接池最大連接數,同時我們用count來記錄連接池當前已經創建的連接。

為了實現連接池的超時管理,當然也得有相關超時配置。

連接池的狀態、當前連接數等這些屬性,是多協程并發操作的,這里用同步鎖lock來確保并發操作安全。

在看一下IdleClient實現:

// Thrift客戶端
type IdleClient struct {
 // Thrift傳輸層,封裝了底層連接建立、維護、關閉、數據讀寫等細節
 Transport thrift.TTransport
 // 真正的Thrift客戶端,業務創建傳入
 RawClient interface{}
}
// 封裝了Thrift客戶端
type idleConn struct {
 // 空閑Thrift客戶端
 c *IdleClient
 // 最近一次放入空閑隊列的時間
 t time.Time
}

RawClient是真正的Thrift客戶端,與實際邏輯相關。

Transport Thrift傳輸層,Thrift傳輸層,封裝了底層連接建立、維護、關閉、數據讀寫等細節。

idleConn封裝了IdleClient,用來實現空閑連接超時管理,idleConn記錄一個時間,這個時間是Thrift客戶端最近一次被放入空閑隊列的時間。

2.2 獲取連接

......
var nowFunc = time.Now
......
// 獲取Thrift空閑客戶端
func (p *ThriftPool) Get() (*IdleClient, error) {
 return p.get(nowFunc().Add(p.config.Timeout))
}
// 獲取連接的邏輯實現
// expire設定了一個超時時間點,當沒有可用連接時,程序會休眠一小段時間后重試
// 如果一直獲取不到連接,一旦到達超時時間點,則報ErrOverMax錯誤
func (p *ThriftPool) get(expire time.Time) (*IdleClient, error) {
 if atomic.LoadUint32(p.status) == poolStop {
 return nil, ErrPoolClosed
 }
 // 判斷是否超額
 p.lock.Lock()
 if p.idle.Len() == 0  atomic.LoadInt32(p.count) >= p.config.MaxConn {
 p.lock.Unlock()
 // 不采用遞歸的方式來實現重試機制,防止棧溢出,這里改用循環方式來實現重試
 for {
 // 休眠一段時間再重試
 time.Sleep(p.config.interval)
 // 超時退出
 if nowFunc().After(expire) {
 return nil, ErrOverMax
 }
 p.lock.Lock()
 if p.idle.Len() == 0  atomic.LoadInt32(p.count) >= p.config.MaxConn {
 p.lock.Unlock()
 } else { // 有可用鏈接,退出for循環
 break
 }
 }
 }
 if p.idle.Len() == 0 {
 // 先加1,防止首次創建連接時,TCP握手太久,導致p.count未能及時+1,而新的請求已經到來
 // 從而導致短暫性實際連接數大于p.count(大部分鏈接由于無法進入空閑鏈接隊列,而被關閉,處于TIME_WATI狀態)
 atomic.AddInt32(p.count, 1)
 p.lock.Unlock()
 client, err := p.Dial(p.config.Addr, p.config.ConnTimeout)
 if err != nil {
 atomic.AddInt32(p.count, -1)
 return nil, err
 }
 // 檢查連接是否有效
 if !client.Check() {
 atomic.AddInt32(p.count, -1)
 return nil, ErrSocketDisconnect
 }
 return client, nil
 }
 // 從隊頭中獲取空閑連接
 ele := p.idle.Front()
 idlec := ele.Value.(*idleConn)
 p.idle.Remove(ele)
 p.lock.Unlock()
 // 連接從空閑隊列獲取,可能已經關閉了,這里再重新檢查一遍
 if !idlec.c.Check() {
 atomic.AddInt32(p.count, -1)
 return nil, ErrSocketDisconnect
 }
 return idlec.c, nil
}

p.Get()的邏輯比較清晰:如果空閑隊列沒有連接,且當前連接已經到達p.config.MaxConn,就休眠等待重試;當滿足獲取連接條件時p.idle.Len() != 0 || atomic.LoadInt32(p.count) p.config.MaxConn,有空閑連接,則返回空閑連接,減少創建連接的開銷,沒有的話,再重新創建一條新的連接。

這里有兩個關鍵的地方需要注意:

等待重試的邏輯,不要用遞歸的方式來實現,防止運行棧溢出。

// 遞歸的方法實現等待重試邏輯
func (p *ThriftPool) get(expire time.Time) (*IdleClient, error) {
 // 超時退出
 if nowFunc().After(expire) {
 return nil, ErrOverMax
 }
 if atomic.LoadUint32(p.status) == poolStop {
 return nil, ErrPoolClosed
 }
 // 判斷是否超額
 p.lock.Lock()
 if p.idle.Len() == 0  atomic.LoadInt32(p.count) >= p.config.MaxConn {
 p.lock.Unlock()
 // 休眠遞歸重試
 time.Sleep(p.config.interval)
 p.get(expire)
 }
 .......
}

注意p.lock.Lock()的和p.lock.UnLock()調用時機,確保公共數據并發操作安全。

2.3 釋放連接

// 歸還Thrift客戶端
func (p *ThriftPool) Put(client *IdleClient) error {
 if client == nil {
 return nil
 }
 if atomic.LoadUint32(p.status) == poolStop {
 err := p.Close(client)
 client = nil
 return err
 }
 if atomic.LoadInt32(p.count) > p.config.MaxConn || !client.Check() {
 atomic.AddInt32(p.count, -1)
 err := p.Close(client)
 client = nil
 return err
 }
 p.lock.Lock()
 p.idle.PushFront(idleConn{
 c: client,
 t: nowFunc(),
 })
 p.lock.Unlock()
 return nil
}

p.Put()邏輯也比較簡單,如果連接已經失效,p.count需要-1,并進行連接關閉操作。否則丟到空閑隊列里,這里還是丟到隊頭,沒錯,還是丟到隊頭,p.Get()和p.Put()都是從隊頭操作,有點像堆操作,為啥這么處理,等下面說到空閑連接超時管理就清楚了,這里先記住丟回空閑隊列的時候,會更新空閑連接的時間。

2.4 超時管理

獲取連接超時管理p.Get()方法已經講過了,創建連接超時管理由p.Dial()去實現,下面說的是空閑連接的超時管理,空閑隊列的連接,如果一直沒有使用,超過一定時間,需要主動關閉掉,服務端的資源有限,不需要用的連接就主動關掉,而且連接放太久,服務端也會主動關掉。

// 超時管理,定期釋放空閑太久的連接
func (p *ThriftPool) CheckTimeout() {
 p.lock.Lock()
 for p.idle.Len() != 0 {
 ele := p.idle.Back()
 if ele == nil {
 break
 }
 v := ele.Value.(*idleConn)
 if v.t.Add(p.config.IdleTimeout).After(nowFunc()) {
 break
 }
 //timeout  clear
 p.idle.Remove(ele)
 p.lock.Unlock()
 p.Close(v.c) //close client connection
 atomic.AddInt32(p.count, -1)
 p.lock.Lock()
 }
 p.lock.Unlock()
 return
}

清理超時空閑連接的時候,是從隊尾開始清理掉超時或者無效的連接,直到找到第一個可用的連接或者隊列為空。p.Get()和p.Put()都從隊頭操作隊列,保證了活躍的連接都在隊頭,如果一開始創建的連接太多,后面業務操作變少,不需要那么多連接的時候,那多余的連接就會沉到隊尾,被超時管理所清理掉。另外,這樣設計也可以優化操作的時間復雜度O(n)。

2.5 重連機制

事實上,thrift的transport層并沒有提供一個檢查連接是否有效的方法,一開始實現連接池的時候,檢測方法是調用thrift.TTransport.IsOpen()來判斷

// 檢測連接是否有效
func (c *IdleClient) Check() bool {
 if c.Transport == nil || c.RawClient == nil {
 return false
 }
 return c.Transport.IsOpen()
}

可在測試階段發現當底層當TCP連接被異常斷開的時候(服務端重啟、服務端宕機等),c.Transport.IsOpen()并不能如期的返回false,如果我們查看thrift的源碼,可以發現,其實c.Transport.IsOpen()只和我們是否調用了c.Transport.Open()方法有關。為了能實現斷開重連機制,我們只能在使用階段發現異常連接時,重連連接。

這里我在ThriftPool上封裝了一層代理ThriftPoolAgent,來實現斷開重連邏輯,具體請參考代碼實現。

package pool
import (
 "fmt"
 "github.com/apache/thrift/lib/go/thrift"
 "log"
 "net"
)
type ThriftPoolAgent struct {
 pool *ThriftPool
}
func NewThriftPoolAgent() *ThriftPoolAgent {
 return ThriftPoolAgent{}
}
func (a *ThriftPoolAgent) Init(pool *ThriftPool) {
 a.pool = pool
}
// 真正的業務邏輯放到do方法做,ThriftPoolAgent只要保證獲取到可用的Thrift客戶端,然后傳給do方法就行了
func (a *ThriftPoolAgent) Do(do func(rawClient interface{}) error) error {
 var (
 client *IdleClient
 err error
 )
 defer func() {
 if client != nil {
 if err == nil {
 if rErr := a.releaseClient(client); rErr != nil {
 log.Println(fmt.Sprintf("releaseClient error: %v", rErr))
 }
 } else if _, ok := err.(net.Error); ok {
 a.closeClient(client)
 } else if _, ok = err.(thrift.TTransportException); ok {
 a.closeClient(client)
 } else {
 if rErr := a.releaseClient(client); rErr != nil {
 log.Println(fmt.Sprintf("releaseClient error: %v", rErr))
 }
 }
 }
 }()
 // 從連接池里獲取鏈接
 client, err = a.getClient()
 if err != nil {
 return err
 }
 if err = do(client.RawClient); err != nil {
 if _, ok := err.(net.Error); ok {
 log.Println(fmt.Sprintf("err: retry tcp, %T, %s", err, err.Error()))
 // 網絡錯誤,重建連接
 client, err = a.reconnect(client)
 if err != nil {
 return err
 }
 return do(client.RawClient)
 }
 if _, ok := err.(thrift.TTransportException); ok {
 log.Println(fmt.Sprintf("err: retry tcp, %T, %s", err, err.Error()))
 // thrift傳輸層錯誤,也重建連接
 client, err = a.reconnect(client)
 if err != nil {
 return err
 }
 return do(client.RawClient)
 }
 return err
 }
 return nil
}
// 獲取連接
func (a *ThriftPoolAgent) getClient() (*IdleClient, error) {
 return a.pool.Get()
}
// 釋放連接
func (a *ThriftPoolAgent) releaseClient(client *IdleClient) error {
 return a.pool.Put(client)
}
// 關閉有問題的連接,并重新創建一個新的連接
func (a *ThriftPoolAgent) reconnect(client *IdleClient) (newClient *IdleClient, err error) {
 return a.pool.Reconnect(client)
}
// 關閉連接
func (a *ThriftPoolAgent) closeClient(client *IdleClient) {
 a.pool.CloseConn(client)
}
// 釋放連接池
func (a *ThriftPoolAgent) Release() {
 a.pool.Release()
}
func (a *ThriftPoolAgent) GetIdleCount() uint32 {
 return a.pool.GetIdleCount()
}
func (a *ThriftPoolAgent) GetConnCount() int32 {
 return a.pool.GetConnCount()
}

3 對照實驗

啟用100個協程,不斷調用Thrift服務端API 10分鐘,對比服務平均吞吐量、Thrift API調用平均延遲、機器端口消耗。

平均吞吐量(r/s) = 總成功數 / 600

API調用平均延遲(ms/r) = 總成功數 / API成功請求總耗時(微秒) / 1000

機器端口消耗計算:netstat -nt | grep 9444 -c

3.1 實驗一:未使用連接池

機器端口消耗

平均吞吐量、平均延遲

從結果看,API的平均延遲在77ms左右,但是服務的平均吞吐量才到360,比理論值1000 / 77 * 1000 = 1299少了很多,而且有96409次錯誤,報錯的主要原因是:connect can't assign request address,100個協程并發調用就已經消耗了1.6w個端口,如果并發數更高的場景,端口消耗的情況會更加嚴重,實際上,這1.6w條TCP連接,幾乎都是TIME_WAIT狀態,Thrfit客戶端用完就close掉,根據TCP三次握手可知主動斷開連接的一方最終將會處于TIME_WAIT狀態,并等待2MSL時間。

3.2 實驗二:使用連接池

機器端口消耗

平均吞吐量、平均延遲

可以看出,用了連接池后,平均吞吐量可達到1.8w,API調用平均延遲才0.5ms,你可能會問,理論吞吐量不是可以達到1000 / 0.5 * 100 = 20w?理論歸理論,如果按照1.8w吞吐量算,一次處理過程總時間消耗是1000 / (18000 / 100) = 5.6ms,所以這里影響吞吐量的因素已經不是API調用的耗時了,1.8w的吞吐量其實已經挺不錯了。

另外,消耗的端口數也才194/2 = 97(除余2是因為server端也在本地跑),而且都是ESTABLISH狀態,連接一直保持著,不斷的在被復用。連接被復用,少了創建TCP連接的三次握手環節,這里也可以解釋為啥API調用的平均延遲可以從77ms降到0.5ms,不過0.5ms確實有點低,線上環境Server一般不會和Client在同一臺機器,而且業務邏輯也會比這里復雜,API調用的平均延遲會相對高一點。

4 總結

調用Thrift API必須使用Thrift客戶端連接池,否則在高并發的情況下,會有大量的TCP連接處于TIME_WAIT狀態,機器端口被大量消耗,可能會導致部分請求失敗甚至服務不可用。每次請求都重新創建TCP連接,進行TCP三次握手環節,API調用的延遲會比較高,服務的吞吐量也不會很高。

使用Thrift客戶端連接池,可以提高系統的吞吐量,同時可以避免機器端口被耗盡的危險,提高服務的可靠性。

以上為個人經驗,希望能給大家一個參考,也希望大家多多支持腳本之家。如有錯誤或未考慮完全的地方,望不吝賜教。

您可能感興趣的文章:
  • golang 通過ssh代理連接mysql的操作
  • 淺談golang結構體偷懶初始化
  • golang連接kafka消費進ES操作
  • golang實現各種情況的get請求操作
  • Golang 實現分片讀取http超大文件流和并發控制
  • 在Golang中使用http.FileServer返回靜態文件的操作
  • golang 生成定單號的操作

標簽:海南 電子產品 西雙版納 青海 儋州 物業服務 遼寧 安康

巨人網絡通訊聲明:本文標題《Golang 實現Thrift客戶端連接池方式》,本文關鍵詞  Golang,實現,Thrift,客戶端,;如發現本文內容存在版權問題,煩請提供相關信息告之我們,我們將及時溝通與處理。本站內容系統采集于網絡,涉及言論、版權與本站無關。
  • 相關文章
  • 下面列出與本文章《Golang 實現Thrift客戶端連接池方式》相關的同類信息!
  • 本頁收集關于Golang 實現Thrift客戶端連接池方式的相關信息資訊供網民參考!
  • 推薦文章
    免费国产羞羞网站视频| 日韩亚洲国产中文字幕欧美| 亚洲六月丁香色婷婷综合久久| 国产精品一区二区x88av| 美国av一区二区| 日韩精品每日更新| 老司机精品导航| 色丁香婷婷综合久久| www.香蕉视频| 国产91麻豆视频| 黄频网站在线观看| 天堂v在线观看| 人妻91麻豆一区二区三区| 成人精品在线播放| 国产91免费在线观看| 天天综合网在线观看| 天天操天天干天天舔| 亚洲av成人无码久久精品老人| 亚洲精品国产一区二| 精品国产亚洲av麻豆| 风流少妇一区二区三区91| 欧美少妇bbw| 久久精品成人| 免费观看在线综合| 激情欧美日韩一区二区| 国产麻豆精品在线| 成人av动漫在线| www久久精品| 国产精品美女视频| 一级日本不卡的影视| 午夜av电影一区| 91黄视频在线| 欧美日本在线观看| 欧美成人性战久久| 亚洲区中文字幕| www.久久久久久.com| 欧美成在线视频| 欧美亚洲第一区| 国产精品一二区| 99国产在线观看| 蜜桃传媒视频麻豆一区| 亚洲在线视频一区二区| 欧美午夜小视频| 黄色在线视频网| 精品国产一二区| 成人性生交大免费看| 日韩在线一卡二卡| 五月天综合激情| 亚洲一二区视频| 日本人妻丰满熟妇久久久久久| 蜜桃精品视频在线| gogogo免费视频观看亚洲一| 亚洲国产精品传媒在线观看| 亚洲国产乱码最新视频 | 国产成人a亚洲精品| 91精品综合视频| 九九九九精品| 超碰10000| 亚洲狠狠丁香婷婷综合久久久| 久久久噜噜噜| 国产精品123区| 国产亚洲精品中文字幕| 亚洲一区二区免费视频| 欧美日韩一级视频| 日韩电影中文字幕一区| 久热精品视频在线观看| 国产精品精品视频| 激情欧美一区二区三区中文字幕| 自拍亚洲欧美老师丝袜| 久久久噜噜噜www成人网| 美女被艹视频网站| 免费黄在线观看| 毛片基地在线观看| 黄频在线免费观看| 国产电影一区在线| 国产精品麻豆网站| 欧美主播一区二区三区| 日韩国产中文字幕| 国内精品久久久久| 国产二区不卡| 亚洲色婷婷久久精品av蜜桃| 天天干天天操天天做| 51妺嘿嘿午夜福利| 无码人妻熟妇av又粗又大| 手机在线观看免费av| 成人av免费观看| 亚洲国产va精品久久久不卡综合 | 成人99免费视频| 亚洲精品免费在线播放| 欧美自拍丝袜亚洲| 色乱码一区二区三区在线| 国产精品xxxxx| 黑人中文字幕一区二区三区| 中文字幕第50页| 永久免费毛片在线播放不卡| 九九九久久国产免费| 国产日韩精品视频| 一卡二卡3卡四卡高清精品视频| 日韩视频第二页| 国产美女喷水视频| 久久99国产综合精品免费| 欧美天堂在线视频| 2欧美一区二区三区在线观看视频 337p粉嫩大胆噜噜噜噜噜91av | 青青草原国产视频| 顶臀精品视频www| 亚洲一区中文字幕永久在线| 精品影院一区二区久久久| 中文字幕精品在线不卡| 欧美日韩成人高清| 欧美一级黑人aaaaaaa做受| 亚洲精品视频在线看| 欧美三级在线看| 国产亚洲免费的视频看| 国产精品 欧美在线| 日韩不卡av| 亚洲午夜av电影| 97高清免费视频| 蜜桃91精品入口| 在线视频日韩一区| 中文字幕美女视频| 亚洲乱码精品久久久久.. | 精品国产一区二区三区久久狼黑人| 国产精品日韩av| 三区精品视频观看| 欧美性猛交乱大交| 51国产偷自视频区视频| 国内精品免费**视频| 亚洲国产综合91精品麻豆| 亚洲精品在线91| 国产日韩欧美视频| 国产精品专区在线| 亚洲色图日韩精品| 丰满人妻av一区二区三区| 国产调教视频一区| 日韩欧美www| 国产aⅴ夜夜欢一区二区三区| 在线观看国产一区| 三叶草欧洲码在线| 91成人一区二区三区| 99久久伊人精品| 欧美男生操女生| 欧美性受xxxx黑人猛交| 在线播放 亚洲| 国产呦小j女精品视频| 97人妻精品一区二区三区视频| 99精品欧美一区二区三区综合在线| 91豆麻精品91久久久久久| 欧美成人精品xxx| 清纯唯美一区二区三区| 女同性αv亚洲女同志| 少妇又紧又色又爽又刺激视频| 成人激情视频网站| 7777精品伊人久久久大香线蕉完整版| 97国产一区二区精品久久呦| 超碰在线免费观看97| 久久亚洲AV无码专区成人国产| www.久久色| 亚洲视频免费看| 亚洲小视频在线| 国产伦一区二区三区色一情| 亚洲a级黄色片| 中文字幕69页| 2020日本不卡一区二区视频| 日韩精品一区二区三区视频| 日本一本a高清免费不卡| 国内精品国产三级国产99| 日韩女同一区二区三区| 老司机午夜精品视频在线观看| 亚洲高清免费观看| 欧美第一淫aaasss性| 国产av第一区| 国产午夜精品理论片| 久久精品国产第一区二区三区| 日本久久电影网| 日本道色综合久久影院| 欧美亚洲一二三区| www日韩精品| av在线一区二区| 亚洲成人久久一区| 国内一区在线| 中文字幕 日本| 色香蕉在线视频| 五月激情六月综合| 2020国产精品视频| 大陆极品少妇内射aaaaa| 中文字幕第28页| 99久久伊人精品| 亚洲男人的天堂网站| 免费日韩电影在线观看| 国产精品1000部啪视频| 丝袜诱惑亚洲看片| 欧美三级视频在线观看| 国产精品自拍偷拍| www.成人黄色| www.av在线.com| 午夜天堂影视香蕉久久| 欧美一级淫片播放口| av免费网站观看| 依依成人在线视频| 一区二区三区中文字幕电影| 欧美激情aaaa| 国产亚洲欧美在线视频| 波多野结衣电车痴汉| 亚洲视频一区二区在线| 欧美激情精品在线| 男人天堂999| 这里只有精品国产| 一区二区久久久久| 欧美一级片一区| 欧美一级特黄a| 国产suv精品一区二区69| 欧美日韩国产色视频| 国产精品激情自拍| 四虎国产精品永久免费观看视频| 女人18毛片一区二区三区| 欧美综合欧美视频| 国产高清精品一区| 伊人网在线视频观看| 国产精品1区二区.| 亚洲精品中文字幕av| 中文字幕欧美日韩一区二区三区| 久久久久成人网站| 国产喂奶挤奶一区二区三区| 另类美女黄大片| 无码aⅴ精品一区二区三区浪潮 | 精品亚洲欧美一区| 亚洲第一区第二区| 亚洲v国产v| 国产精品999久久久| 国产精品乱码一区二三区小蝌蚪| 欧美精品videosex性欧美| 天天操天天摸天天爽| 亚洲精品911| 欧美日韩国产色站一区二区三区| 国产精品一区二区三区不卡| 亚洲最大成人综合网| 99视频精品在线| 操人视频在线观看欧美| 亚洲乱码国产一区三区| 深爱激情五月婷婷| 日韩精品一区国产麻豆| 亚洲精品中文字幕在线| 欧美成人aaaaⅴ片在线看| 亚洲特级片在线| 国产精品电影网站| 一区二区视频观看| 成人永久免费视频| 久久在线视频在线| 在线观看的毛片| 三级久久三级久久久| 亚洲第一区在线观看| 男人的天堂视频在线| 亚洲在线视频播放| 欧美三级电影在线观看| 欧美日韩免费精品| 国产情侣在线视频| 亚洲成人tv网| 成人免费在线视频网站| 欧美a在线播放| 欧美极品少妇xxxxⅹ高跟鞋| 51午夜精品视频| 国产精品扒开腿做爽爽爽a片唱戏| 国产精品一二三四五| 久久精品视频网站| 四季av一区二区三区| 日本aⅴ精品一区二区三区| 亚洲欧美综合v| 欧美极品欧美精品欧美图片| 天天操天天干天天操| 亚洲精品国产美女| 乱妇乱女熟妇熟女网站| 午夜小视频在线播放| 亚洲摸下面视频| 成人3d动漫一区二区三区| 日韩精品乱码免费| 亚洲全黄一级网站| 久草福利视频在线| 狠狠色丁香婷婷综合| 久久精品91久久久久久再现| av噜噜在线观看| 国产高清不卡一区| 国内外成人免费激情在线视频网站 | 国外色69视频在线观看| 日本wwwwwww| 91麻豆.com| 国产精品久久久久久亚洲调教| www亚洲色图| 国产精品久久久久久久久动漫 | 国产传媒久久久| 理论片中文字幕| 亚洲人高潮女人毛茸茸| av污在线观看| 国产乱码字幕精品高清av | 国产传媒视频在线| 亚洲女人小视频在线观看| 99久久精品无码一区二区毛片| 日韩 欧美 精品| 欧美亚洲丝袜传媒另类| 中文字幕精品—区二区日日骚| 国产夫绿帽单男3p精品视频| 日韩精品视频在线| 五月天亚洲视频| 成人精品视频一区| 国产精品大陆在线观看| 亚洲AV成人无码精电影在线| 国产午夜精品一区二区三区视频 | 久久久久久亚洲av无码专区| 欧美性猛片aaaaaaa做受| 99亚洲精品视频| 亚洲爱情岛论坛永久| 亚洲欧美色图片| 欧美日韩理论片| xnxx国产精品| 成人精品久久久| 日韩欧美一区二区一幕| 欧美日韩日日夜夜| av日韩在线看| 美女脱光内衣内裤视频久久影院| 欧美另类在线观看| 人妻少妇无码精品视频区| 一区二区三区在线免费观看| 久久综合久久综合这里只有精品| 中文字幕在线日亚洲9| 亚洲缚视频在线观看| 91人人澡人人爽人人精品| thepron国产精品| 成人网中文字幕| 国产日产精品一区二区三区| 日韩视频免费观看高清在线视频| 男人亚洲天堂网| 成人精品一区二区三区四区| 国产精品一区二区三区免费视频 | 亚洲成a天堂v人片| 在线成人av电影| 久久精品女人天堂| 欧美激情精品久久久久久久变态| 亚洲女同二女同志奶水| 精品久久中文字幕久久av| 亚洲成年人专区| 青青草视频一区| 国产91精品青草社区| 久久久久久久九九九九| 欧美一区二区三区在线电影 | 国产欧美小视频| 91久久精品一区二区三| 日本中文字幕网址| 成人午夜又粗又硬又大| 91精品在线看| 中文字幕日韩经典| 亚洲色图15p| 亚洲乱码国产乱码精品精大量| 亚洲一区中文在线| 在线观看成人免费| 黄色精品一二区| 国产精品美女av| 国产精品久久久久久久久久精爆| 亚洲第一天堂av| 91porn在线| 亚洲午夜久久久久中文字幕久| 中文字幕成人一区| 国产一区二区三区久久久| 国产成a人亚洲| 欧美午夜不卡在线观看免费| www.激情网| 精品亚洲aⅴ乱码一区二区三区| 热草久综合在线| 欧美成人精品欧美一级乱黄| 欧美r级电影在线观看| www.亚洲自拍| 亚洲日本韩国一区| 欧美性视频在线播放| 国产一区二区三区国产| 欧美网站一区二区| 国产亚洲天堂网| 久久久国产一区二区三区四区小说 | 国产亚洲小视频| 亚洲福利精品在线| 国产高清成人久久| 欧美午夜性色大片在线观看| 久久网站免费视频| 久久久久久久久久久久久久久99| 国产日韩欧美二区| 亚州精品国产精品乱码不99按摩| 欧美在线性爱视频| 波多野结衣日韩| 日韩一级裸体免费视频| www.97视频| 精品久久人人做人人爱| 国产精品久久久久久久无码| 色诱亚洲精品久久久久久| 91视频免费版污| 亚洲欧美日韩综合aⅴ视频| 亚洲精品98久久久久久中文字幕| 欧洲永久精品大片ww免费漫画| 日韩成人av毛片| 亚洲人成在线观看网站高清| 波多野结衣一二三四区| 欧美一区二区啪啪| 国产999免费视频| 欧美日韩国产激情| 在线观看免费成人av| 亚洲激情第一区| 日韩免费一级视频| 国产精品国产成人国产三级| 男人天堂新网址| 国产无遮挡一区二区三区毛片日本| 在线成人午夜影院| 97人人模人人爽人人少妇| 亚洲av无码片一区二区三区| 欧美亚洲日本网站|