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

來,四種分布式限流算法實現(xiàn)!

開發(fā) 前端
關(guān)于Redission是怎么實現(xiàn)這個限速器的,大家可以看一下參考[3],還是Redisson家的老傳統(tǒng)——Lua腳本,設(shè)計相當(dāng)巧妙。

大家好,我是老三,最近公司在搞年終大促,隨著各種營銷活動“組合拳”打出,進(jìn)站流量時不時會有一個小波峰,一般情況下,當(dāng)然是流量越多越好,前提是系統(tǒng)能杠地住。大家都知道,一個分布式系統(tǒng),有兩個“棄車保帥”的策略:限流和熔斷,這期,我們就來討論一下分布式系統(tǒng)的限流。

探探限流

帶著問題走近限流

為什么要限流呢?

就像我上面說的,流量多,的確是一件好事,但是如果過載,把系統(tǒng)打掛了,那大家都要吃席了。

沒逝吧

所以,在各種大促活動之前,要對系統(tǒng)進(jìn)行壓測,評估整個系統(tǒng)的峰值QPS,要做一些限流的設(shè)置,超過一定閾值,就拒絕處理或者延后處理,避免把系統(tǒng)打掛的情況出現(xiàn)。

限流和熔斷有什么區(qū)別?

限流發(fā)生在流量進(jìn)來之前,超過的流量進(jìn)行限制。

熔斷是一種應(yīng)對故障的機(jī)制,發(fā)生在流量進(jìn)來之后,如果系統(tǒng)發(fā)生故障或者異常,熔斷會自動切斷請求,防止故障進(jìn)一步擴(kuò)展,導(dǎo)致服務(wù)雪崩。

限流和削峰有什么區(qū)別?

削峰是對流量的平滑處理,通過緩慢地增加請求的處理速率來避免系統(tǒng)瞬時過載。

削峰大概就是水庫,把流量儲存起來,慢慢流,限流大概就是閘口,拒絕超出的流量。

限流的通用流程

那么具體限流怎么實現(xiàn)呢?可以概括為以下幾個步驟:

限流通用流程限流通用流程

  1. 統(tǒng)計請求流量:記錄請求的數(shù)量或速率,可以通過計數(shù)器、滑動窗口等方式進(jìn)行統(tǒng)計。
  2. 判斷是否超過限制:根據(jù)設(shè)定的限制條件,判斷當(dāng)前請求流量是否超過限制。
  3. 執(zhí)行限流策略:如果請求流量超過限制,執(zhí)行限流策略,如拒絕請求、延遲處理、返回錯誤信息等。
  4. 更新統(tǒng)計信息:根據(jù)請求的處理結(jié)果,更新統(tǒng)計信息,如增加計數(shù)器的值、更新滑動窗口的數(shù)據(jù)等。
  5. 重復(fù)執(zhí)行以上步驟:不斷地統(tǒng)計請求流量、判斷是否超過限制、執(zhí)行限流策略、更新統(tǒng)計信息

需要注意的是,具體的限流算法實現(xiàn)可能會根據(jù)不同的場景和需求進(jìn)行調(diào)整和優(yōu)化,比如使用令牌桶算法、漏桶算法等。

單機(jī)限流和分布式限流

我們注意到,在限流的通用流程里,需要統(tǒng)計請求量、更新統(tǒng)計量,那么這個請求量的統(tǒng)計和更新就必須維護(hù)在一個存儲里。

假如只是一個單機(jī)版的環(huán)境,那就很好辦了,直接儲存到本地。

單機(jī)vs集群單機(jī)vs集群

但是一般來講,我們的服務(wù)都是集群部署的,如何來實現(xiàn)多臺機(jī)器之間整體的限流呢?

這時候就可以把我們的統(tǒng)計信息放到Tair或Redis等分布式的K-V存儲中。

四種限流算法與分布式實現(xiàn)

接下來,我們開始實現(xiàn)一些常見的限流算法,這里使用Redis作為分布式存儲,Redis不用多說了吧,最流行的分布式緩存DB;Redission作為Redis客戶端,Redission單純只是用來做分布式鎖,有些”屈才“,其實用來作為Redis的客戶端也非常好用。

五種限流算法分布式實現(xiàn)

在開始之前,我們先簡單準(zhǔn)備一下環(huán)境,Redis安裝和項目創(chuàng)建就不多說了。

  • 添加依賴
<dependency>
            <groupId>org.redisson</groupId>
            <artifactId>redisson</artifactId>
            <version>3.16.2</version>
        </dependency>
  • 用單例模式獲取RedissonClient,這里就不注冊成bean了,跑單測太慢
public class RedissonConfig {

    private static final String REDIS_ADDRESS = "redis://127.0.0.1:6379";

