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

字節二面:Spring Boot Redis 可重入分布式鎖實現原理?

數據庫 Redis
當一個線程執行一段代碼成功獲取鎖之后,繼續執行時,又遇到加鎖的代碼,可重入性就就保證線程能繼續執行,而不可重入就是需要等待鎖釋放之后,再次獲取鎖成功,才能繼續往下執行。

我是碼哥,可以叫我靚仔。

書接上回,碼哥上一篇《糾正誤區:這才是 SpringBoot Redis 分布式鎖的正確實現方式》分享了分布式鎖如何從錯誤到殘缺,再到青銅版本的高性能 Redis 分布式鎖代碼實戰,讓你一飛沖天。

這是我們最常用的分布式鎖方案,今天碼哥給你來一個進階。

Chaya:「碼哥,上次的分布式鎖版本雖然好,但是不支持可重入獲取鎖,還差一點點意思。」

Chaya 別急,今日碼哥給你帶來一個高性能可重入 Redis 分布式鎖解決方案,直搗黃龍,一笑破蒼穹。

什么是可重入鎖

當一個線程執行一段代碼成功獲取鎖之后,繼續執行時,又遇到加鎖的代碼,可重入性就就保證線程能繼續執行,而不可重入就是需要等待鎖釋放之后,再次獲取鎖成功,才能繼續往下執行。

public synchronized void a() {
    b();
}
public synchronized void b() {
    // doWork
}

假設 X 線程在 a 方法獲取鎖之后,繼續執行 b 方法,如果此時不可重入,線程就必須等待鎖釋放,再次爭搶鎖。

鎖明明是被 X 線程擁有,卻還需要等待自己釋放鎖,然后再去搶鎖,這看起來就很奇怪,我釋放我自己~

可重入鎖實現原理

Chaya:「Redis String 數據結構無法滿足可重入鎖,key 表示鎖定的資源,value 是客戶端唯一標識,可重入沒地方放了。」

我們可以使用 Redis hash 結構實現,key 表示被鎖的共享資源, hash 結構的 fieldKey 存儲客戶端唯一標識,fieldKey 的 value 則保存加鎖的次數。

加鎖原理

可重入鎖加鎖的過程中有以下場景需要考慮。

  • 鎖已經被 A 客戶端獲取,客戶端 B 獲取鎖失敗。
  • 鎖已經被客戶端 A 獲取,客戶端 A 多次執行獲取鎖操作。
  • 鎖沒有被其他客戶端獲取,那么此刻獲取鎖的客戶端可以獲取成功。

按照之前的經驗,多個操作的原子性可以用 lua 腳本實現。可重入鎖加鎖 lua 腳本如下。

if ((redis.call('exists', KEYS[1]) == 0) or
   (redis.call('hexists', KEYS[1], ARGV[2]) == 1)) then
    redis.call('hincrby', KEYS[1], ARGV[2], 1);
    redis.call('pexpire', KEYS[1], ARGV[1]);
  return nil;
end;
return redis.call('pttl', KEYS[1]);
  • KEYS[1]是 lockKey 表示獲取的鎖資源,比如 lock:168。
  • ARGV[1] 表示表示鎖的有效時間(單位毫秒)。
  • ARGV[2] 表示客戶端唯一標識,在 Redisson 中使用 UUID:ThreadID。

下面我來接下是這段腳本的邏輯。

鎖不存在或者鎖存在且值與客戶端唯一標識匹配,則執行 'hincrby' 和 pexpire指令,接著 return nil。表示的含義就是鎖不存在就設置鎖并設置鎖重入計數值為 1,設置過期時間;鎖存在且唯一標識匹配表明當前加鎖請求是鎖重入請求,鎖從如計數 +1,重新鎖超時時間。

  • redis.call('exists', KEYS[1]) == 0判斷鎖是否存在,0 表示不存在。
  • redis.call('hexists', KEYS[1], ARGV[2]) == 1)鎖存在的話,判斷 hash 結構中 fieldKey 與客戶端的唯一標識是否相等。相等表示當前加鎖請求是鎖重入。
  • redis.call('hincrby', KEYS[1], ARGV[2], 1)將存儲在 hash 結構的 ARGV[2] 的值 +1,不存在則支持成 1。
  • redis.call('pexpire', KEYS[1], ARGV[1])對 KEYS[1] 設置超時時間。

