成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Redisson簡(jiǎn)明教程—你家的鎖芯該換了

數(shù)據(jù)庫(kù) 其他數(shù)據(jù)庫(kù)
今天咱們就來(lái)聊聊Redisson提供的各種鎖,Redisson就像是Redis給Java程序員的一把瑞士軍刀,不僅能存數(shù)據(jù),還能玩出各種分布式花樣。

1.簡(jiǎn)介

2.看門狗

  2-1.為什么需要這個(gè)"狗子"?

  2-2.工作原理

  2-3.如何“擼狗子”

3.可重入鎖:你的分布式"萬(wàn)能鑰匙"

  3-1.Redisson可重入鎖的魔法

  3-2.使用姿勢(shì)大全

  3-3.公平鎖

  3-4.非公平鎖

  3-5.可重入原理深扒

4.聯(lián)鎖:分布式鎖中的"全家桶套餐"

  4-1.聯(lián)鎖是什么?——"要么全有,要么全無(wú)"的霸道總裁

  4-2.為什么需要聯(lián)鎖?

  4-3.聯(lián)鎖使用三件套

  4-4.聯(lián)鎖的硬核原理

  4-5.聯(lián)鎖的三大禁忌

5.Redisson讀寫鎖:分布式系統(tǒng)中的"讀寫分離"高手

  5-1.使用姿勢(shì)

  5-2.原理深扒

6.信號(hào)量(Semaphore):分布式系統(tǒng)中的"限量入場(chǎng)券"

  6-1.使用姿勢(shì)大全

  6-2.原理深扒

7.紅鎖(RedLock):分布式鎖界的“聯(lián)合國(guó)維和部隊(duì)”

  7-1.核心原理

  7-2.注意事項(xiàng)

  7-3.使用姿勢(shì)

8.閉鎖(CountDownLatch):分布式系統(tǒng)中的"集結(jié)號(hào)"

  8-1.使用姿勢(shì)

  8-2.原理深扒

9.總結(jié)

1.簡(jiǎn)介

各位攻城獅們,你還在使用原生命令來(lái)上鎖么?看來(lái)你還是不夠懶,餃子都給你包好了,你非要吃大餅配炒韭菜,快點(diǎn)改善一下“伙食”吧,寫代碼也要來(lái)點(diǎn)幸福感。今天咱們就來(lái)聊聊Redisson提供的各種鎖,Redisson就像是Redis給Java程序員的一把瑞士軍刀,不僅能存數(shù)據(jù),還能玩出各種分布式花樣。

  • Redis版本:Redis 2.8+,理想版本5.0+(支持 Stream、模塊化等高級(jí)特性,Redisson 能秀出全部技能)。
  • 架構(gòu)模式:支持單機(jī)、哨兵和集群(集群模式可靠性更高)

2.看門狗

想象你上廁所(獲取鎖)時(shí)帶著一只忠心耿耿的阿黃(看門狗)。當(dāng)你蹲坑時(shí)間快到時(shí)(鎖快要過(guò)期),阿黃就會(huì)大叫:"主人你還沒(méi)完事嗎?我給你續(xù)時(shí)間啦!"(自動(dòng)續(xù)期)

2-1.為什么需要這個(gè)"狗子"?

  • 防止業(yè)務(wù)沒(méi)執(zhí)行完鎖就過(guò)期:默認(rèn)鎖30秒過(guò)期,但萬(wàn)一你的業(yè)務(wù)要31秒呢?
  • 避免鎖丟失:如果客戶端崩潰,看門狗停止續(xù)期,鎖最終會(huì)自動(dòng)釋放
  • 不用手動(dòng)計(jì)算業(yè)務(wù)時(shí)間:再也不用戰(zhàn)戰(zhàn)兢兢估算業(yè)務(wù)執(zhí)行時(shí)間了

2-2.工作原理

圖片

  • 首次加鎖:默認(rèn)設(shè)置鎖過(guò)期時(shí)間30秒
  • 啟動(dòng)看門狗:加鎖成功后啟動(dòng)一個(gè)定時(shí)任務(wù)(后臺(tái)線程)
  • 定期續(xù)期:每10秒(過(guò)期時(shí)間的1/3)檢查業(yè)務(wù)是否完成。未完成:執(zhí)行expire命令把鎖再續(xù)30秒;已完成:停止續(xù)期。
  • 最終釋放:業(yè)務(wù)完成調(diào)用unlock或客戶端斷開(kāi)連接時(shí)釋放

