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

Go-Zero 的自適應(yīng)熔斷器

開發(fā) 后端
本篇文章會介紹主流熔斷器的工作原理,并且會借助 Go-Zero 源碼,分析 GoogleBreaker 是如何通過滑動窗口來統(tǒng)計(jì)流量,并且最終執(zhí)行熔斷的。

這篇文章來說說熔斷。

熔斷和限流還不太一樣,限流是控制請求速率,只要還能承受,那么都會處理,但熔斷不是。

在一條調(diào)用鏈上,如果發(fā)現(xiàn)某個服務(wù)異常,比如響應(yīng)超時。那么調(diào)用者為了避免過多請求導(dǎo)致資源消耗過大,最終引發(fā)系統(tǒng)雪崩,會直接返回錯誤,而不是瘋狂調(diào)用這個服務(wù)。

本篇文章會介紹主流熔斷器的工作原理,并且會借助 go-zero 源碼,分析 googleBreaker 是如何通過滑動窗口來統(tǒng)計(jì)流量,并且最終執(zhí)行熔斷的。

工作原理

這部分主要介紹兩種熔斷器的工作原理,分別是 Netflix 開源的 Hystrix,其也是 Spring Cloud 默認(rèn)的熔斷組件,和 Google 的自適應(yīng)的熔斷器。

Hystrix is no longer in active development, and is currently in maintenance mode.

注意,Hystrix 官方已經(jīng)宣布不再積極開發(fā)了,目前處在維護(hù)模式。

Hystrix 官方推薦替代的開源組件:Resilience4j,還有阿里開源的 Sentinel 也是不錯的替代品。

hystrixBreaker

Hystrix 采用了熔斷器模式,相當(dāng)于電路中的保險絲,系統(tǒng)出現(xiàn)緊急問題,立刻禁止所有請求,已達(dá)到保護(hù)系統(tǒng)的作用。

圖片

系統(tǒng)需要維護(hù)三種狀態(tài),分別是:

  • 關(guān)閉: 默認(rèn)狀態(tài),所有請求全部能夠通過。當(dāng)請求失敗數(shù)量增加,失敗率超過閾值時,會進(jìn)入到斷開狀態(tài)。
  • 斷開: 此狀態(tài)下,所有請求都會被攔截。當(dāng)經(jīng)過一段超時時間后,會進(jìn)入到半斷開狀態(tài)。
  • 半斷開: 此狀態(tài)下會允許一部分請求通過,并統(tǒng)計(jì)成功數(shù)量,當(dāng)請求成功時,恢復(fù)到關(guān)閉狀態(tài),否則繼續(xù)斷開。

通過狀態(tài)的變更,可以有效防止系統(tǒng)雪崩的問題。同時,在半斷開狀態(tài)下,又可以讓系統(tǒng)進(jìn)行自我修復(fù)。

googleBreaker

googleBreaker 實(shí)現(xiàn)了一種自適應(yīng)的熔斷模式,來看一下算法的計(jì)算公式,客戶端請求被拒絕的概率。

圖片

參數(shù)很少,也比較好理解:

  • requests:請求數(shù)量。
  • accepts:后端接收的請求數(shù)量。
  • K:敏感度,一般推薦 1.5-2 之間。

通過分析公式,我們可以得到下面幾個結(jié)論,也就是產(chǎn)生熔斷的實(shí)際原理:

  • 正常情況下,requests 和 accepts 是相等的,拒絕的概率就是 0,沒有產(chǎn)生熔斷。
  • 當(dāng)正常請求量,也就是 accepts 減少時,概率會逐漸增加,當(dāng)概率大于 0 時,就會產(chǎn)生熔斷。如果 accepts 等于 0 了,則完全熔斷。
  • 當(dāng)服務(wù)恢復(fù)后,requests 和 accepts 的數(shù)量會同時增加,但由于 K * accepts 增長的更快,所以概率又會很快變回到 0,相當(dāng)于關(guān)閉了熔斷。

總的來說,googleBreaker 的實(shí)現(xiàn)方案更加優(yōu)雅,而且參數(shù)也少,不用維護(hù)那么多的狀態(tài)。

go-zero 就是采用了 googleBreaker 的方案,下面就來分析代碼,看看到底是怎么實(shí)現(xiàn)的。

接口設(shè)計(jì)