鎖存在,但是唯一標識不匹配,表明鎖被其他線程持有,調用 pttl返回鎖剩余的過期時間。

Chaya:「“腳本執行結果返回 nil、鎖剩余過期時間有什么目的?”」

當且僅當返回 nil才表示加鎖成功;客戶端需要感知鎖是否成功的結果。

解鎖原理

解鎖邏輯復雜一些,不僅要保證不能刪除別人的鎖。還要確保,重入次數為 0 才能解鎖。

解鎖代碼執行方式與加鎖類似,三個返回值含義如下。

  • 1 代表解鎖成功,鎖被釋放。
  • 0 代表可重入次數被減 1。
  • nil 代表其他線程嘗試解鎖,解鎖失敗。
if (redis.call('hexists', KEYS[1], ARGV[2]) == 0) then
    return nil;
end;
local counter = redis.call('hincrby', KEYS[1], ARGV[2], -1);
if (counter > 0) then
    redis.call('pexpire', KEYS[1], ARGV[1]);
    return 0;
else
    redis.call('del', KEYS[1]);
    return 1;
end;
return nil;
  • KEYS[1]是 lockKey,表示鎖的資源,比如 lock:order:pay。
  • ARGV[1],鎖的超時時間。
  • ARGV[2],Hash 表的 FieldKey。

首先使用 hexists 判斷 Redis 的 Hash 表是否存在 fileKey,如果不存在則直接返回 nil解鎖失敗。

若存在的情況下,且唯一標識匹配,使用 hincrby 對 fileKey 的值 -1,然后判斷計算之后可重入次數。當前值 > 0 表示持有的鎖存在重入情況,重新設置超時時間,返回值 1;

若值小于等于 0,表明鎖釋放了,執行 del釋放鎖。

Chaya:“可重入鎖很好,依然存在的一個問題是:加鎖后,業務邏輯執行耗時超過了 lockKey 的過期時間,lockKey 會被 Reids 刪除。”

這個時間不能瞎寫,一般要根據在測試環境多次測試,然后壓測多輪之后,比如計算出接口平均執行時間 200 ms。那么鎖的超時時間就放大為平均執行時間的 3~5 倍。

Chaya:“鎖的超時時間怎么計算合適呢?”

這個時間不能瞎寫,一般要根據在測試環境多次測試,然后壓測多輪之后,比如計算出接口平均執行時間 200 ms。那么鎖的超時時間就放大為平均執行時間的 3~5 倍。

Chaya:“為啥要放大呢?”

因為如果鎖的操作邏輯中有網絡 IO 操作、JVM FullGC 等,線上的網絡不會總一帆風順,我們要給網絡抖動留有緩沖時間。

Chaya:“有沒有完美的方案呢?不管時間怎么設置都不大合適。”

我們可以讓獲得鎖的線程開啟一個守護線程,用來給當前客戶端快要過期的鎖續航,續命的前提是,得判斷是不是當前進程持有的鎖,如果不是就不進行續。

如果快要過期,但是業務邏輯還沒執行完成,自動對這個鎖進行續期,重新設置過期時間。

這就是下一篇我要說的超神方案,加入看門狗機制實現鎖自動續期。不過鎖自動續期比較復雜,今天的 Redis 可重入分布式鎖王者方案已經可以讓你稱霸武林,接下來上實戰。

可重入分布式鎖實戰

關于 Spring Boot 的環境搭建以及普通分布式鎖實戰詳見上一篇《糾正誤區:這才是 SpringBoot Redis 分布式鎖的正確實現方式》。今天直接上可重入鎖核心代碼。

ReentrantDistributedLock

可重入鎖由ReentrantDistributedLock標識,它實現 Lock接口,構造方法實現 resourceName 和 StringRedisTemplate 的屬性設置。

客戶端唯一標識使用uuid:threadId 組成。

public class ReentrantDistributedLock implements Lock {

    /**
     * 鎖超時時間,默認 30 秒
     */
    protected long internalLockLeaseTime = 30000;