2-3.如何“擼狗子”

Config config = new Config();
config.setLockWatchdogTimeout(30000L); // 單位毫秒,默認(rèn)就是30秒
// ...
RedissonClient redisson = Redisson.create(config);
// 你也可以在加鎖時(shí)指定(會(huì)覆蓋默認(rèn)值)
lock.lock(60, TimeUnit.SECONDS); // 這時(shí)看門狗會(huì)按60秒周期續(xù)期

3.可重入鎖:你的分布式"萬(wàn)能鑰匙"

我們都知道Java中ReentrantLock和synchronized都是可重入鎖,但都只能用于單機(jī)環(huán)境的,在分布式環(huán)境下,Redisson給我提供了類似體驗(yàn)的可重入鎖。

3-1.Redisson可重入鎖的魔法

  • 線程安全:不同JVM的相同線程也可重入
  • 自動(dòng)續(xù)期:看門狗機(jī)制?;睿J(rèn)30秒)
  • 公平/非公平:兩種模式可選
  • 超時(shí)機(jī)制:避免無(wú)限等待

3-2.使用姿勢(shì)大全

基礎(chǔ)款(阻塞式):
RLock lock = redisson.getLock("orderLock");
lock.lock(); // 一直等到天荒地老
try {
    // 你的核心業(yè)務(wù)
} finally {
    lock.unlock(); // 一定要放在finally!
}
高級(jí)款(嘗試獲?。?/span>
if (lock.tryLock(3, 30, TimeUnit.SECONDS)) { // 最多等3秒,鎖30秒自動(dòng)過(guò)期
    try {
        // 業(yè)務(wù)處理
    } finally {
        lock.unlock();
    }
} else {
    log.warn("獲取鎖失敗,換個(gè)姿勢(shì)再試一次");
}
騷操作款(異步獲取):
RFuture<Void> lockFuture = lock.lockAsync();
lockFuture.whenComplete((res, ex) -> {
    if (ex == null) {
        try {
            // 異步業(yè)務(wù)處理
        } finally {
            lock.unlock();
        }
    }
});

3-3.公平鎖

  • 排隊(duì)機(jī)制:使用Redis的List結(jié)構(gòu)維護(hù)等待隊(duì)列
  • 訂閱發(fā)布:通過(guò)Redis的pub/sub通知下一個(gè)等待者
  • 雙重檢查:獲取鎖時(shí)檢查自己是否在隊(duì)列頭部
RLock fairLock = redisson.getFairLock("myFairLock");
try {
    fairLock.lock();
    // 業(yè)務(wù)邏輯
} finally {
    fairLock.unlock();
}

3-4.非公平鎖

  • 直接競(jìng)爭(zhēng):所有線程同時(shí)嘗試CAS操作
  • 效率優(yōu)先:沒(méi)有隊(duì)列維護(hù)開(kāi)銷
  • 可能饑餓:運(yùn)氣差的線程可能長(zhǎng)期得不到鎖
RLock nonFairLock = redisson.getLock("hotItemLock");
if (nonFairLock.tryLock(50, TimeUnit.MILLISECONDS)) { // 拼手速!
    try {
        // 秒殺業(yè)務(wù)邏輯
    } finally {
        nonFairLock.unlock();
    }
}

3-5.可重入原理深扒

加鎖Lua腳本偽代碼:

-- 參數(shù):鎖key、鎖超時(shí)時(shí)間、客戶端ID+線程ID
if (redis.call('exists', KEYS[1]) == 0) then
    -- 鎖不存在,直接獲取
    redis.call('hset', KEYS[1], ARGV[2], 1);
    redis.call('pexpire', KEYS[1], ARGV[1]);
    returnnil;
end;

if (redis.call('hexists', KEYS[1], ARGV[2]) == 1) then
    -- 重入情況:計(jì)數(shù)器+1
    redis.call('hincrby', KEYS[1], ARGV[2], 1);
    redis.call('pexpire', KEYS[1], ARGV[1]);
    returnnil;
end;

-- 鎖被其他線程持有
return redis.call('pttl', KEYS[1]); -- 返回剩余過(guò)期時(shí)間

解鎖Lua腳本偽代碼:

-- 參數(shù):鎖key、客戶端ID+線程ID
if (redis.call('hexists', KEYS[1], ARGV[1]) == 0) then
    -- 壓根沒(méi)持有鎖
    returnnil;
end;

-- 重入次數(shù)-1
local counter = redis.call('hincrby', KEYS[1], ARGV[1], -1);
if (counter > 0) then
    -- 還有重入次數(shù),更新過(guò)期時(shí)間
    redis.call('pexpire', KEYS[1], 30000);
    return0;
else
    -- 最后一次解鎖,刪除key
    redis.call('del', KEYS[1]);
    -- 發(fā)布解鎖消息
    redis.call('publish', KEYS[2], ARGV[2]);
    return1;
end;

4.聯(lián)鎖:分布式鎖中的"全家桶套餐"

4-1.聯(lián)鎖是什么?——"要么全有,要么全無(wú)"的霸道總裁

想象你要同時(shí)約三個(gè)女神約會(huì):

  • 女神A:周末有空 ?
  • 女神B:周末有空 ?
  • 女神C:周末要加班 ? Redisson聯(lián)鎖的做法是:只要有一個(gè)拒絕,就取消所有約會(huì)!這就是聯(lián)鎖的"All or Nothing"哲學(xué)。

4-2.為什么需要聯(lián)鎖?

典型場(chǎng)景:
  • 跨資源事務(wù):需要同時(shí)鎖定訂單、庫(kù)存、優(yōu)惠券三個(gè)系統(tǒng)
  • 數(shù)據(jù)一致性:確保多個(gè)關(guān)聯(lián)資源同時(shí)被保護(hù)
  • 避免死鎖:防止交叉等待導(dǎo)致的死鎖情況

4-3.聯(lián)鎖使用三件套

基本用法:

// 準(zhǔn)備三把鎖(就像三個(gè)女神的聯(lián)系方式)
RLock lock1 = redisson.getLock("order_lock");
RLock lock2 = redisson.getLock("stock_lock");
RLock lock3 = redisson.getLock("coupon_lock");

// 創(chuàng)建聯(lián)鎖"約會(huì)套餐"
RedissonMultiLock multiLock = new RedissonMultiLock(lock1, lock2, lock3);

try {
    // 嘗試同時(shí)鎖定(約三位女神)
    if (multiLock.tryLock(3, 30, TimeUnit.SECONDS)) {
        // 三位都同意了!開(kāi)始你的表演
        processOrder();
        updateStock();
        useCoupon();
    } else {
        log.warn("有個(gè)女神拒絕了你");
    }
} finally {
    multiLock.unlock(); // 記得送她們回家
}

高階技巧:

// 動(dòng)態(tài)構(gòu)造聯(lián)鎖(適合不確定數(shù)量的資源)
List<RLock> locks = resourceIds.stream()
    .map(id -> redisson.getLock("resource_" + id))
    .collect(Collectors.toList());

RedissonMultiLock dynamicLock = new RedissonMultiLock(locks.toArray(new RLock[0]));

4-4.聯(lián)鎖的硬核原理

加鎖流程:
  • 順序加鎖:按傳入鎖的順序依次嘗試獲取
  • 失敗回滾:任意一個(gè)鎖獲取失敗時(shí),釋放已獲得的所有鎖
  • 統(tǒng)一過(guò)期時(shí)間:所有鎖使用相同的過(guò)期時(shí)間
底層Lua腳本(簡(jiǎn)化版):
-- 參數(shù):多個(gè)鎖的KEYS,統(tǒng)一過(guò)期時(shí)間,線程標(biāo)識(shí)
local failed = false
for i, key inipairs(KEYS) do
    if redis.call('setnx', key, ARGV[2]) == 0then
        failed = true
        break
    end
    redis.call('expire', key, ARGV[1])
end

if failed then
    -- 釋放已經(jīng)獲取的鎖
    for j = 1, i-1do
        redis.call('del', KEYS[j])
    end
    return0
end
return1

4-5.聯(lián)鎖的三大禁忌

亂序使用(導(dǎo)致死鎖):

// 線程1:
multiLock(lockA, lockB).lock();

// 線程2:
multiLock(lockB, lockA).lock(); // 危險(xiǎn)!可能死鎖

? 正確做法:全局統(tǒng)一加鎖順序

混合鎖類型:

// 混合普通鎖和公平鎖
new MultiLock(lock1, fairLock2); // 不推薦

? 正確做法:使用相同特性的鎖組合

忽略部分鎖失?。?/span>

if (!multiLock.tryLock()) {
    // 直接返回,不處理部分獲取成功的情況
    return; // 危險(xiǎn)!
}

? 正確做法:確保完全獲取或完全失敗

5.Redisson讀寫鎖:分布式系統(tǒng)中的"讀寫分離"高手

也許單機(jī)版的ReentrantReadWriteLock你聽(tīng)說(shuō)過(guò),但是分布式環(huán)境下的版本可能很少接觸到。

典型場(chǎng)景:
  • 讀多寫少系統(tǒng):比如商品詳情頁(yè)(每秒上萬(wàn)次讀取,每分鐘幾次更新)
  • 數(shù)據(jù)一致性要求:保證讀取時(shí)不會(huì)讀到半成品數(shù)據(jù)
  • 系統(tǒng)性能優(yōu)化:避免讀操作被不必要的串行化

5-1.使用姿勢(shì)

RReadWriteLock rwLock = redisson.getReadWriteLock("libraryBook_123");

// 讀操作(多個(gè)線程可同時(shí)進(jìn)入)
rwLock.readLock().lock();
try {
    // 查詢數(shù)據(jù)(安全讀?。?    Book book = getBookFromDB(123);
} finally {
    rwLock.readLock().unlock();
}

// 寫操作(獨(dú)占訪問(wèn))
rwLock.writeLock().lock();
try {
    // 修改數(shù)據(jù)(安全寫入)
    updateBookInDB(123, newVersion);
} finally {
    rwLock.writeLock().unlock();
}

5-2.原理深扒

加讀鎖Lua腳本(簡(jiǎn)化):

-- 檢查是否可以加讀鎖(沒(méi)有寫鎖或當(dāng)前線程持有寫鎖)
if redis.call('hget', KEYS[1], 'mode') == 'write' then
    -- 如果有寫鎖且不是當(dāng)前線程持有,則失敗
    if redis.call('hexists', KEYS[1], ARGV[2]) == 0 then
        return 0;
    end;
end;

-- 增加讀鎖計(jì)數(shù)
redis.call('hincrby', KEYS[1], ARGV[1], 1);
redis.call('pexpire', KEYS[1], ARGV[3]);
return 1;

加寫鎖Lua腳本(簡(jiǎn)化):

-- 檢查是否已有鎖
if redis.call('exists', KEYS[1]) == 1 then
    -- 如果是讀模式或有其他寫鎖
    if redis.call('hget', KEYS[1], 'mode') == 'read' or
       redis.call('hlen', KEYS[1]) > 1 then
        return0;
    end;
    
    -- 如果是當(dāng)前線程持有的寫鎖(重入)
    if redis.call('hexists', KEYS[1], ARGV[2]) == 1 then
        redis.call('hincrby', KEYS[1], ARGV[2], 1);
        return1;
    end;
end;

-- 獲取寫鎖
redis.call('hset', KEYS[1], 'mode', 'write');
redis.call('hset', KEYS[1], ARGV[2], 1);
redis.call('pexpire', KEYS[1], ARGV[3]);
return1;

6.信號(hào)量(Semaphore):分布式系統(tǒng)中的"限量入場(chǎng)券"

同樣的味道,Java中Semaphore的分布式版本。

6-1.使用姿勢(shì)大全

基礎(chǔ)用法:

// 獲取信號(hào)量(初始10個(gè)許可)
RSemaphore semaphore = redisson.getSemaphore("apiLimit");
semaphore.trySetPermits(10); // 設(shè)置許可數(shù)量

// 獲取許可(阻塞直到可用)
semaphore.acquire();
try {
    // 執(zhí)行業(yè)務(wù)(保證最多10個(gè)并發(fā))
    callLimitedAPI();
} finally {
    semaphore.release(); // 記得歸還!
}

// 嘗試獲取(非阻塞)
if (semaphore.tryAcquire()) {
    try {
        // 搶到許可了!
    } finally {
        semaphore.release();
    }
} else {
    log.warn("系統(tǒng)繁忙,請(qǐng)稍后再試");
}

高級(jí)技巧:

// 帶超時(shí)的嘗試獲取
if (semaphore.tryAcquire(3, 500, TimeUnit.MILLISECONDS)) {
    try {
        // 在500ms內(nèi)獲取到3個(gè)許可
        batchProcess();
    } finally {
        semaphore.release(3); // 歸還多個(gè)許可
    }
}

// 動(dòng)態(tài)調(diào)整許可數(shù)量
semaphore.addPermits(5); // 增加5個(gè)許可(擴(kuò)容)
semaphore.reducePermits(3); // 減少3個(gè)許可(縮容)

6-2.原理深扒

獲取許可的Lua腳本(簡(jiǎn)化):

-- 參數(shù):信號(hào)量key、請(qǐng)求許可數(shù)
local value = redis.call('get', KEYS[1])
if value >= ARGV[1] then
    return redis.call('decrby', KEYS[1], ARGV[1])
else
    return -1
end

釋放許可的Lua腳本(簡(jiǎn)化):

-- 參數(shù):信號(hào)量key、釋放許可數(shù)
return redis.call('incrby', KEYS[1], ARGV[1])

7.紅鎖(RedLock):分布式鎖界的“聯(lián)合國(guó)維和部隊(duì)”

RedLock 的誕生是為了對(duì)抗單點(diǎn) Redis 掛掉后鎖失效的問(wèn)題。它的目標(biāo)就是:“即使部分節(jié)點(diǎn)掛了,我也要穩(wěn)如老狗”。

7-1.核心原理

Redisson 的 RedLock 實(shí)現(xiàn)來(lái)源于 Redis 作者 antirez 提出的 Redlock 算法。流程如下:

  • 準(zhǔn)備多個(gè)獨(dú)立的 Redis 節(jié)點(diǎn)(注意:是互相獨(dú)立的,不是主從復(fù)制結(jié)構(gòu))。
  • 客戶端依次向這些節(jié)點(diǎn)嘗試加鎖(使用 SET NX PX 命令)。
  • 記錄耗時(shí):加鎖操作總共不能超過(guò)鎖過(guò)期時(shí)間的 1/2(比如設(shè)置鎖有效期 10 秒,那就必須 5 秒內(nèi)搞定加鎖)。
  • 加鎖成功節(jié)點(diǎn)超過(guò)半數(shù)(N/2 + 1)視為成功。
  • 若失敗,立刻釋放所有加鎖成功的節(jié)點(diǎn),以避免資源死鎖。
  • 釋放鎖時(shí),同樣要向所有節(jié)點(diǎn)發(fā)送 unlock 操作。

7-2.注意事項(xiàng)

  • RedLock 是為多主 Redis 實(shí)例準(zhǔn)備的,不是給 Redis Cluster 用的。
  • 你得維護(hù)多個(gè)彼此獨(dú)立的 Redis 實(shí)例,部署和運(yùn)維成本更高。
  • RedLock 的“強(qiáng)一致性”并非線性一致性,它只是通過(guò)多點(diǎn)確認(rèn)提升“高可用性”。

7-3.使用姿勢(shì)

// 準(zhǔn)備多個(gè)獨(dú)立的RLock實(shí)例
RLock lock1 = redissonClient1.getLock("lock");
RLock lock2 = redissonClient2.getLock("lock"); 
RLock lock3 = redissonClient3.getLock("lock");

// 構(gòu)造紅鎖(建議奇數(shù)個(gè),通常3/5個(gè))
RedissonRedLock redLock = new RedissonRedLock(lock1, lock2, lock3);

try {
    // 嘗試獲取鎖(等待時(shí)間100s,鎖持有時(shí)間30s)
    boolean locked = redLock.tryLock(100, 30, TimeUnit.SECONDS);
    if (locked) {
        // 執(zhí)行業(yè)務(wù)邏輯
        doCriticalWork();
    }
} finally {
    redLock.unlock();
}

8.閉鎖(CountDownLatch):分布式系統(tǒng)中的"集結(jié)號(hào)"

一樣是Java的CountDownLatch的分布式版本,用法也是基本一樣。

8-1.使用姿勢(shì)

// 主協(xié)調(diào)節(jié)點(diǎn)(教官)
RCountDownLatch latch = redisson.getCountDownLatch("batchTaskLatch");
latch.trySetCount(5); // 需要等待5個(gè)任務(wù)

// 工作節(jié)點(diǎn)(學(xué)員)
RCountDownLatch workerLatch = redisson.getCountDownLatch("batchTaskLatch");
workerLatch.countDown(); // 完成任務(wù)時(shí)調(diào)用

// 主節(jié)點(diǎn)等待(在另一個(gè)線程/JVM)
latch.await(); // 阻塞直到計(jì)數(shù)器歸零
System.out.println("所有任務(wù)已完成!");

8-2.原理深扒

關(guān)鍵操作偽代碼:

-- countDown操作
local remaining = redis.call('decr', KEYS[1])
if remaining <= 0then
    redis.call('publish', KEYS[2], '0') -- 通知所有等待者
    redis.call('del', KEYS[1]) -- 清理計(jì)數(shù)器
end
return remaining

-- await操作
local count = redis.call('get', KEYS[1])
if count == falseortonumber(count) <= 0then
    return1-- 已經(jīng)完成
end
return0-- 需要繼續(xù)等待

9.總結(jié)

Redisson 提供了豐富的分布式鎖實(shí)現(xiàn),適用于各種分布式場(chǎng)景,使用體驗(yàn)更好,選擇鎖類型時(shí)應(yīng)根據(jù)具體業(yè)務(wù)場(chǎng)景和需求來(lái)決定,同時(shí)要注意鎖的粒度和持有時(shí)間,避免分布式死鎖和性能問(wèn)題。

關(guān)于作者,高宏杰,轉(zhuǎn)轉(zhuǎn)門店技術(shù)部研發(fā)工程師。

責(zé)任編輯:武曉燕 來(lái)源: 轉(zhuǎn)轉(zhuǎn)技術(shù)
相關(guān)推薦

2013-12-03 13:05:30

Lua腳本語(yǔ)言

2023-10-20 14:08:35

digDNS

2018-02-07 10:59:38

2014-06-20 10:51:35

Linux LVM邏輯卷

2011-06-03 08:49:54

Java

2010-05-26 10:42:20

SVN1.5配置

2023-11-02 14:26:30

PyTorch機(jī)器學(xué)習(xí)

2023-11-02 14:30:25

機(jī)器學(xué)習(xí)

2009-08-06 17:45:08

C# Webservi

2021-01-05 09:55:46

TmateLinux命令

2013-12-04 11:21:01

2010-12-15 12:48:26

VirtualBox

2009-09-02 17:38:19

C#開(kāi)發(fā)GIS

2011-08-17 09:55:45

Objective-CCategory

2021-05-08 09:02:48

KubeBuilderOperatork8s

2009-07-03 13:45:48

JSP簡(jiǎn)明教程組件為中心

2011-08-17 10:00:12

Objective-CProperty

2021-05-11 09:31:31

kustomizeoperator kubernetes

2010-05-25 16:11:25

Git-SVN

2024-09-13 09:32:30

點(diǎn)贊
收藏

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

主站蜘蛛池模板: 亚洲国产偷| 国产精品精品视频 | 色综合久久天天综合网 | 91精品国产综合久久久久久丝袜 | 精品视频网 | 成人免费网站视频 | 性高湖久久久久久久久 | 黄色片视频网站 | 午夜影院在线观看视频 | 妖精视频一区二区三区 | 国产精品自拍视频 | 亚洲国产一区二区三区四区 | 国产日韩欧美在线 | 黄色精品视频网站 | 99久久视频| 欧美日韩综合精品 | 国产一区二区 | 亚洲视频一区二区三区四区 | 午夜一区二区三区视频 | 精品国产一区二区三区久久久蜜月 | 一区二区中文 | 天堂免费看片 | 99精品久久 | 中文字字幕一区二区三区四区五区 | 欧美日韩精品亚洲 | 成年人在线观看 | 日本免费一区二区三区四区 | gogo肉体亚洲高清在线视 | 97在线超碰 | 欧美舔穴 | 国产精品亚洲成在人线 | 久久免费国产 | 国产精品一区在线观看 | 波多野结衣一区二区 | 国产午夜一级 | 欧美日韩亚洲国产综合 | 国产一区成人 | 99亚洲精品 | 国产三级精品三级在线观看四季网 | 中文在线一区 | 亚洲黄色在线 |