精品欧美一区二区三区在线观看 _久久久久国色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免费网址| 免费一级全黄少妇性色生活片| 色在线视频观看| 91在线免费播放| 国产精品91在线| 777777国产7777777| 成人午夜网址| 欧美在线一区二区| 99久久免费观看| 噜噜噜噜噜在线视频| 激情丁香综合五月| 7777kkkk成人观看| 美国黄色特级片| www.成人网| 欧美日韩一区二区电影| 免费看黄在线看| 亚洲中文字幕无码一区二区三区 | 99久久精品99国产精品| 日韩免费不卡av| 亚洲国产美女视频| 欧美精品第一区| 日韩欧美激情在线| 午夜免费精品视频| 国产在线精彩视频| 亚洲图片欧美激情| 乱一区二区三区在线播放| www.激情五月| 欧美aaaaa成人免费观看视频| 欧美精品久久久久| www.av免费| 国产亚洲一卡2卡3卡4卡新区| 日韩欧美国产高清| 无限资源日本好片| 一个人看的www视频在线免费观看| 亚洲美女偷拍久久| 色乱码一区二区三在线看| 天堂网av2014| 国产成人av福利| 国产在线视频2019最新视频| 蜜臀精品一区二区三区| 一本久道综合久久精品| 欧美精品videofree1080p| 99成人在线观看| 日韩国产综合| 久久精品动漫| 一区二区三区不卡在线观看| 日韩精品国内| 日本在线视频1区| 99免费精品在线观看| 5g影院天天爽成人免费下载| 一女二男一黄一片| 蜜臀va亚洲va欧美va天堂| 国产成人啪精品视频免费网| 国产99免费视频| 亚洲欧美成人| 欧美在线国产精品| 免费观看成人毛片| 国产精品资源| 日本aⅴ大伊香蕉精品视频| 日本在线视频中文字幕| 激情丁香综合| 久久久久中文字幕2018| 欧美日韩中文视频| 亚洲黄色影片| 9.1国产丝袜在线观看| 天堂网一区二区三区| 精品动漫3d一区二区三区免费版| 久久久久久亚洲| 日韩无码精品一区二区三区| 一本色道久久综合亚洲精品不卡 | 奇米精品一区二区三区四区| 国产精品久久久久久一区二区| 69视频免费看| 六月婷婷色综合| 成人久久精品视频| 亚洲爱爱综合网| 波多野结衣91| 欧美日韩精品免费观看| 91在线播放网站| 亚洲男人电影天堂| 国产精品成人久久电影| 竹内纱里奈兽皇系列在线观看| 色呦呦日韩精品| 91小视频网站| 日韩精品久久久久久久软件91| 精品免费国产一区二区三区四区| 欧美精品亚洲一区二区在线播放| 成人免费毛片网| 欧美日韩精品免费观看视完整| 欧洲精品在线观看| а 天堂 在线| 91夜夜蜜桃臀一区二区三区| 亚洲男人天天操| 日韩av片在线免费观看| 欧美久色视频| 日产日韩在线亚洲欧美| 一本大道伊人av久久综合| 国产成人自拍网| 免费一区二区三区| 黄色免费在线网站| 精品久久中文字幕久久av| 杨幂毛片午夜性生毛片| 中文在线综合| 在线免费看av不卡| 免费在线视频观看| 老司机精品久久| 97视频中文字幕| 欧美777四色影视在线| 亚洲视频一区在线| 欧美 日韩 国产在线观看| 日本欧美在线| 亚洲精品一区二区三区婷婷月| 成年人免费视频播放| 在线日韩欧美| 成人国产精品一区二区| 四虎影院在线播放| 亚洲激情网站免费观看| 欧美性猛交久久久乱大交小说| 综合激情久久| 狠狠色丁香久久综合频道| 亚洲欧美国内爽妇网| 成人自拍小视频| 视频在线观看91| 国产精品久久国产精品| 欧美三级电影一区二区三区| 欧美性20hd另类| 性高潮久久久久久| 99成人在线视频| 国产成人综合亚洲| 日韩a在线看| 亚洲国产欧美在线人成| 午夜xxxxx| 日韩电影免费在线观看| 国产成人91久久精品| 熟妇人妻系列aⅴ无码专区友真希| 亚洲欧洲日韩在线| 青青草av网站| 中国av一区| 26uuu亚洲伊人春色| 国模人体一区二区| 一区二区在线看| 亚洲免费在线播放视频| 成人在线免费小视频| 日韩av快播网址| 男男激情在线| 色综合视频在线观看| 国产精品久久无码| 亚洲高清久久| 国产乱码精品一区二区三区中文 | 538任你躁在线精品免费| 久久精品亚洲成在人线av网址| 久久五月情影视| 亚洲在线视频播放| 国产精品久久一级| 在线观看av网页| 日韩一区自拍| 国产视频999| 1024免费在线视频| 欧美日韩在线亚洲一区蜜芽| 国产美女免费网站| 日本伊人色综合网| 午夜精品一区二区在线观看的| 欧美va在线| 一本色道久久88综合日韩精品| 国产精品乱码一区二区视频| 国产三级三级三级精品8ⅰ区| 无人在线观看的免费高清视频| 超碰成人久久| 国产日韩精品一区二区| 国产高清一区二区三区视频| 欧美一区二区三区喷汁尤物| 九九热精彩视频| 成年人国产精品| aaa毛片在线观看| 日本不卡二三区| 成人亚洲综合色就1024| 天使と恶魔の榨精在线播放| 精品久久五月天| 国产成人无码精品| 久久久精品黄色| 国产精品v日韩精品v在线观看| 亚洲啊v在线观看| 99re国产在线播放| 超碰在线99| 国产午夜一区二区| 国产精品久久久久久久一区二区| 夜夜嗨av一区二区三区中文字幕| 久久久久亚洲AV成人无码国产| 日韩黄色在线观看| 男人的天堂视频在线| 日韩在线影视| 91精品久久久久久久久久久久久| 午夜av在线播放| 亚洲欧洲自拍偷拍| 91极品身材尤物theporn| 亚洲国产精品久久久久秋霞影院 | 亚洲乱熟女一区二区| 一本一道久久a久久精品| 久久精品国产亚洲精品2020| 国精品无码一区二区三区| 懂色av一区二区三区免费观看| www黄色av| 中文字幕人成人乱码| 免费看成人片| 日韩08精品| 国产999精品久久久| 蜜臀av在线| 有码中文亚洲精品| 日本精品久久久久| 欧美精品一二三| 韩国av免费观看| 成人免费在线视频观看| 国产亚洲色婷婷久久99精品91| 国模大尺度一区二区三区| 无码精品a∨在线观看中文| 2023国产精品久久久精品双| 免费av一区二区三区| 亚洲综合色婷婷在线观看| 国产精品久久久久久久久影视| 黄色漫画在线免费看| 欧美不卡视频一区发布| a天堂中文在线| 日韩精品免费看| 亚洲爱爱综合网| 制服.丝袜.亚洲.另类.中文| 波多野结衣人妻| 欧美日韩国产在线看| 美女的奶胸大爽爽大片| 欧美高清在线视频| 白丝女仆被免费网站| av在线一区二区三区| 国产亚洲色婷婷久久| 久99久精品视频免费观看| 国产天堂在线播放| 亚洲欧美春色| 久久免费视频3| 99久久久国产精品无码网爆| 久久精品国产一区二区| 国产精品免费观看久久| 99av国产精品欲麻豆| 精品人妻人人做人人爽| 亚洲精品一区二区在线看| 亚洲国产激情一区二区三区| 国产精品一区二区av交换| 精品国产一区二区三区久久久久久| 久久9999免费视频| 亚洲综合在线做性| 久久久久久久久成人| 91精品久久久久久蜜桃| 国产一区一区| 51国偷自产一区二区三区的来源| 精品国产亚洲一区二区三区大结局| 国产日本欧美一区| 日韩五码电影| 4444kk亚洲人成电影在线| 久久免费精品| 国产成人精品免费视频大全最热 | 天天操天天舔天天射| 久久精品亚洲精品国产欧美| 国产ts丝袜人妖系列视频| 91丝袜高跟美女视频| 无码国产69精品久久久久同性| 久久色在线视频| 国产熟女一区二区| 国产精品成人免费在线| 麻豆网址在线观看| 亚洲精品免费电影| 久久精品国产亚洲AV无码男同 | 97超碰在线视| 黄色综合网站| 国产视频一视频二| 日韩中文字幕综合| 国产高清亚洲一区| 日本网站在线看| 成人午夜激情视频| 亚洲天堂网一区二区| 欧美国产成人在线| 欧美日韩三级在线观看| 天天影视涩香欲综合网| 波多野结衣黄色网址| 欧美一区二区三区精品| 天堂成人在线观看| 一本久久综合亚洲鲁鲁| bestiality新另类大全| 97国产精品视频人人做人人爱| 欧美精品总汇| 亚洲一区二区三区香蕉| 日韩欧美在线精品| 视频在线99| 亚洲国产专区校园欧美| 无码日韩人妻精品久久蜜桃| 国产精品自拍网站| 90岁老太婆乱淫| 亚洲精品国产无套在线观 | 91国偷自产一区二区三区成为亚洲经典| 中文字幕乱码人妻二区三区| 欧美一区二区视频免费观看| 亚洲av成人精品毛片| 中文在线资源观看视频网站免费不卡| 97影院秋霞午夜在线观看| 日本韩国欧美精品大片卡二| 日韩电影精品| 久久99热只有频精品91密拍| 999国产精品| 97超碰青青草| 国产精品一区二区免费不卡| 亚欧洲乱码视频| 一区二区高清免费观看影视大全 | 久久五月激情| 熟妇女人妻丰满少妇中文字幕| 不卡视频一二三四| 成年人网站在线观看视频| 欧美性猛交xxxx乱大交蜜桃| 国产麻豆精品一区| 国产亚洲精品一区二555| 金瓶狂野欧美性猛交xxxx| 日韩av中文字幕一区二区| 欧美极品欧美精品欧美| 国产制服丝袜一区| 国产ts丝袜人妖系列视频| 一区二区三区四区精品在线视频 | 精品无码人妻一区二区免费蜜桃 | 99久久久无码国产精品免费蜜柚| 日韩欧美中文字幕精品| 日本在线视频网| 欧洲成人午夜免费大片| 久久91在线| 黄色网在线视频| 韩国欧美一区二区| 2019男人天堂| 欧美性猛交xxxx黑人| 天天干天天摸天天操| 色在人av网站天堂精品| 亚洲男人在线| 亚洲欧洲日夜超级视频| 日日夜夜免费精品视频| 国产精品三级在线观看无码| 性做久久久久久免费观看欧美| 国产高清第一页| 欧美xxxx做受欧美| 91麻豆精品一二三区在线| 亚洲日本精品国产第一区| 奇米精品一区二区三区在线观看| 在线国产视频一区| 色婷婷综合久久久久中文一区二区 | 国产女优一区| 免费黄色三级网站| 午夜影院久久久| 日本高清视频在线| 韩国19禁主播vip福利视频| 91国内精品白嫩初高生| 久草视频这里只有精品| 高清毛片在线观看| 亚洲视频在线观看| 日韩毛片免费观看| 欧美连裤袜在线视频| 久热精品在线| 日本美女xxx| 欧美日韩亚洲另类| 毛片在线不卡| 91最新在线免费观看| 欧美日韩国产免费观看| 免费啪视频在线观看| 亚洲一二三四区不卡| 天堂在线观看视频| 日本国产精品视频| 日韩av在线播放网址| 992kp免费看片| 亚洲综合成人在线| 天堂在线一二区| 国产精品久久久久aaaa九色| 欧美第一精品| 亚洲美女高潮久久久| 精品露脸国产偷人在视频| 成人精品一区| 91夜夜未满十八勿入爽爽影院 | 久久久999精品视频| 国产一区一区| 鲁一鲁一鲁一鲁一色| 欧美激情一区二区| av免费在线不卡| 97香蕉超级碰碰久久免费的优势| 亚洲国产欧美日韩在线观看第一区 | 精品不卡一区二区三区| 狂野欧美性猛交xxxx巴西| 尤物在线免费视频| 亚洲国产精品美女| jizzyou欧美16| 国产传媒久久久| 久久天天做天天爱综合色| 国产乱色精品成人免费视频 | 亚洲国产日韩综合一区| 国产精品亚洲第一区在线暖暖韩国| 日本午夜小视频| 夜夜嗨av一区二区三区四区| 一区二区三区视频播放| 在线免费视频a| 亚洲综合网站在线观看| 久久福利免费视频| 久久精品国产99国产精品|