    private static volatile  RedissonClient redissonClient;

   public static RedissonClient getInstance(){
        if (redissnotallow==null){
            synchronized (RedissonConfig.class){
                if (redissnotallow==null){
                    Config config = new Config();
                    config.useSingleServer().setAddress(REDIS_ADDRESS);
                    redissonClient = Redisson.create(config);
                    return redissonClient;
                }
            }
        }
        return redissonClient;
    }
}

固定窗口限流算法

算法原理

固定窗口算法,很多參考資料也稱之為計數(shù)器算法,當(dāng)然我個人理解,計數(shù)器算法是固定窗口算法的一種特例,當(dāng)然我們不糾結(jié)那么多。

固定窗口算法,是一種比較簡單的限流算法,它把時間劃分為固定的時間窗口,每個窗口內(nèi)允許的請求次數(shù)設(shè)置限制。如果在一個時間窗口內(nèi),請求次數(shù)超過了上限,那么就會觸發(fā)限流。

在這里插入圖片描述

算法實現(xiàn)

基于Redisson的實現(xiàn)固定窗口相當(dāng)簡單。在每個窗口期內(nèi),我們可以通過incrementAndGet操作來統(tǒng)計請求的數(shù)量。一旦窗口期結(jié)束,我們可以利用Redis的鍵過期功能來自動重置計數(shù)。

  • 來看下代碼實現(xiàn):
public class FixedWindowRateLimiter {
    public static final String KEY = "fixedWindowRateLimiter:";
    /**
     * 請求限制數(shù)量
     */
    private Long limit;
    /**
     * 窗口大小(單位:S)
     */
    private Long windowSize;

    public FixedWindowRateLimiter(Long limit, Long windowSize) {
        this.limit = limit;
        this.windowSize = windowSize;
    }

    /**
     * 固定窗口限流
     */
    public boolean triggerLimit(String path) {
        RedissonClient redissonClient = RedissonConfig.getInstance();
        //加分布式鎖,防止并發(fā)情況下窗口初始化時間不一致問題
        RLock rLock = redissonClient.getLock(KEY + "LOCK:" + path);
        try {
            rLock.lock(100, TimeUnit.MILLISECONDS);
            String redisKey = KEY + path;
            RAtomicLong counter = redissonClient.getAtomicLong(redisKey);
            //計數(shù)
            long count = counter.incrementAndGet();
            //如果為1的話,就說明窗口剛初始化
            if (count == 1) {
                //直接設(shè)置過期時間,作為窗口
                counter.expire(windowSize, TimeUnit.SECONDS);
            }
            //觸發(fā)限流
            if (count > limit) {
                //觸發(fā)限流的不記在請求數(shù)量中
                counter.decrementAndGet();
                return true;
            }
            return false;
        } finally {
            rLock.unlock();
        }
    }

}

這里還額外用了一個分布式鎖,來解決并發(fā)情況下,窗口的初始化問題。

  • 再來測試一下
class FixedWindowRateLimiterTest {
    ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(20, 50, 10, TimeUnit.SECONDS, new LinkedBlockingDeque<>(10));

    @Test
    @DisplayName("1min限制10次請求固定窗口測試")
    void triggerLimit() throws InterruptedException {
        FixedWindowRateLimiter fixedWindowRateLimiter = new FixedWindowRateLimiter(10L,60L);
        //模擬不同窗口內(nèi)的調(diào)用
        for (int i = 0; i < 3; i++) {
            CountDownLatch countDownLatch = new CountDownLatch(20);
            //20個線程并發(fā)調(diào)用
            for (int j = 0; j < 20; j++) {
                threadPoolExecutor.execute(() -> {
                    boolean isLimit = fixedWindowRateLimiter.triggerLimit("/test");
                    System.out.println(isLimit);
                    countDownLatch.countDown();
                });
            }
            countDownLatch.await();
            //休眠1min
            TimeUnit.MINUTES.sleep(1);
        }
    }
}

當(dāng)然大家也可以寫個接口,用Jmeter之類的壓測工具來進(jìn)行測試。

固定窗口算法的優(yōu)點是實現(xiàn)簡單,占用空間小,但是它存在臨界問題,由于窗口的切換是瞬間完成的,因此請求的處理并不平滑,可能會在窗口切換的瞬間出現(xiàn)流量的劇烈波動。

比如這個例子,假如在00:02,突然有大量請求過來,但是我們這時候計數(shù)重置了,那么就沒法限制突發(fā)的這些流量。

臨界值問題

滑動窗口算法

為了緩解固定窗口的突發(fā)流量問題,可以采用滑動窗口算法,計算機(jī)網(wǎng)絡(luò)中TCP的流量控制就是采用滑動窗口算法。