    /**
     * 標識 id
     */
    private final String id = UUID.randomUUID().toString();

    /**
     * 資源名稱
     */
    private final String resourceName;

    private final List<String> keys = new ArrayList<>(1);


    /**
     * Redis 客戶端
     */
    private final StringRedisTemplate redisTemplate;

    public ReentrantDistributedLock(String resourceName, StringRedisTemplate redisTemplate) {
        this.resourceName = resourceName;
        this.redisTemplate = redisTemplate;
        keys.add(resourceName);
    }
}

加鎖 tryLock、lock

tryLock 以阻塞等待 waitTime 時間的方式來嘗試獲取鎖。獲取成功則返回 true,反之 false。

與 tryLock不同的是, lock 一直嘗試自旋阻塞等待獲取分布式鎖,直到獲取成功為止。而 tryLock 只會阻塞等待 waitTime 時間。

@Override
public boolean tryLock(long waitTime, long leaseTime, TimeUnit unit) throws InterruptedException {
    long time = unit.toMillis(waitTime);
    long current = System.currentTimeMillis();
    long threadId = Thread.currentThread().getId();
    // lua 腳本獲取鎖
    Long ttl = tryAcquire(leaseTime, unit, threadId);
    // lock acquired
    if (ttl == null) {
        return true;
    }

    time -= System.currentTimeMillis() - current;
    // 等待時間用完,獲取鎖失敗
    if (time <= 0) {
        return false;
    }
    // 自旋獲取鎖
    while (true) {
        long currentTime = System.currentTimeMillis();
        ttl = tryAcquire(leaseTime, unit, threadId);
        // lock acquired
        if (ttl == null) {
            return true;
        }

        time -= System.currentTimeMillis() - currentTime;
        if (time <= 0) {
            return false;
        }
    }
}

@Override
public void lock(long leaseTime, TimeUnit unit) {
    long threadId = Thread.currentThread().getId();
    Long ttl = tryAcquire(leaseTime, unit, threadId);
    // lock acquired
    if (ttl == null) {
        return;
    }
    do {
        ttl = tryAcquire(leaseTime, unit, threadId);
        // lock acquired
    } while (ttl != null);
}

private Long tryAcquire(long leaseTime, TimeUnit unit, long threadId) {
    // 執行 lua 腳本
    DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>(LuaScript.reentrantLockScript(), Long.class);
    return redisTemplate.execute(redisScript, keys, String.valueOf(unit.toMillis(leaseTime)), getRequestId(threadId));
}

private String getRequestId(long threadId) {
    return id + ":" + threadId;
}

解鎖 unlock

public void unlock() {
        long threadId = Thread.currentThread().getId();

        // 執行 lua 腳本
        DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>(LuaScript.reentrantUnlockScript(), Long.class);
        Long opStatus = redisTemplate.execute(redisScript, keys, String.valueOf(internalLockLeaseTime), getRequestId(threadId));

        if (opStatus == null) {
            throw new IllegalMonitorStateException("attempt to unlock lock, not locked by current thread by node id: "
                    + id + " thread-id: " + threadId);
        }


    }

LuaScript

這個腳本就是在講解可重入分布式鎖原理具體邏輯已經解釋過,這里就不再重復分析。

public class LuaScript {

    private LuaScript() {

    }

    /**
     * 可重入分布式鎖加鎖腳本
     *
     * @return 當且僅當返回 `nil`才表示加鎖成功;返回鎖剩余過期時間是讓客戶端感知鎖是否成功。
     */
    public static String reentrantLockScript() {
        return "if ((redis.call('exists', KEYS[1]) == 0) " +
                "or (redis.call('hexists', KEYS[1], ARGV[2]) == 1)) then " +
                "redis.call('hincrby', KEYS[1], ARGV[2], 1); " +
                "redis.call('pexpire', KEYS[1], ARGV[1]); " +
                "return nil; " +
                "end; " +
                "return redis.call('pttl', KEYS[1]);";
    }