接口定義這部分我個人感覺還是挺不好理解的,看了好多遍才理清了它們之間的關(guān)系。

其實(shí)看代碼和看書是一樣的,書越看越薄,代碼會越看越短。剛開始看感覺代碼很長,隨著看懂的地方越來越多,明顯感覺代碼變短了。所以遇到不懂的代碼不要怕,反復(fù)看,總會看懂的。

圖片

首先來看一下 breaker 部分的 UML 圖,有了這張圖,很多地方看起來還是相對清晰的,下面來詳細(xì)分析。

這里用到了靜態(tài)代理模式,也可以說是接口裝飾器,接下來就看看到底是怎么定義的:

// core/breaker/breaker.go
internalThrottle interface {
    allow() (internalPromise, error)
    doReq(req func() error, fallback func(err error) error, acceptable Acceptable) error
}

// core/breaker/googlebreaker.go
type googleBreaker struct {
    k     float64
    stat  *collection.RollingWindow
    proba *mathx.Proba
}

這個接口是最終實(shí)現(xiàn)熔斷方法的接口,由 googleBreaker 結(jié)構(gòu)體實(shí)現(xiàn)。

// core/breaker/breaker.go
throttle interface {
    allow() (Promise, error)
    doReq(req func() error, fallback func(err error) error, acceptable Acceptable) error
}

type loggedThrottle struct {
    name string
    internalThrottle
    errWin *errorWindow
}

func newLoggedThrottle(name string, t internalThrottle) loggedThrottle {
    return loggedThrottle{
        name:             name,
        internalThrottle: t,
        errWin:           new(errorWindow),
    }
}

這個是實(shí)現(xiàn)了日志收集的結(jié)構(gòu)體,首先它實(shí)現(xiàn)了 throttle 接口,然后它包含了一個字段 internalThrottle,相當(dāng)于具體的熔斷方法是代理給 internalThrottle 來做的。

// core/breaker/breaker.go
func (lt loggedThrottle) allow() (Promise, error) {
    promise, err := lt.internalThrottle.allow()
    return promiseWithReason{
        promise: promise,
        errWin:  lt.errWin,
    }, lt.logError(err)
}

func (lt loggedThrottle) doReq(req func() error, fallback func(err error) error, acceptable Acceptable) error {
    return lt.logError(lt.internalThrottle.doReq(req, fallback, func(err error) bool {
        accept := acceptable(err)
        if !accept && err != nil {
            lt.errWin.add(err.Error())
        }
        return accept
    }))
}

所以當(dāng)它執(zhí)行相應(yīng)方法時,都是直接調(diào)用 internalThrottle 接口的方法,然后再加上自己的邏輯。

這也就是代理所起到的作用,在不改變原方法的基礎(chǔ)上,擴(kuò)展原方法的功能。

// core/breaker/breaker.go
circuitBreaker struct {
    name string
    throttle
}

// NewBreaker returns a Breaker object.
// opts can be used to customize the Breaker.
func NewBreaker(opts ...Option) Breaker {
    var b circuitBreaker
    for _, opt := range opts {
        opt(&b)
    }
    if len(b.name) == 0 {
        b.name = stringx.Rand()
    }
    b.throttle = newLoggedThrottle(b.name, newGoogleBreaker())

    return &b
}

最終的熔斷器又將功能代理給了 throttle。

這就是它們之間的關(guān)系,如果感覺有點(diǎn)亂的話,就反復(fù)看,看的次數(shù)多了,就清晰了。

日志收集

上文介紹過了,loggedThrottle 是為了記錄日志而設(shè)計(jì)的代理層,這部分內(nèi)容來分析一下是如何記錄日志的。

// core/breaker/breaker.go
type errorWindow struct {
    // 記錄日志的數(shù)組
    reasons [numHistoryReasons]string
    // 索引
    index   int
    // 數(shù)組元素?cái)?shù)量,小于等于 numHistoryReasons
    count   int
    lock    sync.Mutex
}

func (ew *errorWindow) add(reason string) {
    ew.lock.Lock()
    // 記錄錯誤日志內(nèi)容
    ew.reasons[ew.index] = fmt.Sprintf("%s %s", time.Now().Format(timeFormat), reason)
    // 對 numHistoryReasons 進(jìn)行取余來得到數(shù)組索引
    ew.index = (ew.index + 1) % numHistoryReasons
    ew.count = mathx.MinInt(ew.count+1, numHistoryReasons)
    ew.lock.Unlock()
}