算法原理

滑動窗口限流算法的原理是將一個大的時間窗口劃分為多個小的時間窗口,每個小的窗口都有獨立的計數(shù)。

請求過來的時候,判斷請求的次數(shù)是否超過整個窗口的限制。窗口的移動是每次向前滑動一個小的單元窗口。

例如下面這個滑動窗口,將大時間窗口1min分成了5個小窗口,每個小窗口的時間是12s。

每個單元格有自己獨立的計數(shù)器,每過12s就會向前移動一格。

假如有請求在00:01的時候過來,這時候窗口的計數(shù)就是3+12+9+15=39,也能起到限流的作用。

滑動窗口算法示意圖

這就是為什么滑動窗口能解決臨界問題,滑的格子越多,那么整體的滑動就會越平滑,限流的效果就會越精準(zhǔn)。

算法實現(xiàn)

那么我們這里怎么實現(xiàn)滑動窗口限流算法呢?非常簡單,我們可以直接使用Redis的有序集合(zset)結(jié)構(gòu)。

我們使用時間戳作為score和member,有請求過來的時候,就把當(dāng)前時間戳添加到有序集合里。那么窗口之外的請求,我們可以根據(jù)窗口大小,計算出起始時間戳,刪除窗口外的請求。這樣,有序集合的大小,就是我們這個窗口的請求數(shù)了。

zset實現(xiàn)滑動窗口

  • 代碼實現(xiàn)
public class SlidingWindowRateLimiter {
    public static final String KEY = "slidingWindowRateLimiter:";

    /**
     * 請求次數(shù)限制
     */
    private Long limit;
    /**
     * 窗口大小(單位:S)
     */
    private Long windowSize;

    public SlidingWindowRateLimiter(Long limit, Long windowSize) {
        this.limit = limit;
        this.windowSize = windowSize;
    }


    public boolean triggerLimit(String path) {
        RedissonClient redissonClient = RedissonConfig.getInstance();
        //窗口計數(shù)
        RScoredSortedSet<Long> counter = redissonClient.getScoredSortedSet(KEY + path);
        //使用分布式鎖,避免并發(fā)設(shè)置初始值的時候,導(dǎo)致窗口計數(shù)被覆蓋
        RLock rLock = redissonClient.getLock(KEY + "LOCK:" + path);
        try {
            rLock.lock(200, TimeUnit.MILLISECONDS);
            // 當(dāng)前時間戳
            long currentTimestamp = System.currentTimeMillis();
            // 窗口起始時間戳
            long windowStartTimestamp = currentTimestamp - windowSize * 1000;
            // 移除窗口外的時間戳,左閉右開
            counter.removeRangeByScore(0, true, windowStartTimestamp, false);
            // 將當(dāng)前時間戳作為score,也作為member,
            // TODO:高并發(fā)情況下可能沒法保證唯一,可以加一個唯一標(biāo)識
            counter.add(currentTimestamp, currentTimestamp);
            //使用zset的元素個數(shù),作為請求計數(shù)
            long count = counter.size();
            // 判斷時間戳數(shù)量是否超過限流閾值
            if (count > limit) {
                System.out.println("[triggerLimit] path:" + path + " count:" + count + " over limit:" + limit);
                return true;
            }
            return false;
        } finally {
            rLock.unlock();
        }
    }

}

這里還有一個小的可以完善的點,zset在member相同的情況下,是會覆蓋的,也就是說高并發(fā)情況下,時間戳可能會重復(fù),那么就有可能統(tǒng)計的請求偏少,這里可以用時間戳+隨機(jī)數(shù)來緩解,也可以生成唯一序列來解決,比如UUID、雪花算法等等。

  • 還是來測試一下
class SlidingWindowRateLimiterTest {
    ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(30, 50, 10, TimeUnit.SECONDS, new LinkedBlockingDeque<>(10));

    @Test
    @DisplayName("滑動窗口限流")
    void triggerLimit() throws InterruptedException {
        SlidingWindowRateLimiter slidingWindowRateLimiter = new SlidingWindowRateLimiter(10L, 1L);
        //模擬在不同時間片內(nèi)的請求
        for (int i = 0; i < 8; i++) {
            CountDownLatch countDownLatch = new CountDownLatch(20);
            for (int j = 0; j < 20; j++) {
                threadPoolExecutor.execute(() -> {
                    boolean isLimit = slidingWindowRateLimiter.triggerLimit("/test");
                    System.out.println(isLimit);
                    countDownLatch.countDown();
                });
            }
            countDownLatch.await();
            //休眠10s
            TimeUnit.SECONDS.sleep(10L);
        }
    }
}