    /**
     * 可重入分布式鎖解鎖腳本
     *
     * @return 當且僅當返回 `nil`才表示解鎖成功;
     */
    public static String reentrantUnlockScript() {
        return "if (redis.call('hexists', KEYS[1], ARGV[2]) == 0) then " +
                "return nil;" +
                "end; " +
                "local counter = redis.call('hincrby', KEYS[1], ARGV[2], -1); " +
                "if (counter > 0) then " +
                "redis.call('pexpire', KEYS[1], ARGV[1]); " +
                "return 0; " +
                "else " +
                "redis.call('del', KEYS[1]); " +
                "return 1; " +
                "end; " +
                "return nil;";
    }
}

RedisLockClient

最后,還需要提供一個客戶端給方便使用。

@Component
public class RedisLockClient {

    @Autowired
    private StringRedisTemplate redisTemplate;

    /**
     * 獲取可重入分布式鎖
     * @param name
     * @return
     */
    public Lock getReentrantLock(String name) {
        return new ReentrantDistributedLock(name, redisTemplate);
    }

}

單元測試走一個,驗證下分布式鎖是否支持可重入。

@Slf4j
@SpringBootTest(classes = RedisApplication.class)
public class RedisLockTest {

    @Autowired
    private RedisLockClient redisLockClient;

    @Test
    public void testTryReentrantLockSuccess() throws InterruptedException {
        Lock lock = redisLockClient.getReentrantLock("order:pay");
        try {
            boolean isLock = lock.tryLock(10, 30, TimeUnit.SECONDS);
            if (!isLock) {
                log.warn("加鎖失敗");
                return;
            }
            // 重復加鎖
            reentrant(lock);

            log.info("業務邏輯執行完成");
        } finally {
            lock.unlock();
        }

    }

    private void reentrant(Lock lock) throws InterruptedException {
        try {
            boolean isLock = lock.tryLock(10, 30, TimeUnit.SECONDS);
            if (!isLock) {
                log.warn("加鎖失敗");
                return;
            }

            log.info("業務邏輯執行完成");
        } finally {
            lock.unlock();
        }
    }

}

有兩個點需要注意。

  • 釋放鎖的代碼一定要放在 finally{} 塊中。否則一旦執行業務邏輯過程中拋出異常,程序就無法執行釋放鎖的流程。只能干等著鎖超時釋放。
  • 加鎖的代碼應該寫在 try {} 代碼中,放在 try 外面的話,如果執行加鎖異常(客戶端網絡連接超時),但是實際指令已經發送到服務端并執行,就會導致沒有機會執行解鎖的代碼。

CHaya:“碼哥,這個方案確實很王者,大開眼界,接下來的超神版可以實現看門狗自動續期么?”

鑒于篇幅有限,今天就跟大家介紹 Redis 可重入分布式鎖王者方案,關注我,下一篇給你分享、超神版分布式鎖解決方案。

責任編輯:姜華 來源: 碼哥字節
相關推薦

2020-07-15 16:50:57

Spring BootRedisJava

2020-06-15 08:15:47

分布式鎖系統

2021-06-27 21:24:55

RedissonJava數據

2021-07-08 09:21:17

ZooKeeper分布式鎖 Curator

2022-10-10 14:41:44

RedisJVM數據

2021-07-09 06:48:31

ZooKeeperCurator源碼

2024-02-04 09:29:07

Redis數據庫

2024-04-26 08:06:58

分布式系統

2024-11-28 15:11:28

2021-07-10 10:02:30

ZooKeeperCurator并發

2023-08-21 19:10:34

Redis分布式

2022-01-06 10:58:07

Redis數據分布式鎖

2022-12-31 09:42:14

超時功能

2022-09-22 13:28:34

Redis分布式鎖

2022-09-29 08:28:57

SpringRedis分布式

2021-02-28 07:49:28

Zookeeper分布式

2019-02-26 09:51:52

分布式鎖RedisZookeeper

2024-10-07 10:07:31

2019-06-19 15:40:06

分布式鎖RedisJava

2024-04-01 05:10:00

Redis數據庫分布式鎖
點贊
收藏

51CTO技術棧公眾號