func (ew *errorWindow) String() string {
    var reasons []string

    ew.lock.Lock()
    // reverse order
    for i := ew.index - 1; i >= ew.index-ew.count; i-- {
        reasons = append(reasons, ew.reasons[(i+numHistoryReasons)%numHistoryReasons])
    }
    ew.lock.Unlock()

    return strings.Join(reasons, "\n")
}

核心就是這里采用了一個環(huán)形數(shù)組,通過維護(hù)兩個字段來實(shí)現(xiàn),分別是 index 和 count。

count 表示數(shù)組中元素的個數(shù),最大值是數(shù)組的長度;index 是索引,每次 +1,然后對數(shù)組長度取余得到新索引。

我之前有一次面試就讓我設(shè)計(jì)一個環(huán)形數(shù)組,當(dāng)時答的還不是很好,這次算是學(xué)會了。

滑動窗口

一般來說,想要判斷是否需要觸發(fā)熔斷,那么首先要知道一段時間的請求數(shù)量,一段時間內(nèi)的數(shù)量統(tǒng)計(jì)可以使用滑動窗口來實(shí)現(xiàn)。

首先看一下滑動窗口的定義:

// core/collection/rollingwindow.go

type RollingWindow struct {
    lock          sync.RWMutex
    // 窗口大小
    size          int
    // 窗口數(shù)據(jù)容器
    win           *window
    // 時間間隔
    interval      time.Duration
    // 游標(biāo),用于定位當(dāng)前應(yīng)該寫入哪個 bucket
    offset        int
    // 匯總數(shù)據(jù)時,是否忽略當(dāng)前正在寫入桶的數(shù)據(jù)
    // 某些場景下因?yàn)楫?dāng)前正在寫入的桶數(shù)據(jù)并沒有經(jīng)過完整的窗口時間間隔
    // 可能導(dǎo)致當(dāng)前桶的統(tǒng)計(jì)并不準(zhǔn)確
    ignoreCurrent bool
    // 最后寫入桶的時間
    // 用于計(jì)算下一次寫入數(shù)據(jù)間隔最后一次寫入數(shù)據(jù)的之間
    // 經(jīng)過了多少個時間間隔
    lastTime      time.Duration // start time of the last bucket
}

再來看一下 window 的結(jié)構(gòu):

type Bucket struct {
    // 桶內(nèi)值的和
    Sum   float64
    // 桶內(nèi) add 次數(shù)
    Count int64
}

func (b *Bucket) add(v float64) {
    b.Sum += v
    b.Count++
}

func (b *Bucket) reset() {
    b.Sum = 0
    b.Count = 0
}

type window struct {
    // 桶,一個桶就是一個時間間隔
    buckets []*Bucket
    // 窗口大小,也就是桶的數(shù)量
    size    int
}

有了這兩個結(jié)構(gòu)之后,我們就可以畫出這個滑動窗口了,如圖所示。

圖片

現(xiàn)在來看一下向窗口中添加數(shù)據(jù),是怎樣一個過程。

func (rw *RollingWindow) Add(v float64) {
    rw.lock.Lock()
    defer rw.lock.Unlock()
    // 獲取當(dāng)前寫入下標(biāo)
    rw.updateOffset()
    // 向 bucket 中寫入數(shù)據(jù)
    rw.win.add(rw.offset, v)
}

func (rw *RollingWindow) span() int {
    // 計(jì)算距離 lastTime 經(jīng)過了多少個時間間隔,也就是多少個桶
    offset := int(timex.Since(rw.lastTime) / rw.interval)
    // 如果在窗口范圍內(nèi),返回實(shí)際值,否則返回窗口大小
    if 0 <= offset && offset < rw.size {
        return offset
    }

    return rw.size
}

func (rw *RollingWindow) updateOffset() {
    // 經(jīng)過了多少個時間間隔,也就是多少個桶
    span := rw.span()
    // 還在同一單元時間內(nèi)不需要更新
    if span <= 0 {
        return
    }

    offset := rw.offset
    // reset expired buckets
    // 這里是清除過期桶的數(shù)據(jù)
    // 也是對數(shù)組大小進(jìn)行取余的方式,類似上文介紹的環(huán)形數(shù)組
    for i := 0; i < span; i++ {
        rw.win.resetBucket((offset + i + 1) % rw.size)
    }

    // 更新游標(biāo)
    rw.offset = (offset + span) % rw.size
    now := timex.Now()
    // align to interval time boundary
    // 這里應(yīng)該是一個時間的對齊,保持在桶內(nèi)指向位置是一致的
    rw.lastTime = now - (now-rw.lastTime)%rw.interval
}