用Redis實現(xiàn)了滑動窗口限流,解決了固定窗口限流的邊界問題,當(dāng)然這里也帶來了新的問題,因為我們存儲了窗口期的所有請求,所以高并發(fā)的情況下,可能會比較占內(nèi)存。

漏桶算法

我們可以看到,計數(shù)器類的限流,體現(xiàn)的是一個“戛然而止”,超過限制,立馬決絕,但是有時候,我們可能只是希望請求平滑一些,追求的是“波瀾不驚”,這時候就可以考慮使用其它的限流算法。

算法原理

漏桶算法(Leaky Bucket),名副其實,就是請求就像水一樣以任意速度注入漏桶,而桶會按照固定的速率將水漏掉。

漏桶算法

當(dāng)進(jìn)水速率大于出水速率的時候,漏桶會變滿,此時新進(jìn)入的請求將會被丟棄。

漏桶算法的兩大作用是網(wǎng)絡(luò)流量整形(Traffic Shaping)和速度限制(Rate Limiting)。

算法實現(xiàn)

我們接著看看具體應(yīng)該怎么實現(xiàn)。

在滑動窗口限流算法里我們用到了RScoredSortedSet,非常好用對不對,這里也可以用這個結(jié)構(gòu),直接使用ZREMRANGEBYSCORE命令來刪除舊的請求。

進(jìn)水就不用多說了,請求進(jìn)來,判斷桶有沒有滿,滿了就拒絕,沒滿就往桶里丟請求。

那么出水怎么辦呢?得保證穩(wěn)定速率出水,可以用一個定時任務(wù),來定時去刪除舊的請求。

  • 代碼實現(xiàn)
public class LeakyBucketRateLimiter {
    private RedissonClient redissonClient = RedissonConfig.getInstance();
    private static final String KEY_PREFIX = "LeakyBucket:";

    /**
     * 桶的大小
     */
    private Long bucketSize;
    /**
     * 漏水速率,單位:個/秒
     */
    private Long leakRate;


    public LeakyBucketRateLimiter(Long bucketSize, Long leakRate) {
        this.bucketSize = bucketSize;
        this.leakRate = leakRate;
        //這里啟動一個定時任務(wù),每s執(zhí)行一次
        ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1);
        executorService.scheduleAtFixedRate(this::leakWater, 0, 1, TimeUnit.SECONDS);
    }

    /**
     * 漏水
     */
    public void leakWater() {
        RSet<String> pathSet=redissonClient.getSet(KEY_PREFIX+":pathSet");
        //遍歷所有path,刪除舊請求
        for(String path:pathSet){
            String redisKey = KEY_PREFIX + path;
            RScoredSortedSet<Long> bucket = redissonClient.getScoredSortedSet(KEY_PREFIX + path);
            // 獲取當(dāng)前時間
            long now = System.currentTimeMillis();
            // 刪除舊的請求
            bucket.removeRangeByScore(0, true,now - 1000 * leakRate,true);
        }
    }

    /**
     * 限流
     */
    public boolean triggerLimit(String path) {
        //加鎖,防止并發(fā)初始化問題
        RLock rLock = redissonClient.getLock(KEY_PREFIX + "LOCK:" + path);
        try {
            rLock.lock(100,TimeUnit.MILLISECONDS);
            String redisKey = KEY_PREFIX + path;
            RScoredSortedSet<Long> bucket = redissonClient.getScoredSortedSet(redisKey);
            //這里用一個set,來存儲所有path
            RSet<String> pathSet=redissonClient.getSet(KEY_PREFIX+":pathSet");
            pathSet.add(path);
            // 獲取當(dāng)前時間
            long now = System.currentTimeMillis();
            // 檢查桶是否已滿
            if (bucket.size() < bucketSize) {
                // 桶未滿,添加一個元素到桶中
                bucket.add(now,now);
                return false;
            }
            // 桶已滿,觸發(fā)限流
            System.out.println("[triggerLimit] path:"+path+" bucket size:"+bucket.size());
            return true;
        }finally {
            rLock.unlock();
        }
    }
    
}

在代碼實現(xiàn)里,我們用了RSet來存儲path,這樣一來,一個定時任務(wù),就可以搞定所有path對應(yīng)的桶的出水,而不用每個桶都創(chuàng)建一個一個定時任務(wù)。

這里我直接用ScheduledExecutorService啟動了一個定時任務(wù),1s跑一次,當(dāng)然集群環(huán)境下,每臺機(jī)器都跑一個定時任務(wù),對性能是極大的浪費,而且不好管理,我們可以用分布式定時任務(wù),比如xxl-job去執(zhí)行l(wèi)eakWater。

  • 最后還是大家熟悉的測試