午夜国产精品一区| 久久狠狠亚洲综合| 亚洲人成电影在线| 在线播放免费视频| 日韩伦理在线一区| 亚洲欧洲韩国日本视频| 国产日产精品一区二区三区四区| 无码人妻精品一区二区蜜桃色欲| 亚洲国产一区二区在线观看| 亚洲精品综合久久中文字幕| 热久久久久久久久| 精精国产xxx在线视频app| 国产精品午夜免费| 精品一区二区三区国产| 国产又粗又猛又爽| 日韩中文字幕区一区有砖一区 | 精品一二三四区| 浅井舞香一区二区| 国产第100页| 国产精品传媒精东影业在线| 亚洲嫩模很污视频| 国产精品成人免费一区久久羞羞| 日韩欧美看国产| 亚洲成av人片一区二区| 在线免费观看成人网| 日韩欧美在线观看一区二区| 国产精品一区久久久久| 国产精品网红直播| 69视频免费看| 亚洲在线网站| 国内精品久久久久久影视8| 国产免费久久久久| 日韩精品电影| 一区二区av在线| av在线网站观看| 特黄特色欧美大片| 亚洲国产欧美一区二区丝袜黑人 | 成人午夜888| 欧美三片在线视频观看| 妺妺窝人体色www在线小说| 亚洲卡一卡二| 一区二区三区在线视频免费观看 | 日韩精品卡通动漫网站| 欧美大胆视频| 日韩av一卡二卡| 玖草视频在线观看| 日韩在线影视| 亚洲区在线播放| 亚洲永久精品ww.7491进入| 任你弄精品视频免费观看| 精品国产91久久久久久久妲己| aaaaa黄色片| 亚洲精品观看| 精品国产99国产精品| 李丽珍裸体午夜理伦片| 牛牛影视久久网| 亚洲精品视频免费在线观看| 日韩网站在线播放| 国产99亚洲| 一区三区二区视频| 性生交大片免费全黄| 香蕉精品视频在线观看| 欧美人在线观看| 久久久久99精品| 午夜亚洲视频| 国产精品入口免费视频一| 亚洲视频中文字幕在线观看| 精品亚洲aⅴ乱码一区二区三区| 成人激情视频在线播放| 国产黄色一区二区| 成人免费毛片片v| 美乳视频一区二区| 色大18成网站www在线观看| 亚洲少妇屁股交4| 日韩精品在线视频免费观看| 中文字幕乱码在线播放| 在线精品视频一区二区| 97人人爽人人| 国产精品极品| 国产一区二区三区在线观看网站| 男人的午夜天堂| 精品成人国产| 国产精品美腿一区在线看| 99国产精品久久久久久久成人 | 91精品国产91热久久久做人人| 日本少妇激三级做爰在线| 粉嫩一区二区三区四区公司1| 亚洲欧美福利视频| 黄色片子在线观看| 亚洲深夜福利| 成人写真福利网| 亚洲欧美日韩免费| 1区2区3区欧美| 免费无遮挡无码永久视频| 88xx成人网| 亚洲国产精品久久久久| 99久久99久久精品免费看小说.| 重囗味另类老妇506070| 日韩av免费一区| 北条麻妃一二三区| 欧美激情一二三区| 国产精品国产亚洲精品看不卡| 电影天堂国产精品| 亚洲а∨天堂久久精品9966| 成年人免费视频播放| 亚洲国产专区| 91美女高潮出水| 国产中文在线视频| 午夜精彩视频在线观看不卡| 国产精品一区二区小说| 欧美调教网站| 欧美第一黄网免费网站| 中文字幕免费高清在线观看| jizz一区二区| 欧美一区二区三区综合| 国产精品字幕| 国产视频精品久久久| 免费在线观看亚洲| 激情综合色综合久久综合| 欧美连裤袜在线视频| ****av在线网毛片| 日韩欧美二区三区| www.97视频| 蜜臀av性久久久久蜜臀aⅴ四虎| 欧美成人在线免费观看| а√在线中文网新版地址在线| 91精品综合久久久久久| 日韩av片在线免费观看| 日韩中文字幕区一区有砖一区| 国内视频一区二区| 黑人极品ⅴideos精品欧美棵| 欧美久久免费观看| 日本中文在线视频| 九九视频精品免费| 亚洲午夜久久久影院伊人| 国产高清不卡| 亚洲人成毛片在线播放| 毛片在线免费视频| 久久免费精品国产久精品久久久久| 亚洲理论电影在线观看| 成人香蕉社区| 国模叶桐国产精品一区| 日本精品久久久久| 午夜精品久久久| 国产麻豆xxxvideo实拍| 国产亚洲精品bv在线观看| 国产区日韩欧美| 中文字幕色婷婷在线视频| 亚洲美女性生活视频| 99精品人妻国产毛片| 国产欧美一区视频| 老司机午夜性大片| 亚洲天堂免费| 成人av片网址| 最近高清中文在线字幕在线观看1| 精品亚洲国产成av人片传媒| 中文字幕在线播| 国产欧美精品区一区二区三区| 中文字幕一区二区三区四区在线视频| 国产亚洲一卡2卡3卡4卡新区| 国产精品福利久久久| 97超碰国产一区二区三区| 欧美性色黄大片手机版| 日韩在线一卡二卡| 毛片一区二区| 蜜桃精品久久久久久久免费影院| av日韩中文| 精品网站999www| 精品国产乱子伦| 国产精品免费视频一区| 亚洲综合20p| 亚洲日韩成人| 色噜噜狠狠色综合网| 久久天天久久| 久久久久久久久久久成人| 日本韩国免费观看| 91国模大尺度私拍在线视频| 多男操一女视频| 国产黄色精品视频| 国产男女无遮挡| 亚欧美无遮挡hd高清在线视频| 99久久无色码| 国模套图日韩精品一区二区| 俺去亚洲欧洲欧美日韩| 男人的天堂a在线| 91久久精品一区二区| 极品久久久久久| 久久久久久久电影| 国产又粗又猛大又黄又爽| 亚洲精品四区| 艳母动漫在线免费观看| 亚洲ab电影| 亚洲va欧美va国产综合剧情| 亚洲欧美se| 精品自在线视频| jizz日韩| 日韩风俗一区 二区| 一区二区www| 欧美视频裸体精品| 真实国产乱子伦对白在线| 久久久久久久久久久久久久久99 | 国产99一区视频免费| 免费午夜视频在线观看| 欧美国产另类| 亚洲国产精品综合| 日本午夜精品| 99国产在线视频| 国产欧美自拍| 欧美亚洲在线视频| 国产羞羞视频在线播放| 久久精品福利视频| 国产福利免费在线观看| 亚洲精品美女在线观看| wwwav在线播放| 欧美日本韩国一区| 国产第一页在线观看| 五月婷婷综合网| 久草视频手机在线观看| 1024成人网色www| 伊人影院综合网| 久久蜜桃av一区二区天堂| 国产chinesehd精品露脸| 久久狠狠亚洲综合| 一路向西2在线观看| 日韩成人免费电影| 蜜臀久久99精品久久久酒店新书 | 国产精品女视频| 午夜欧美巨大性欧美巨大| 久久久久久亚洲| 黄色在线看片| 久久久综合免费视频| 人妖欧美1区| 欧美第一淫aaasss性| 在线h片观看| 欧美激情精品久久久久久免费印度| 国产精品实拍| 日韩中文字幕免费看| 午夜视频成人| 日韩在线免费高清视频| 成人午夜影视| 日韩专区在线观看| 久久77777| 美女少妇精品视频| 91极品在线| 欧美黑人国产人伦爽爽爽| 亚洲精品一线| 97精品国产97久久久久久| 大桥未久在线视频| 热久久这里只有精品| 另类图片综合电影| 国产精品激情av电影在线观看| 日韩一区精品| 91亚洲精品一区二区| 日韩黄色av| 精品国产乱码一区二区三区四区| 久9re热视频这里只有精品| 精品一区二区日本| 欧美午夜精品一区二区三区电影| 亚洲精品日韩精品| 一区二区三区网站| www.日本少妇| 久久久久国产精品午夜一区| 亚洲最大综合网| 国精品**一区二区三区在线蜜桃| 国产裸体视频网站| 91在线视频网址| 国产精品成人在线视频| 亚洲品质自拍视频网站| 国产成年人免费视频| 一本久久a久久免费精品不卡| 国产男人搡女人免费视频| 欧美丰满一区二区免费视频| 国产91免费看| 亚洲色图美腿丝袜| 成人av黄色| 91超碰caoporn97人人| 91大神在线观看线路一区| 91亚洲精品在线| 亚洲另类春色校园小说| 中文字幕日韩一区二区三区不卡| 亚洲视频一二| 孩娇小videos精品| 成人免费视频视频在线观看免费| 中文字幕国产综合| 亚洲欧洲综合另类在线| 久久夜色精品国产噜噜亚洲av| 欧美精品乱码久久久久久| 日韩在线观看视频一区| 在线观看成人黄色| 国精一区二区三区| 国产免费亚洲高清| 欧美亚视频在线中文字幕免费| 影音先锋亚洲视频| 国产欧美在线| 91视频福利网| 中文字幕国产一区二区| 精品在线视频免费| 91精品国产综合久久香蕉麻豆| 四虎国产精品永远| 欧美激情一区二区三区在线视频观看| 日韩欧美一区二区三区在线观看 | 男人天堂网在线视频| www亚洲欧美| 高清电影一区| 精品一区二区三区视频日产| 亚洲深深色噜噜狠狠爱网站| 国产野外作爱视频播放| 91亚洲精品久久久蜜桃| 青娱乐免费在线视频| 欧美人妖巨大在线| 可以在线观看的av网站| 午夜精品久久久久久久男人的天堂 | 欧美视频在线播放| 嫩草在线播放| 国内免费久久久久久久久久久| 亚洲影视资源| 视频一区二区精品| 久久国产一二区| 漂亮人妻被黑人久久精品| 亚洲综合一区在线| av 一区二区三区| 日韩视频永久免费观看| 99只有精品| 日韩欧美电影一区二区| 一区二区黄色| 97香蕉碰碰人妻国产欧美| 亚洲亚洲精品在线观看| av 一区二区三区| 欧美成在线视频| 91久久青草| av电影一区二区三区| 久久成人av少妇免费| wwwww黄色| 欧美日韩三级在线| 在线观看a视频| 成人精品久久一区二区三区| 久久在线视频| 污污视频在线免费| 一区二区在线观看免费| 国产黄色片免费观看| 欧美黑人一区二区三区| swag国产精品一区二区| 69sex久久精品国产麻豆| 成人av资源网站| 狠狠躁夜夜躁人人爽天天高潮| 亚洲精品国产欧美| 欧美电影免费观看网站| 日韩欧美一区二区三区久久婷婷| 久热精品在线| 国产一级淫片久久久片a级| 欧美无人高清视频在线观看| 亚洲xxxxxx| 亚洲一区二区三区xxx视频| 欧美日一区二区三区在线观看国产免| 亚洲综合伊人久久| 亚洲韩国一区二区三区| 深夜福利视频一区| 国产精品久久一区主播| 久久久久久久久久久久久久久久久久 | 亚洲黄色av网站| 亚洲第一影院| 在线视频精品一区| 高清不卡一区二区| 台湾佬中文在线| 日韩专区在线观看| 大桥未久女教师av一区二区| 久久久999视频| 中文字幕不卡三区| 理论片中文字幕| 国产成人精品a视频一区www| 国产精品久久久久久麻豆一区软件| 在线观看中文av| 欧美性xxxxx| 国产在线观看免费麻豆| 国产亚洲自拍偷拍| 青青草国产精品97视觉盛宴| 国产日韩欧美在线观看视频| 日韩经典中文字幕| 亚洲精品伦理| 青娱乐自拍偷拍| 中文字幕欧美一区| 婷婷在线观看视频| 国产日韩欧美在线观看| 亚洲国产婷婷| 成人一级黄色大片| 亚洲欧美日韩国产成人| 成人在线视频区| 免费黄色福利视频| 伊人夜夜躁av伊人久久| 国产三级视频在线看| 99中文字幕| 美女视频黄 久久| 日本网站在线播放| www.欧美免费| 亚洲免费福利一区| 亚洲精品鲁一鲁一区二区三区| 在线观看91精品国产入口| 俺来俺也去www色在线观看| 亚洲国产午夜伦理片大全在线观看网站 | 一本一道久久a久久精品综合蜜臀|