// 向桶內(nèi)添加數(shù)據(jù)
func (w *window) add(offset int, v float64) {
    // 根據(jù) offset 對數(shù)組大小取余得到索引,然后添加數(shù)據(jù)
    w.buckets[offset%w.size].add(v)
}

// 重置桶數(shù)據(jù)
func (w *window) resetBucket(offset int) {
    w.buckets[offset%w.size].reset()
}

我畫了一張圖,來模擬整個滑動過程:

圖片

主要經(jīng)歷 4 個步驟:

  • 計(jì)算當(dāng)前時間距離上次添加時間經(jīng)過了多少個時間間隔,也就是多少個 bucket。
  • 清理過期桶數(shù)據(jù)。
  • 更新 offset,更新 offset 的過程實(shí)際就是模擬窗口滑動的過程。
  • 添加數(shù)據(jù)。

比如上圖,剛開始 offset 指向了 bucket[1],經(jīng)過了兩個 span 之后,bucket[2] 和 bucket[3] 會被清空,同時,新的 offset 會指向 bucket[3],新添加的數(shù)據(jù)會寫入到 bucket[3]。

再來看看數(shù)據(jù)統(tǒng)計(jì),也就是窗口內(nèi)的有效數(shù)據(jù)量是多少。

// Reduce runs fn on all buckets, ignore current bucket if ignoreCurrent was set.
func (rw *RollingWindow) Reduce(fn func(b *Bucket)) {
    rw.lock.RLock()
    defer rw.lock.RUnlock()

    var diff int
    span := rw.span()
    // ignore current bucket, because of partial data
    if span == 0 && rw.ignoreCurrent {
        diff = rw.size - 1
    } else {
        diff = rw.size - span
    }
    // 需要統(tǒng)計(jì)的 bucket 數(shù)量,窗口大小減去 span 數(shù)量
    if diff > 0 {
        // 獲取統(tǒng)計(jì)的起始位置,span 是已經(jīng)被重置的 bucket
        offset := (rw.offset + span + 1) % rw.size
        rw.win.reduce(offset, diff, fn)
    }
}

func (w *window) reduce(start, count int, fn func(b *Bucket)) {
    for i := 0; i < count; i++ {
        // 自定義統(tǒng)計(jì)函數(shù)
        fn(w.buckets[(start+i)%w.size])
    }
}

統(tǒng)計(jì)出窗口數(shù)據(jù)之后,就可以判斷是否需要熔斷了。

執(zhí)行熔斷

接下來就是執(zhí)行熔斷了,主要就是看看自適應(yīng)熔斷是如何實(shí)現(xiàn)的。

// core/breaker/googlebreaker.go

const (
    // 250ms for bucket duration
    window     = time.Second * 10
    buckets    = 40
    k          = 1.5
    protection = 5
)

窗口的定義部分,整個窗口是 10s,然后分成 40 個 bucket,每個 bucket 就是 250ms。

// googleBreaker is a netflixBreaker pattern from google.
// see Client-Side Throttling section in https://landing.google.com/sre/sre-book/chapters/handling-overload/
type googleBreaker struct {
    k     float64
    stat  *collection.RollingWindow
    proba *mathx.Proba
}

func (b *googleBreaker) accept() error {
    // 獲取最近一段時間的統(tǒng)計(jì)數(shù)據(jù)
    accepts, total := b.history()
    // 根據(jù)上文提到的算法來計(jì)算一個概率
    weightedAccepts := b.k * float64(accepts)
    // https://landing.google.com/sre/sre-book/chapters/handling-overload/#eq2101
    dropRatio := math.Max(0, (float64(total-protection)-weightedAccepts)/float64(total+1))
    // 如果小于等于 0 直接通過,不熔斷
    if dropRatio <= 0 {
        return nil
    }

    // 隨機(jī)產(chǎn)生 0.0-1.0 之間的隨機(jī)數(shù)與上面計(jì)算出來的熔斷概率相比較
    // 如果隨機(jī)數(shù)比熔斷概率小則進(jìn)行熔斷
    if b.proba.TrueOnProba(dropRatio) {
        return ErrServiceUnavailable
    }

    return nil
}