class LeakyBucketRateLimiterTest {

    ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(30, 50, 10, TimeUnit.SECONDS, new LinkedBlockingDeque<>(10));

    @Test
    @DisplayName("漏桶算法")
    void triggerLimit() throws InterruptedException {
        LeakyBucketRateLimiter leakyBucketRateLimiter = new LeakyBucketRateLimiter(10L, 1L);
        for (int i = 0; i < 8; i++) {
            CountDownLatch countDownLatch = new CountDownLatch(20);
            for (int j = 0; j < 20; j++) {
                threadPoolExecutor.execute(() -> {
                    boolean isLimit = leakyBucketRateLimiter.triggerLimit("/test");
                    System.out.println(isLimit);
                    countDownLatch.countDown();
                });
            }
            countDownLatch.await();
            //休眠10s
            TimeUnit.SECONDS.sleep(10L);
        }
    }
}

漏桶算法能夠有效防止網(wǎng)絡(luò)擁塞,實現(xiàn)也比較簡單。

但是,因為漏桶的出水速率是固定的,假如突然來了大量的請求,那么只能丟棄超量的請求,即使下游能處理更大的流量,沒法充分利用系統(tǒng)資源。

令牌桶算法

令牌桶算法來了!

算法原理

令牌桶算法是對漏桶算法的一種改進(jìn)。

它的主要思想是:系統(tǒng)以一種固定的速率向桶中添加令牌,每個請求在發(fā)送前都需要從桶中取出一個令牌,只有取到令牌的請求才被通過。因此,令牌桶算法允許請求以任意速率發(fā)送,只要桶中有足夠的令牌。

令牌桶算法令牌桶算法

算法實現(xiàn)

我們繼續(xù)看怎么實現(xiàn),首先是要發(fā)放令牌,要固定速率,那我們又得開個線程,定時往桶里投令牌,然后……

——然后Redission提供了令牌桶算法的實現(xiàn),舒不舒服?

拿來吧你

拿來就用!

  • 代碼實現(xiàn)
public class TokenBucketRateLimiter {

    public static final String KEY = "TokenBucketRateLimiter:";

    /**
     * 閾值
     */
    private Long limit;
    /**
     * 添加令牌的速率,單位:個/秒
     */
    private Long tokenRate;

    public TokenBucketRateLimiter(Long limit, Long tokenRate) {
        this.limit = limit;
        this.tokenRate = tokenRate;
    }

    /**
     * 限流算法
     */
    public boolean triggerLimit(String path){
        RedissonClient redissnotallow=RedissonConfig.getInstance();
        RRateLimiter rateLimiter = redissonClient.getRateLimiter(KEY+path);
        // 初始化,設(shè)置速率模式,速率,間隔,間隔單位
        rateLimiter.trySetRate(RateType.OVERALL, limit, tokenRate, RateIntervalUnit.SECONDS);
        // 獲取令牌
        return rateLimiter.tryAcquire();
    }
}

Redisson實現(xiàn)的,還是比較穩(wěn)的,這里就不測試了。

關(guān)于Redission是怎么實現(xiàn)這個限速器的,大家可以看一下參考[3],還是Redisson家的老傳統(tǒng)——Lua腳本,設(shè)計相當(dāng)巧妙。

總結(jié)

在這篇文章里,我們對四(三)種限流算法進(jìn)行了分布式實現(xiàn),采用了非常好用的Redission客戶端,當(dāng)然我們也有不完善的地方:

  • 并發(fā)處理采用了分布式鎖,高并發(fā)情況下,對性能有一定損耗,邏輯最好還是直接采用Lua腳本實現(xiàn),來提高性能
  • 可以提供更加優(yōu)雅的調(diào)用方式,比如利用aop實現(xiàn)注解式調(diào)用,代碼設(shè)計也可以更加優(yōu)雅,繼承體系可以完善一下
  • 沒有實現(xiàn)限流的拒絕策略,比如拋異常、緩存、丟進(jìn)MQ打散……限流是一種方法,最終的目的還是盡可能保證系統(tǒng)平穩(wěn)

如果后面有機(jī)會,希望可以繼續(xù)完善這個簡單的Demo,達(dá)到工程級的應(yīng)用。

除此之外,市面上也有很多好用的開源限流工具:

  • Guava RateLimiter ,基于令牌桶算法限流,當(dāng)然是單機(jī)的;
  • Sentinel ,基于滑動窗口限流,支持單機(jī),也支持集群
  • 網(wǎng)關(guān)限流,很多網(wǎng)關(guān)自帶限流方法,比如Spring Cloud Gateway、Nginx

……

好了,這期文章就到這里了,我們下期見。

參考:

[1]. 面試官:來,年輕人!請手?jǐn)]5種常見限流算法!

[2].https://zhuanlan.zhihu.com/p/479956069

[3].https://github.com/oneone1995/blog/issues/13

責(zé)任編輯:武曉燕 來源: 三分惡
相關(guān)推薦

2024-02-28 09:22:03

限流算法數(shù)量

2023-11-15 07:40:40

2021-03-04 17:55:27

算法Raft分布式

2020-05-19 22:05:39

Serverless微服務(wù)分布式

2015-03-19 15:13:20

PHP基本排序算法代碼實現(xiàn)

2023-09-13 09:52:14

分布式鎖Java

2014-05-08 14:38:26

tornadoredissession

2018-07-16 08:29:54

redis集群限流

2024-04-08 11:04:03

2022-01-12 12:46:32

Go限流保障

2021-08-11 20:17:22

推薦算法系統(tǒng)

2011-03-16 09:05:53

NATiptables

2021-12-22 09:34:01

Golagn配置方式

2021-06-24 17:55:40

Python 開發(fā)編程語言

2022-06-27 08:21:05

Seata分布式事務(wù)微服務(wù)

2025-05-13 02:10:00

2018-06-11 11:12:09

秒殺限流分布式

2018-06-19 09:35:51

分布式系統(tǒng)限流

2019-08-14 11:08:01

數(shù)據(jù)庫場景選型

2009-09-08 17:20:01

C#排序算法
點贊
收藏

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