func (b *googleBreaker) history() (accepts, total int64) {
    b.stat.Reduce(func(b *collection.Bucket) {
        accepts += int64(b.Sum)
        total += b.Count
    })

    return
}

以上就是自適應(yīng)熔斷的邏輯,通過概率的比較來隨機(jī)淘汰掉部分請求,然后隨著服務(wù)恢復(fù),淘汰的請求會逐漸變少,直至不淘汰。

func (b *googleBreaker) allow() (internalPromise, error) {
    if err := b.accept(); err != nil {
        return nil, err
    }

    // 返回一個 promise 異步回調(diào)對象,可由開發(fā)者自行決定是否上報(bào)結(jié)果到熔斷器
    return googlePromise{
        b: b,
    }, nil
}

// req - 熔斷對象方法
// fallback - 自定義快速失敗函數(shù),可對熔斷產(chǎn)生的err進(jìn)行包裝后返回
// acceptable - 對本次未熔斷時執(zhí)行請求的結(jié)果進(jìn)行自定義的判定,比如可以針對http.code,rpc.code,body.code
func (b *googleBreaker) doReq(req func() error, fallback func(err error) error, acceptable Acceptable) error {
    if err := b.accept(); err != nil {
        // 熔斷中,如果有自定義的fallback則執(zhí)行
        if fallback != nil {
            return fallback(err)
        }

        return err
    }

    defer func() {
        // 如果執(zhí)行req()過程發(fā)生了panic,依然判定本次執(zhí)行失敗上報(bào)至熔斷器
        if e := recover(); e != nil {
            b.markFailure()
            panic(e)
        }
    }()

    err := req()
    // 上報(bào)結(jié)果
    if acceptable(err) {
        b.markSuccess()
    } else {
        b.markFailure()
    }

    return err
}

熔斷器對外暴露兩種類型的方法:

簡單場景直接判斷對象是否被熔斷,執(zhí)行請求后必須需手動上報(bào)執(zhí)行結(jié)果至熔斷器。

func (b *googleBreaker) allow() (internalPromise, error)

復(fù)雜場景下支持自定義快速失敗,自定義判定請求是否成功的熔斷方法,自動上報(bào)執(zhí)行結(jié)果至熔斷器。

func (b *googleBreaker) doReq(req func() error, fallback func(err error) error, acceptable Acceptable) error

個人感覺,熔斷這部分代碼,相較于前幾篇文章,理解起來是更困難的。但其中的一些設(shè)計(jì)思想,和底層的實(shí)現(xiàn)原理也是非常值得學(xué)習(xí)的,希望這篇文章能夠?qū)Υ蠹矣袔椭?/p>

參考文章:

  • https://juejin.cn/post/7030997067560386590。
  • https://go-zero.dev/docs/tutorials/service/governance/breaker。
  • https://sre.google/sre-book/handling-overload/。
  • https://martinfowler.com/bliki/CircuitBreaker.html。
責(zé)任編輯:姜華 來源: AlwaysBeta
相關(guān)推薦

2021-11-25 09:55:47

Golang熔斷器語言

2023-08-10 08:00:42

令牌限流器計(jì)數(shù)器

2023-08-07 08:01:15

2025-05-26 04:00:00

2024-04-28 14:46:55

gozero微服務(wù)技巧

2022-05-13 09:05:49

Hystrix熔斷器

2014-08-14 10:10:34

設(shè)計(jì)模式熔斷器

2017-06-06 10:30:12

前端Web寬度自適應(yīng)

2025-01-21 08:00:00

自適應(yīng)框架框架開發(fā)

2022-10-24 17:57:06

CSS容器查詢

2012-05-09 10:58:25

JavaMEJava

2014-09-05 10:10:32

Android自適應(yīng)布局設(shè)計(jì)

2010-08-30 09:52:03

DIV高度自適應(yīng)

2010-08-30 10:26:20

DIV自適應(yīng)高度

2023-07-31 08:24:34

MySQL索引計(jì)數(shù)

2014-04-15 13:09:08

Android配色colour

2020-09-09 09:51:41

神經(jīng)網(wǎng)絡(luò)DA技術(shù)感知器

2015-06-08 10:49:04

2010-08-30 09:22:13

DIV高度自適應(yīng)

2025-05-28 02:40:00

AdaptThink推理模型AI
點(diǎn)贊
收藏

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

综合另类专区| 国产精品无码天天爽视频| 日韩av资源网| 一本色道亚洲精品aⅴ| 美国av一区二区三区| 26uuu成人网| 在线精品自拍| 黑人巨大精品欧美一区二区三区| 欧美连裤袜在线视频| 国产精品乱码一区二区视频| 天堂网av成人| 在线免费观看不卡av| 亚洲一区二三| 免费国产精品视频| 老鸭窝毛片一区二区三区| 亚洲人成在线观看网站高清| 久热精品在线观看视频| 直接在线观看的三级网址| 国产91精品露脸国语对白| 欧美一级淫片videoshd| 99国产精品免费| 51精品国产| 色婷婷综合久色| 9191国产视频| 久久精品色图| 精品一区二区三区的国产在线播放| 欧美激情一区二区三区在线视频观看 | 欧美日韩生活片| 91麻豆免费在线视频| 国产精品1区2区3区| 57pao成人国产永久免费| 夜夜春很很躁夜夜躁| 超碰在线成人| 日韩精品一区第一页| 成人av资源站| 国产精品日韩av| 日韩精品乱码久久久久久| 99re6这里只有精品| 日韩精品亚洲元码| 女教师高潮黄又色视频| 亚洲成人毛片| 欧美日韩成人一区二区| 欧美成人黄色网址| 亚洲伊人av| 午夜精品福利一区二区蜜股av| 国产四区在线观看| 四虎久久免费| 国产精品视频麻豆| 五月天综合网| 超碰免费在线观看| 国产性色一区二区| 日本视频一区在线观看| 免费av在线电影| 久久美女高清视频 | 成人h动漫免费观看网站| 欧美一区二区日韩一区二区| 亚洲免费av一区| 日韩一区中文| 欧美一区日韩一区| 极品人妻一区二区| 91麻豆精品国产91久久久久推荐资源| 欧美一级搡bbbb搡bbbb| 免费看的av网站| 国产 日韩 欧美 综合 一区| 日韩成人激情视频| wwwwxxxx国产| 三上亚洲一区二区| 久久精品久久久久| 国产97免费视频| 好看不卡的中文字幕| 91精品国产91久久久久久吃药 | 欧美二区不卡| 欧美激情中文字幕乱码免费| 中文在线观看免费网站| 亚洲欧美网站| 国产精品视频1区| 国产一区二区在线视频聊天| 国产精品一区二区果冻传媒| 国产欧美欧洲| 三级黄视频在线观看| 国产女人水真多18毛片18精品视频 | 乱子伦视频在线看| 国产精品成人国产| 欧美一区二区三区在线观看| 91精品又粗又猛又爽| 久久香蕉精品香蕉| 色吧影院999| 一区二区三区免费高清视频| 美女精品一区| 91午夜在线播放| 五月婷婷丁香花| 国产精品五月天| 青青草国产免费| 成人欧美大片| 91精品免费在线| www.88av| 在线观看国产精品入口| 日韩免费av在线| 99视频在线观看免费| 久久午夜色播影院免费高清| 中国老女人av| 欧美日韩免费观看视频| 欧美va亚洲va国产综合| 色欲AV无码精品一区二区久久 | 欧美成人精品影院| 久久一区二区三区视频| 国模一区二区三区白浆| 牛人盗摄一区二区三区视频| 成人影院在线观看| 色菇凉天天综合网| 亚洲欧美日韩色| 国产电影一区二区在线观看| 欧美在线观看网址综合| 精品人妻无码一区二区色欲产成人 | 性少妇bbw张开| 欧美a级片网站| 国产成人精品久久久| 东京干手机福利视频| 国产精品国产精品国产专区不片 | 日本网站在线观看一区二区三区| 97人摸人人澡人人人超一碰| 国产二区视频在线观看| 亚洲成av人片一区二区三区 | 免费视频观看成人| 亚洲国产高潮在线观看| www.超碰在线观看| 另类欧美日韩国产在线| 青青成人在线| 精精国产xxxx视频在线播放| 欧美va在线播放| 曰本女人与公拘交酡| 精品一区二区国语对白| 日韩三级在线播放| 欧美黑人粗大| 精品无人区太爽高潮在线播放| 免费在线观看国产精品| 国产一区二区三区在线观看精品 | 欧美日韩三级在线| 国产全是老熟女太爽了| 亚洲欧美日韩国产一区二区| 国产中文一区二区| 激情网站在线| 精品日韩欧美在线| 久久精品一区二区三| 国产在线国偷精品免费看| 一区二区三区我不卡| jizz亚洲女人高潮大叫| 最近免费中文字幕视频2019| 中文字幕一区2区3区| 亚洲国产精品二十页| 色乱码一区二区三区在线| 日韩在线观看电影完整版高清免费悬疑悬疑| 日韩av片免费在线观看| 九九九伊在人线综合| 色婷婷av一区二区| 人人人妻人人澡人人爽欧美一区| 日韩高清国产一区在线| 涩涩涩999| 欧美亚洲二区| 欧美成人午夜免费视在线看片| 99国产精品久久久久99打野战| 亚洲欧美另类久久久精品| 亚洲av无码久久精品色欲| 红桃视频欧美| 久久久久久国产精品一区| 中文字幕不卡三区视频| 一区二区三区在线播放欧美| 亚洲字幕av一区二区三区四区| 18成人在线视频| 无码人妻一区二区三区在线视频| 亚洲视频日本| 欧美日韩大片一区二区三区| 精品三级在线| 久久久久国产精品免费| 午夜黄色小视频| 欧美在线观看一区二区| 久草福利资源在线| 成人午夜视频网站| 免费日韩视频在线观看| 久久国产亚洲精品| 俄罗斯精品一区二区三区| 欧美黑人一区| 精品中文字幕在线2019| 欧美成熟毛茸茸| 88在线观看91蜜桃国自产| 国产精品suv一区二区| 国产日韩精品久久久| 亚欧精品在线视频| 99亚洲一区二区| 亚洲视频在线观看日本a| 亚洲精品黑牛一区二区三区| 欧美亚洲午夜视频在线观看| 午夜激情视频在线观看| 亚洲成**性毛茸茸| 一区二区乱子伦在线播放| 亚洲精品免费一二三区| 性猛交娇小69hd| 国产盗摄视频一区二区三区| 黑鬼大战白妞高潮喷白浆| 在线观看免费一区二区| 日本免费高清一区| 99这里只有精品视频| 国产精品第1页| 91丝袜在线| 久久久成人的性感天堂| 亚洲欧美综合在线观看| 欧美一区二区三区在线| 亚洲高清在线看| 婷婷久久综合九色综合伊人色| 国产精品麻豆免费版现看视频| 99久久精品国产网站| 精品人妻一区二区三| 免费观看在线综合| 欧美a在线视频| 国内综合精品午夜久久资源| 一区二区三区不卡在线| 女厕嘘嘘一区二区在线播放 | 国产伦精品一区二区三区千人斩| 147欧美人体大胆444| 成人开心激情| 国产69久久精品成人看| av免费在线视| 蜜臀久久99精品久久久无需会员 | 日本不卡高字幕在线2019| 欧美色图天堂| 欧美剧在线观看| 国产淫片在线观看| 日韩中文字幕在线精品| 国产黄在线播放| 亚洲欧美色婷婷| 深夜福利在线观看直播| 337p日本欧洲亚洲大胆色噜噜| 国产成人a人亚洲精品无码| 在线观看91av| 91成人在线免费| 欧美日韩国产一二三| 日本一本在线观看| 色综合视频一区二区三区高清| 日产欧产va高清| 亚洲成av人片一区二区| 精品少妇久久久久久888优播| 亚洲欧美成人一区二区三区| 国产午夜精品理论片| 中文字幕中文字幕在线一区 | 国产在线视频网站| 精品无人区乱码1区2区3区在线| 婷婷视频在线观看| 精品国产一区二区在线观看| 亚洲国产福利视频| 精品盗摄一区二区三区| 丰满少妇在线观看bd| 欧美大片一区二区| 黄色aaa毛片| 日韩国产精品视频| 深夜福利在线观看直播| 亚洲品质视频自拍网| 黄色av免费在线看| 国产一区二区三区视频 | 久久人人爽人人爽人人片av高清| 欧美男男video| 国模视频一区二区三区| 999av小视频在线| 91高清视频免费| 欧美xxx网站| 国产一区私人高清影院| 国产精品亚洲四区在线观看| ts人妖另类在线| 欧美交a欧美精品喷水| 欧美xxxx黑人又粗又长精品| 精品大片一区二区| 波多野结衣激情| 国产精品激情电影| 日韩av片在线看| 久草这里只有精品视频| 2018国产精品| 国产亚洲成aⅴ人片在线观看 | 亚洲av人人澡人人爽人人夜夜| 91麻豆国产香蕉久久精品| 长河落日免费高清观看| 樱桃国产成人精品视频| 69视频免费在线观看| 欧美日韩国产综合视频在线观看| 丁香六月色婷婷| 伊人伊成久久人综合网小说| 亚洲性图自拍| 人人澡人人澡人人看欧美| 996久久国产精品线观看| 国产日韩二区| 日本激情一区| 欧美激情 国产精品| 男女男精品视频| 69亚洲乱人伦| 中日韩免费视频中文字幕| 国产精品18p| 欧美久久一二三四区| 性感美女一级片| 久久高清视频免费| 偷拍中文亚洲欧美动漫| 亚洲最大av在线| 精品福利久久久| 亚洲美免无码中文字幕在线| 国产一区日韩二区欧美三区| 性欧美精品中出| 亚洲一区二区综合| 在线视频欧美亚洲| 精品视频久久久久久| caoporn免费在线| 国产精品久久久久久av| 国语一区二区三区| 欧美aaa在线观看| 久久一二三四| 50一60岁老妇女毛片| 亚洲人亚洲人成电影网站色| 男操女视频网站| 日韩精品中文在线观看| 丝袜美女在线观看| 国产在线视频91| 成人av二区| 日日碰狠狠躁久久躁婷婷| 成人免费观看av| 翔田千里88av中文字幕| 欧美日韩国产美| 成年网站在线| 奇米影视亚洲狠狠色| 97se亚洲国产一区二区三区| 正在播放久久| 日本系列欧美系列| 精品欧美一区二区久久久| 黄色精品在线看| 色婷婷av一区二区三区之e本道| 欧美成在线视频| 99re8精品视频在线观看| 亚洲精品影院| 日日夜夜精品免费视频| 新91视频在线观看| 色综合一个色综合| 天堂av在线资源| 2023亚洲男人天堂| 宅男在线一区| 亚洲视频在线a| 国产日韩欧美精品综合| 日本熟女毛茸茸| 亚洲少妇中文在线| 欧美国产日韩电影| 亚洲区一区二区三区| 欧美a一区二区| 国产aaaaaaaaa| 91麻豆精品国产91久久久久久久久| 在线观看精品一区二区三区| 国产欧美日韩丝袜精品一区| 欧美激情国产在线| 亚洲一二区在线观看| 一区二区三区免费在线观看| 亚洲精品18p| 97色在线视频观看| 美女精品一区最新中文字幕一区二区三区| 天堂…中文在线最新版在线| proumb性欧美在线观看| 色婷婷av国产精品| 亚洲丝袜在线视频| 欧美一级做一级爱a做片性| 中文字幕精品在线播放| 国产成人av电影在线观看| 亚洲欧美在线观看视频| 亚洲欧美中文字幕| 免费成人黄色网| 国产成人在线小视频| 91婷婷韩国欧美一区二区| 久久精品99北条麻妃| 久久艳片www.17c.com | 精品女同一区二区| 五月天国产在线| 性刺激综合网| 粉嫩嫩av羞羞动漫久久久| 国内自拍视频在线播放| 日韩有码在线视频| 动漫3d精品一区二区三区乱码| 日韩视频第二页| 综合欧美亚洲日本| 手机看片福利永久| 国产精品久久久久影院日本| 午夜国产精品视频免费体验区| 少妇饥渴放荡91麻豆| 欧美日本乱大交xxxxx| 超碰在线网站| 亚洲va久久久噜噜噜久久狠狠| 国产精品123区| 中文字幕在线看人| 欧美国产一区二区三区| 米奇777超碰欧美日韩亚洲| 99视频在线观看视频| 日韩欧美极品在线观看| 米奇精品一区二区三区| 国产一区二区三区奇米久涩| 美腿丝袜在线亚洲一区| 国产精品久久久久久99| 久久久av网站| 欧美色图在线播放| 亚洲av无码专区在线播放中文| 欧美私人免费视频|