水蜜桃色314在线观看| 午夜免费在线观看精品视频| 日本精品久久久久中文字幕| 岛国最新视频免费在线观看| 丝袜美腿成人在线| 日韩在线欧美在线| 免费观看一区二区三区| 91九色在线播放| 国产日产欧美一区二区视频| 国产精品色悠悠| www.av视频在线观看| 精品国产91乱码一区二区三区四区 | 色综合久久久久久久久| 一区二区视频在线播放| 日韩永久免费视频| 日本亚洲最大的色成网站www| 久久成人国产精品| 女女互磨互喷水高潮les呻吟| 精品视频一二| 欧美在线观看视频在线| 国产一区二区三区乱码| av在线1区2区| 久久色中文字幕| 99蜜桃在线观看免费视频网站| 东京热一区二区三区四区| 欧美激情91| 最近2019免费中文字幕视频三| 无码精品一区二区三区在线播放| 小说区图片区亚洲| 色偷偷久久人人79超碰人人澡| 国产精品无码电影在线观看| 男人资源在线播放| 欧美激情一区二区| 欧美日韩日本网| 日韩一级中文字幕| 牛牛影视久久网| 亚洲欧美另类久久久精品2019| 日本午夜精品一区二区| 成人免费视频国产| 国产黄色精品网站| 国产国语videosex另类| 久久夜靖品2区| 亚洲高清资源| 亚洲的天堂在线中文字幕| 91日韩视频在线观看| 丁香花电影在线观看完整版| 一区二区三区日韩精品视频| 亚洲小说欧美另类激情| 黄色在线免费| 亚洲三级观看| 久久久成人av| 26uuu成人网| 亚洲成人二区| 不卡av电影在线观看| 懂色av蜜臀av粉嫩av永久| 成人看的羞羞网站| 51精品视频| 国产精品久久久久9999吃药| 国产精品精品久久久| 国产成人精品网| 国产人成精品一区二区三| 精品久久一二三区| 男人的天堂影院| 偷拍亚洲色图| 欧美变态口味重另类| 国产亚洲精品成人a| 好吊妞国产欧美日韩免费观看网站 | 青青九九免费视频在线| 91丨porny丨国产入口| 久久精精品视频| 深夜福利视频一区| 99国内精品久久| 免费一区二区三区| 国产爆初菊在线观看免费视频网站| 久久精品欧美日韩| 亚洲一卡二卡区| 性做久久久久久久| 99riav1国产精品视频| 欧美一级视频在线观看| 黄色性生活一级片| 无码人妻精品一区二| 国产免费视频在线| 成人免费视频一区二区| 精品一区二区久久久久久久网站| 国产永久免费高清在线观看 | 国产精品福利久久久| 在线观看日韩中文字幕| 久久精品卡一| 国产精品白嫩美女在线观看 | 国产视频三区四区| 久久亚洲在线| 国产+人+亚洲| 中文字幕一区2区3区| а√天堂官网中文在线| 美女精品一区最新中文字幕一区二区三区 | 亚洲激情在线激情| 国产xxxx振车| 国产极品久久久久久久久波多结野| 久久精品人人做人人综合| 亚洲图色在线| 色开心亚洲综合| 亚洲mv在线观看| 日本特级黄色大片| 91福利在线尤物| 欧美日韩一区小说| 善良的小姨在线| 1024在线看片你懂得| 一本到一区二区三区| 黄色一级片国产| 国产亚洲精品精品国产亚洲综合| 精品国产1区二区| 欧美大片拔萝卜| 免费在线观看的毛片| 日本a人精品| 日韩精品在线免费播放| 国产精品国产精品88| 精品日韩免费| 2025国产精品视频| 国产精品久久久久久久久久久久久久久久久久 | 国产69精品久久app免费版| 91丨porny丨蝌蚪视频| 特级西西444| 日韩福利在线观看| 亚洲女人被黑人巨大进入| 欧美成人三级视频| 久久99精品久久久| 日本视频一区二区在线观看| 蜜乳av一区| 91精品在线免费观看| 黄色aaa视频| 亚洲精选一区| 丁香五月网久久综合| aaa大片在线观看| 欧美日韩电影一区| 欧美亚洲色综久久精品国产| 美女网站久久| 欧美大香线蕉线伊人久久| 国产高清视频色在线www| 日韩欧美国产午夜精品| 国产尤物在线播放| 久国产精品韩国三级视频| 天堂av一区二区| 高清欧美日韩| 最近2019中文字幕大全第二页| 无码人妻一区二区三区免费| 久久久国际精品| www.超碰com| 不卡中文字幕| 成人激情免费在线| 国产三区视频在线观看| 3d动漫精品啪啪一区二区竹菊| 老司机深夜福利网站| 麻豆精品久久久| 熟妇熟女乱妇乱女网站| 精品久久亚洲| 欧美黄色三级网站| 天天射,天天干| 欧美午夜片欧美片在线观看| a级在线免费观看| 青青青爽久久午夜综合久久午夜| 亚洲国产精品综合| 9999精品免费视频| 欧美国产视频一区二区| 免费国产羞羞网站视频| 欧美日韩午夜视频在线观看| 素人fc2av清纯18岁| 久久综合影视| 中文字幕综合在线观看| 日韩欧美中文字幕一区二区三区 | 一级特黄录像免费播放全99| 9999精品视频| 午夜精品久久久99热福利| 日韩一区二区三区中文字幕| 在线国产亚洲欧美| 日韩在线不卡av| 成人性生交大片免费看中文| 国产资源在线视频| 日韩精品一区二区三区免费观影| 91久久久亚洲精品| 国产在线精彩视频| 亚洲午夜精品视频| 国产成人a人亚洲精品无码| 亚洲国产婷婷综合在线精品| 日韩精品无码一区二区三区久久久| 蜜臀av性久久久久蜜臀aⅴ四虎| 992tv成人免费观看| 日韩啪啪网站| 国产精自产拍久久久久久蜜| 日韩影视在线| 国产亚洲美女精品久久久| av中文字幕免费在线观看| 欧美日韩亚洲视频| 午夜剧场免费在线观看| 972aa.com艺术欧美| 久久久久久久久久久久久久久国产| 精品动漫3d一区二区三区免费版| 日本一区二区三区视频在线播放 | 成人午夜大片免费观看| 91av俱乐部| 狠狠干综合网| 亚洲精品一区二区三区樱花| 超碰在线一区| 国产区亚洲区欧美区| 涩涩视频在线免费看| 久久午夜a级毛片| 国产乱子伦三级在线播放| 精品久久99ma| 国产精品久久综合青草亚洲AV| 狠狠躁夜夜躁人人爽天天天天97 | 国产欧美日韩一级| ijzzijzzij亚洲大全| 国产在视频线精品视频www666| 超碰97在线资源| 久久久久伊人| 国产成人在线播放| 国产美女高潮在线观看| 久久精品国产亚洲7777| 成人综合影院| 亚洲人成在线一二| 日日躁夜夜躁白天躁晚上躁91| 91麻豆精品国产91久久久更新时间 | 欧美偷拍一区二区| 久久精品视频1| 亚洲国产毛片aaaaa无费看| 男女性高潮免费网站| 欧美国产精品一区二区| 中文字幕一区二区三区人妻不卡| 成人性色生活片| 一区二区三区人妻| 精品系列免费在线观看| 污污网站免费看| 日韩二区在线观看| 国产欧美高清在线| 久久av在线| www.com毛片| 国产日韩欧美一区| 日日摸日日碰夜夜爽无码| 亚洲视频免费| 精品无码国产一区二区三区av| 欧美激情精品久久久六区热门| 午夜探花在线观看| 综合精品一区| 久久久久久av无码免费网站下载| 亚洲最大黄网| 久久久天堂国产精品| 午夜日韩电影| 黄网站欧美内射| 亚洲欧美久久| 男人的天堂日韩| 美女性感视频久久| 一区二区三区四区毛片| 国模一区二区三区白浆| 亚洲精品中文字幕乱码无线| 国产美女主播视频一区| 国内自拍偷拍视频| 成人a免费在线看| 国产精品无码午夜福利| 久久久久国产成人精品亚洲午夜 | 亚洲男人都懂的| 久久久精品99| 欧美日韩国产限制| 欧美日韩 一区二区三区| 欧美三级电影在线看| 国产欧美一级片| 精品国产一区二区三区久久久蜜月 | 久久久久久久久久久97| 亚洲va中文字幕| 午夜精品免费观看| 欧美日韩国产美| 亚洲精品911| 亚洲欧美999| 黄色网页在线播放| 午夜精品蜜臀一区二区三区免费 | 亚洲伊人第一页| 岛国成人av| 日本一区二区免费看| 999精品色在线播放| 久久成人福利视频| 久久久一二三| 亚洲av无码久久精品色欲| 97久久久精品综合88久久| 成年人在线免费看片| 亚洲另类在线制服丝袜| 欧美亚洲国产免费| 亚洲av无码乱码国产麻豆| 欧美一区二区久久| 日本人妖在线| 另类视频在线观看| 手机在线观看av| 成人在线小视频| 日韩电影在线观看完整免费观看| 亚洲精品不卡| 国产欧美成人| 色婷婷一区二区三区在线观看| 91小视频在线免费看| 日韩在线视频网址| 一本一本久久a久久精品综合麻豆| 国产剧情久久久| 亚洲欧美在线磁力| 色呦呦久久久| 国产精品电影网站| 老司机aⅴ在线精品导航| 伊人情人网综合| 嫩草成人www欧美| 少妇献身老头系列| 国产精品久久久久久久岛一牛影视 | 天堂在线观看av| 久久婷婷国产麻豆91天堂| 美女100%一区| 国产一区二区自拍| 中文一区一区三区免费在线观看| 嫩草av久久伊人妇女超级a| 不卡一区二区中文字幕| 欧美三级日本三级| 欧美久久一二区| 国产三级电影在线| 97超级碰在线看视频免费在线看| 清纯唯美激情亚洲| 宅男av一区二区三区| 视频一区欧美日韩| 亚洲综合自拍网| 亚洲高清免费在线| 国产高清视频免费| 久久精品视频在线播放| 88xx成人网| 日韩一区二区电影在线观看| 免费一区视频| 亚洲精品中文字幕在线播放| 亚洲综合在线视频| 国产在成人精品线拍偷自揄拍| 正在播放国产一区| 国产另类xxxxhd高清| 欧美日韩大片一区二区三区| 999亚洲国产精| 日韩av一二区| 精品久久久久久中文字幕一区奶水| 亚洲美女性生活| 欧美精品久久久久久久久| 亚洲一区电影| 蜜臀av色欲a片无码精品一区| 国产aⅴ综合色| 九九精品在线观看视频| 日韩一区二区三区视频| caopo在线| 高清视频一区二区三区| 国产精品va| 无码人妻一区二区三区在线| 亚洲一级片在线观看| 日本高清视频免费观看| 亚洲91精品在线观看| 香蕉精品久久| 日韩手机在线观看视频| 国产欧美一区二区精品忘忧草 | 在线观看a视频| 成人动漫网站在线观看| 一本到12不卡视频在线dvd| 手机看片国产精品| 亚洲丰满少妇videoshd| 人妻丰满熟妇av无码区hd| 欧美一级视频一区二区| 成久久久网站| 樱花草www在线| 亚洲国产日韩精品| 美女欧美视频在线观看免费 | 亚洲色图一区二区三区| 精品人妻一区二区三区浪潮在线| 高清一区二区三区日本久| 亚洲精品蜜桃乱晃| 麻豆三级在线观看| 亚洲日本韩国一区| 内射无码专区久久亚洲| 日本一区二区在线免费播放| 久久综合电影| 又黄又色的网站| 欧美影视一区二区三区| av免费看在线| 欧美高清视频一区| 激情文学综合丁香| 日本三级片在线观看| 在线播放精品一区二区三区| 国产精品3区| 国产精品50p| 18欧美亚洲精品| 午夜国产在线观看| 国产色综合天天综合网| 亚洲国产一区二区三区a毛片 | 亚洲欧美国产77777| 婷婷开心激情网| 国产中文字幕91| 日韩亚洲国产欧美| 日韩欧美在线视频播放| 亚洲精品在线免费观看视频| 国产成人福利夜色影视| 欧美人成在线观看| 国产精品国产三级国产三级人妇| 日本免费一区视频| 91久久久在线| 视频一区在线播放| 国产在线视频二区| 日日噜噜噜夜夜爽亚洲精品|