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

并發場景下的冪等問題-分布式鎖詳解

開發 開發工具 分布式
本文從釘釘實人認證場景的一例數據重復問題出發,分析了其原因是因為并發導致冪等失效,引出冪等的概念。

寫在前面:本文討論的冪等問題,均為并發場景下的冪等問題。即系統本存在冪等設計,但是在并發場景下失效了。

一 摘要

本文從釘釘實人認證場景的一例數據重復問題出發,分析了其原因是因為并發導致冪等失效,引出冪等的概念。

針對并發場景下的冪等問題,提出了一種實現冪等可行的方法論,結合通訊錄加人業務場景對數據庫冪等問題進行了簡單分析,就分布式鎖實現冪等方法展開了詳細討論。

分析了鎖在分布式場景下存在的問題,包括單點故障、網絡超時、錯誤釋放他人鎖、提前釋放鎖以及分布式鎖單點故障等,提出了對應的解決方案,介紹了對應方案的具體實現。

二 問題

釘釘實人認證業務存在數據重復的問題。

1 問題現象

正常情況下,數據庫中應該只有一條實人認證成功記錄,但是實際上某用戶有多條。

2 問題原因

并發導致了不冪等。

我們先來回顧一下冪等的概念:

冪等(idempotent、idempotence)是一個數學與計算機學概念,常見于抽象代數中。

在編程中一個冪等操作的特點是其任意多次執行所產生的影響均與一次執行的影響相同。

--來自百度百科

實人認證在業務上有冪等設計,其一般流程為:

1)用戶選擇實人認證后會在服務端初始化一條記錄;

2)用戶在釘釘移動端按照指示完成人臉比對;

3)比對完成后訪問服務端修改數據庫狀態。

在第3步中,在修改數據庫狀態之前,會判斷「是否已經初始化」、「是否已經實人認證」以及「智科是否返回認證成功」以保證冪等。僅當請求首次訪問服務端嘗試修改數據庫狀態時,才能滿足冪等的判斷條件并修改數據庫狀態。其余任意次請求將直接返回,對數據庫狀態無影響。請求多次訪問服務端所產生的結果,和請求首次訪問服務端一致。因此,在實人認證成功的前提下,數據庫應當有且僅有一條認證成功的記錄。

但是在實際過程中我們發現,同一個請求會多次修改數據庫狀態,系統并未按照我們預期的那樣實現冪等。究其原因,是因為請求并發訪問,在首次請求完成修改服務端狀態前,并發的其他請求和首次請求都通過了冪等判斷,對數據庫狀態進行了多次修改。

并發導致了原冪等設計失效。

并發導致了不冪等。

三 解決方案

解決并發場景下冪等問題的關鍵,是找到唯一性約束,執行唯一性檢查,相同的數據保存一次,相同的請求操作一次。

一次訪問服務端的請求,可能產生以下幾種交互:

  1. 與數據源交互,例如數據庫狀態變更等;
  2. 與其他業務系統交互,例如調用下游服務或發送消息等;

一次請求可以只包含一次交互,也可以包含多次交互。例如一次請求可以僅僅修改一次數據庫狀態,也可以在修改數據庫狀態后再發送一條數據庫狀態修改成功的消息。

于是我們可以得出一個結論:并發場景下,如果一個系統依賴的組件冪等,那么該系統在天然冪等。

以數據庫為例,如果一個請求對數據造成的影響是新增一條數據,那么唯一索引可以是冪等問題的解法。數據庫會幫助我們執行唯一性檢查,相同數據不會重復落庫。

釘釘通訊錄加人就是通過數據庫的唯一索引解決了冪等問題。以釘釘通訊錄加人為例,在向數據庫寫數據之前,會先判斷數據是否已經存在于數據庫之中,如果不存在,加人請求最終會向數據庫的員工表插入一條數據。大量相同的并發的通訊錄加人請求讓系統的冪等設計失效成為可能。在一次加人請求中,(組織ID,工號)可以唯一標記一個請求,在數據庫中,也存在(組織ID,工號)的唯一索引。因此我們可以保證,多次相同的加人請求,只會修改一次數據庫狀態,即添加一條記錄。

如果所依賴的組件天然冪等,那么問題就簡單了,但是實際情況往往更加復雜。并發場景下,如果系統依賴的組件無法冪等,我們就需要使用額外的手段實現冪等。

一個常用的手段就是使用分布式鎖。分布式鎖的實現方式有很多,比較常用的是緩存式分布式鎖。

四 分布式鎖

在What is a Java distributed lock?中有這樣幾段話:

In computer science, locks are mechanisms in a multithreaded environment to prevent different threads from operating on the same resource. When using locking, a resource is "locked" for access by a specific thread, and can only be accessed by a different thread once the resource has been released. Locks have several benefits: they stop two threads from doing the same work, and they prevent errors and data corruption when two threads try to use the same resource simultaneously.

Distributed locks in Java are locks that can work with not only multiple threads running on the same machine, but also threads running on clients on different machines in a distributed system. The threads on these separate machines must communicate and coordinate to make sure that none of them try to access a resource that has been locked up by another.

這幾段話告訴我們,鎖的本質是共享資源的互斥訪問,分布式鎖解決了分布式系統中共享資源的互斥訪問的問題。

java.util.concurrent.locks包提供了豐富的鎖實現,包括公平鎖/非公平鎖,阻塞鎖/非阻塞鎖,讀寫鎖以及可重入鎖等。

我們要如何實現一個分布式鎖呢?

方案一

分布式系統中常見有兩個問題:

1)單點故障問題,即當持有鎖的應用發生單點故障時,鎖將被長期無效占有;

2)網絡超時問題,即當客戶端發生網絡超時但實際上鎖成功時,我們無法再次正確的

獲取鎖。

要解決問題1,一個簡單的方案是引入過期時間(lease time),對鎖的持有將是有時效的,當應用發生單點故障時,被其持有的鎖可以自動釋放。

要解決問題2,一個簡單的方案是支持可重入,我們為每個獲取鎖的客戶端都配置一個不會重復的身份標識(通常是UUID),上鎖成功后鎖將帶有該客戶端的身份標識。當實際上鎖成功而客戶端超時重試時,我們可以判斷鎖已被該客戶端持有而返回成功。

綜上我們給出了一個lease-based distribute lock方案。出于性能考量,使用緩存作為鎖的存儲介質,利用MVCC(Multiversion concurrency control)機制解決共享資源互斥訪問問題,具體實現可見附錄代碼。

分布式鎖的一般使用方式如下

  • 初始化分布式鎖的工廠
  • 利用工廠生成一個分布式鎖實例
  • 使用該分布式實例上鎖和解鎖操作
  1. @Test 
  2. public void testTryLock() { 
  3.  
  4.     //初始化工廠 
  5.     MdbDistributeLockFactory mdbDistributeLockFactory = new MdbDistributeLockFactory(); 
  6.     mdbDistributeLockFactory.setNamespace(603); 
  7.     mdbDistributeLockFactory.setMtairManager(new MultiClusterTairManager()); 
  8.  
  9.     //獲得鎖 
  10.     DistributeLock lock = mdbDistributeLockFactory.getLock("TestLock"); 
  11.  
  12.     //上鎖解鎖操作 
  13.     boolean locked = lock.tryLock(); 
  14.     if (!locked) { 
  15.         return
  16.     } 
  17.     try { 
  18.         //do something  
  19.     } finally { 
  20.         lock.unlock(); 
  21.     } 

該方案簡單易用,但是問題也很明顯。例如,釋放鎖的時候只是簡單的將緩存中的key失效,所以存在錯誤釋放他人已持有鎖問題。所幸只要鎖的租期設置的足夠長,該問題出現幾率就足夠小。

我們借用Martin Kleppmann在文章How to do distributed locking中的一張圖說明該問題。

設想一種情況,當占有鎖的Client 1在釋放鎖之前,鎖就已經到期了,Client 2將獲取鎖,此時鎖被Client 2持有,但是Client 1可能會錯誤的將其釋放。一個更優秀的方案,我們給每個鎖都設置一個身份標識,在釋放鎖的時候,1)首先查詢鎖是否是自己的,2)如果是自己的則釋放鎖。受限于實現方式,步驟1和步驟2不是原子操作,在步驟1和步驟2之間,如果鎖到期被其他客戶端獲取,此時也會錯誤的釋放他人的鎖。

方案二

借助Redis的Lua腳本,可以完美的解決存在錯誤釋放他人已持有鎖問題的。在Distributed locks with Redis這篇文章的 Correct implementation with a single instance 這一節中,我們可以得到我們想要的答案——如何實現一個分布式鎖。

當我們想要獲取鎖時,我們可以執行如下方法

  1. SET resource_name my_random_value NX PX 30000 

當我們想要釋放鎖時,我們可以執行如下的Lua腳本

  1. if redis.call("get",KEYS[1]) == ARGV[1] then 
  2.     return redis.call("del",KEYS[1]) 
  3. else 
  4.     return 0 
  5. end 

方案三

在方案一和方案二的討論過程中,有一個問題被我們反復提及:鎖的自動釋放。

這是一把雙刃劍:

1)一方面它很好的解決了持有鎖的客戶端單點故障的問題

2)另一方面,如果鎖提前釋放,就會出現鎖的錯誤持有狀態

這個時候,我們可以引入Watch Dog自動續租機制,我們可以參考以下Redisson是如何實現的。

在上鎖成功后,Redisson會調用renewExpiration()方法開啟一個Watch Dog線程,為鎖自動續期。每過1/3時間續一次,成功則繼續下一次續期,失敗取消續期操作。

我們可以再看看Redisson是如何續期的。renewExpiration()方法的第17行renewExpirationAsync()方法是執行鎖續期的關鍵操作,我們進入到方法內部,可以看到Redisson也是使用Lua腳本進行鎖續租的:1)判斷鎖是否存在;2)如果存在則重置過期時間。

  1. private void renewExpiration() { 
  2.     ExpirationEntry ee = EXPIRATION_RENEWAL_MAP.get(getEntryName()); 
  3.     if (ee == null) { 
  4.         return
  5.     } 
  6.  
  7.     Timeout task = commandExecutor.getConnectionManager().newTimeout(timeout -> { 
  8.         ExpirationEntry ent = EXPIRATION_RENEWAL_MAP.get(getEntryName()); 
  9.         if (ent == null) { 
  10.             return
  11.         } 
  12.         Long threadId = ent.getFirstThreadId(); 
  13.         if (threadId == null) { 
  14.             return
  15.         } 
  16.  
  17.         RFuture<Boolean> future = renewExpirationAsync(threadId); 
  18.         future.onComplete((res, e) -> { 
  19.             if (e != null) { 
  20.                 log.error("Can't update lock " + getRawName() + " expiration", e); 
  21.                 EXPIRATION_RENEWAL_MAP.remove(getEntryName()); 
  22.                 return
  23.             } 
  24.  
  25.             if (res) { 
  26.                 // reschedule itself 
  27.                 renewExpiration(); 
  28.             } else { 
  29.                 cancelExpirationRenewal(null); 
  30.             } 
  31.         }); 
  32.     }, internalLockLeaseTime / 3, TimeUnit.MILLISECONDS); 
  33.  
  34.     ee.setTimeout(task); 
  1. protected RFuture<Boolean> renewExpirationAsync(long threadId) { 
  2.     return evalWriteAsync(getRawName(), LongCodec.INSTANCE, RedisCommands.EVAL_BOOLEAN, 
  3.                           "if (redis.call('hexists', KEYS[1], ARGV[2]) == 1) then " + 
  4.                           "redis.call('pexpire', KEYS[1], ARGV[1]); " + 
  5.                           "return 1; " + 
  6.                           "end; " + 
  7.                           "return 0;"
  8.                           Collections.singletonList(getRawName()), 
  9.                           internalLockLeaseTime, getLockName(threadId)); 

方案四

借助Redisson的自動續期機制,我們無需再擔心鎖的自動釋放。但是討論到這里,我還是不得不面對一個問題:分布式鎖本身不是一個分布式應用。當Redis服務器故障無法正常工作時,整個分布式鎖也就無法提供服務。

更進一步,我們可以看看Distributed locks with Redis這篇文章中提到的Redlock算法及其實現。

Redlock算法不是銀彈,關于它的好與壞,也有很多爭論:

How to do distributed locking:

https://martin.kleppmann.com/2016/02/08/how-to-do-distributed-locking.html

Is Redlock safe?:

http://antirez.com/news/101

Martin Kleppmann和Antirez關于Redlock的爭辯:

https://news.ycombinator.com/item

參考資料

What is a Java distributed lock?

https://redisson.org/glossary/java-distributed-lock.html

Distributed locks and synchronizers:

https://github.com/redisson/redisson/wiki/8.-distributed-locks-and-synchronizers

Distributed locks with Redis:

https://redis.io/topics/distlock?spm=ata.21736010.0.0.31f77e3aFs96rz

附錄

分布式鎖

  1. public class MdbDistributeLock implements DistributeLock { 
  2.  
  3.     /** 
  4.      * 鎖的命名空間 
  5.      */ 
  6.     private final int namespace; 
  7.  
  8.     /** 
  9.      * 鎖對應的緩存key 
  10.      */ 
  11.     private final String lockName; 
  12.  
  13.     /** 
  14.      * 鎖的唯一標識,保證可重入,以應對put成功,但是返回超時的情況 
  15.      */ 
  16.     private final String lockId; 
  17.  
  18.     /** 
  19.      * 是否持有鎖。true:是 
  20.      */ 
  21.     private boolean locked; 
  22.  
  23.     /** 
  24.      * 緩存實例 
  25.      */ 
  26.     private final TairManager tairManager; 
  27.  
  28.     public MdbDistributeLock(TairManager tairManager, int namespace, String lockCacheKey) { 
  29.  
  30.         this.tairManager = tairManager; 
  31.         this.namespace = namespace; 
  32.         this.lockName = lockCacheKey; 
  33.         this.lockId = UUID.randomUUID().toString(); 
  34.     } 
  35.  
  36.     @Override 
  37.     public boolean tryLock() { 
  38.  
  39.         try { 
  40.             //獲取鎖狀態 
  41.             Result<DataEntry> getResult = null
  42.             ResultCode getResultCode = null
  43.             for (int cnt = 0; cnt < DEFAULT_RETRY_TIMES; cnt++) { 
  44.                 getResult = tairManager.get(namespace, lockName); 
  45.                 getResultCode = getResult == null ? null : getResult.getRc(); 
  46.                 if (noNeedRetry(getResultCode)) { 
  47.                     break; 
  48.                 } 
  49.             } 
  50.  
  51.             //重入,已持有鎖,返回成功 
  52.             if (ResultCode.SUCCESS.equals(getResultCode) 
  53.                 && getResult.getValue() != null && lockId.equals(getResult.getValue().getValue())) { 
  54.                 locked = true
  55.                 return true
  56.             } 
  57.  
  58.             //不可獲取鎖,返回失敗 
  59.             if (!ResultCode.DATANOTEXSITS.equals(getResultCode)) { 
  60.                 log.error("tryLock fail code={} lock={} traceId={}", getResultCode, this, EagleEye.getTraceId()); 
  61.                 return false
  62.             } 
  63.  
  64.             //嘗試獲取鎖 
  65.             ResultCode putResultCode = null
  66.             for (int cnt = 0; cnt < DEFAULT_RETRY_TIMES; cnt++) { 
  67.                 putResultCode = tairManager.put(namespace, lockName, lockId, MDB_CACHE_VERSION, 
  68.                     DEFAULT_EXPIRE_TIME_SEC); 
  69.                 if (noNeedRetry(putResultCode)) { 
  70.                     break; 
  71.                 } 
  72.             } 
  73.             if (!ResultCode.SUCCESS.equals(putResultCode)) { 
  74.                 log.error("tryLock fail code={} lock={} traceId={}", getResultCode, this, EagleEye.getTraceId()); 
  75.                 return false
  76.             } 
  77.             locked = true
  78.             return true
  79.  
  80.         } catch (Exception e) { 
  81.             log.error("DistributedLock.tryLock fail lock={}", this, e); 
  82.         } 
  83.         return false
  84.     } 
  85.  
  86.     @Override 
  87.     public void unlock() { 
  88.  
  89.         if (!locked) { 
  90.             return
  91.         } 
  92.         ResultCode resultCode = tairManager.invalid(namespace, lockName); 
  93.         if (!resultCode.isSuccess()) { 
  94.             log.error("DistributedLock.unlock fail lock={} resultCode={} traceId={}", this, resultCode, 
  95.                 EagleEye.getTraceId()); 
  96.         } 
  97.         locked = false
  98.     } 
  99.  
  100.     /** 
  101.      * 判斷是否需要重試 
  102.      * 
  103.      * @param resultCode 緩存的返回碼 
  104.      * @return true:不用重試 
  105.      */ 
  106.     private boolean noNeedRetry(ResultCode resultCode) { 
  107.         return resultCode != null && !ResultCode.CONNERROR.equals(resultCode) && !ResultCode.TIMEOUT.equals( 
  108.             resultCode) && !ResultCode.UNKNOW.equals(resultCode); 
  109.     } 
  110.  

分布式鎖工廠

  1. public class MdbDistributeLockFactory implements DistributeLockFactory { 
  2.  
  3.     /** 
  4.      * 緩存的命名空間 
  5.      */ 
  6.     @Setter 
  7.     private int namespace; 
  8.  
  9.     @Setter 
  10.     private MultiClusterTairManager mtairManager; 
  11.  
  12.     @Override 
  13.     public DistributeLock getLock(String lockName) { 
  14.         return new MdbDistributeLock(mtairManager, namespace, lockName); 
  15.     } 

 

責任編輯:武曉燕 來源: 51CTO專欄
相關推薦

2023-10-26 07:32:42

2020-09-03 06:33:35

高并發場景分布式鎖

2024-11-27 00:20:32

2021-01-13 11:23:59

分布式冪等性支付

2023-12-26 08:59:52

分布式場景事務機制

2022-03-07 08:14:27

并發分布式

2022-03-11 10:03:40

分布式鎖并發

2024-07-03 11:59:40

2019-06-19 15:40:06

分布式鎖RedisJava

2023-01-13 07:39:07

2025-10-29 01:21:00

2025-07-29 00:49:17

2025-05-07 02:15:00

分布式鎖高并發UUID鎖

2019-10-10 09:16:34

Zookeeper架構分布式

2023-04-03 10:00:00

Redis分布式

2025-07-10 02:00:00

2025-02-14 14:22:40

2024-11-06 12:29:02

2023-03-07 08:19:16

接口冪等性SpringBoot

2025-09-02 07:16:37

點贊
收藏

51CTO技術棧公眾號

中文字幕国产专区| 妞干网在线视频观看| 91丨九色丨蝌蚪丨对白| 自拍偷拍欧美| 国产偷亚洲偷欧美偷精品| 国产情侣av自拍| 顶级网黄在线播放| 99久久久国产精品| 国产精品一久久香蕉国产线看观看| 国产老头老太做爰视频| 高潮按摩久久久久久av免费| 日本精品一区二区三区高清 | 欧美尿孔扩张虐视频| 91国内精品野花午夜精品| 视频一区二区视频| 清纯唯美亚洲色图| 国产精品亚洲人在线观看| 欧洲s码亚洲m码精品一区| 很污很黄的网站| 日韩大胆成人| 日韩一级在线观看| 欧美三级理论片| 九色porny丨入口在线| 丝袜国产在线| 欧美视频官网| 中文字幕精品—区二区| 国产精品嫩草69影院| 美女网站视频一区| 亚洲成人黄色影院| 日本精品免费视频| 国产精品久久一区二区三区不卡| 国产成人在线观看| 国产欧美日韩免费看aⅴ视频| 日韩精品1区2区| 欧美女人交a| 久久影视电视剧免费网站| a级大片在线观看| 欧洲亚洲一区二区三区| 欧美成人一区二区三区片免费| 免费激情视频在线观看| 激情视频网站在线播放色 | 毛片a片免费观看| 久久亚洲国产| 最好看的2019年中文视频| av无码av天天av天天爽| 荡女精品导航| 精品美女一区二区| 色婷婷狠狠18禁久久| 国产成人视屏| 欧美精选一区二区| 黄色在线视频网| 成人看片网站| 91国偷自产一区二区使用方法| 成人在线免费在线观看| 999av小视频在线| 亚洲成人综合在线| 丁香花在线影院观看在线播放| 性欧美猛交videos| 亚洲综合清纯丝袜自拍| 91黄色在线看| 超碰在线视屏| 欧美午夜视频一区二区| 91免费视频网站在线观看| 桃色av一区二区| 色婷婷狠狠综合| 男女爽爽爽视频| 日本成人福利| 欧美人与禽zozo性伦| 污污网站在线观看视频| 国产视频一区二区在线播放| 91精品中文字幕一区二区三区| 999热精品视频| 涩爱av色老久久精品偷偷鲁 | 国产区精品区| 在线观看日韩视频| 欧美风情第一页| 欧美另类专区| 国产91在线视频| 亚洲最大成人在线视频| 国产一区二区在线观看免费| 成人高清在线观看| 日韩av高清在线| 国产精品美日韩| 真人做人试看60分钟免费| 国产网红女主播精品视频| 第一福利永久视频精品| 免费一级特黄录像| 亚洲一二av| 亚洲精品天天看| 999精品视频在线观看播放| 一区视频在线看| 国产经典一区二区| hs视频在线观看| 久久一日本道色综合| 亚洲一区在线直播| 国产h片在线观看| 欧美日韩日日骚| 国产一卡二卡三卡四卡| 成人综合久久| 97热在线精品视频在线观看| 中国女人真人一级毛片| 国产69精品久久777的优势| 欧美另类视频在线| 亚洲国产精品精华素| 色综合视频在线观看| 少妇欧美激情一区二区三区| 欧美欧美黄在线二区| 欧美日本啪啪无遮挡网站| 无码人妻精品一区二区三区蜜桃91 | 午夜在线激情影院| 色综合天天综合在线视频| 免费看的av网站| 精品久久久久久久| 97国产在线视频| 国产青青草视频| 国产日韩欧美在线一区| 欧美精品久久久久久久久久久| 欧美视频第一| 亚洲精品视频久久| 日本一二三区不卡| 国产福利视频一区二区三区| 色一情一区二区三区四区| 69av成人| 日韩久久免费av| 日韩欧美国产成人精品免费| 三级影片在线观看欧美日韩一区二区| 高清国语自产拍免费一区二区三区| 国产九九在线| 欧美性猛交xxxx免费看漫画| 欧美xxxxx少妇| 欧美在线看片| 成人黄色生活片| chinese偷拍一区二区三区| 精品国产乱码久久久久久天美| 国内精品国产三级国产aⅴ久| 日韩精品免费一区二区三区| 国产99久久精品一区二区永久免费| 秋霞欧美在线观看| 一区二区三区免费观看| 亚洲成人手机在线观看| 天天操综合网| 国产在线精品播放| 秋霞午夜理伦电影在线观看| 欧美午夜精品久久久久久久| 91丨porny丨对白| 亚洲第一黄色| 精品久久久久久亚洲| 99热99re6国产在线播放| 精品国产欧美一区二区| 久久视频免费看| 国产成人高清视频| 天天做天天躁天天躁| 精品国产亚洲一区二区在线观看| 日韩在线视频一区| 一区二区日韩视频| 亚洲日本丝袜连裤袜办公室| 思思久久精品视频| 亚洲激情五月| 99精品欧美一区二区三区| 婷婷在线播放| 亚洲高清一二三区| 亚洲国产成人无码av在线| 久久一二三国产| www.99av.com| 亚洲成av人片乱码色午夜| 亚洲va男人天堂| 免费网站在线观看人| 亚洲精品国精品久久99热| 久久人妻免费视频| 欧美国产激情二区三区| 午夜剧场在线免费观看| 91精品高清| 国产精品视频入口| 精品国产免费人成网站| 中文字幕综合一区| a天堂视频在线| 欧美日韩一区免费| 四虎国产成人精品免费一女五男| 黄色资源网久久资源365| 日本一级黄视频| 亚洲电影一级片| 国产欧美精品在线| 免费网站在线观看人| 亚洲欧美一区二区三区四区| 97精品人妻一区二区三区在线| 一区二区三区欧美日| 少妇饥渴放荡91麻豆| 美国十次了思思久久精品导航| 欧美 亚洲 视频| 偷窥自拍亚洲色图精选| 成人国产精品一区| 成人免费观看在线观看| 色悠悠国产精品| 少妇高潮久久久| 欧美日韩美少妇 | 欧美午夜精品久久久久久人妖| 娇小11一12╳yⅹ╳毛片| 成人国产精品视频| 色乱码一区二区三区在线| 激情文学一区| 一区国产精品| 亚洲小说图片视频| 91成人伦理在线电影| 桃花岛成人影院| 欧美国产日韩一区二区| 香蕉视频国产在线观看| 日韩精品免费在线视频观看| 国产精品九九九九| 色婷婷精品大在线视频| 久久精品免费在线| 国产精品白丝在线| 美女又爽又黄视频毛茸茸| 国产一区二区在线观看视频| 狠狠热免费视频| 亚洲另类视频| 中文字幕一区二区三区四区五区人 | 91久久精品国产91久久| 天堂av中文在线观看| 欧美老女人性生活| 午夜在线观看视频| 亚洲欧美制服另类日韩| 色噜噜一区二区三区| 91精品国产综合久久久久久久久久 | 一二三av在线| 免费在线一区观看| 国产成人久久婷婷精品流白浆| 欧美激情1区2区| 亚洲一区二区在线免费观看| 国产精品探花在线观看| 久久精品magnetxturnbtih| 中文一区二区三区四区| 91丝袜美腿美女视频网站| 国产乱子精品一区二区在线观看| 人体精品一二三区| 日本在线影院| 97在线视频免费观看| 国产精品186在线观看在线播放| 久久天天躁狠狠躁夜夜爽蜜月| wwwww在线观看免费视频| 亚洲无线码在线一区观看| 青青青免费视频在线2| 亚洲国产福利在线| 天天干天天色天天| 亚洲精品成a人在线观看| 天堂在线视频免费观看| 亚洲国产成人爱av在线播放| 黄频在线免费观看| 亚洲成人久久网| 日本精品999| 亚洲国产小视频| 青青色在线视频| 国产亚洲欧洲高清| 91在线免费看| 久久精品男人天堂| a篇片在线观看网站| 欧美老女人性生活| 97人人在线视频| 日韩av成人在线| 日本综合视频| 国产日韩精品在线| 国产在线不卡一区二区三区| 亚洲最大福利网| 精品国产一区二区三区成人影院 | 精品一区不卡| 一本久道久久综合| 欧美成人日本| 大j8黑人w巨大888a片| 久久av最新网址| 国产野外作爱视频播放| 国产乱人伦精品一区二区在线观看 | 日本一区二区视频| 欧美激情欧美| 国产传媒久久久| 亚洲免费在线| 亚洲天堂网一区| 国产电影一区二区三区| 久久久久久久久免费看无码 | 日韩精品中文字幕在线| 国产福利免费在线观看| 久久精品成人欧美大片| 国内在线免费视频| 欧美专区国产专区| 国产一区二区色噜噜| www.久久草| 国产欧美日韩免费观看 | 免费看污片的网站| 综合在线观看色| 国产午夜福利一区二区| 色av一区二区| 99久久精品国产一区色| 亚洲精品久久久久| 麻豆免费在线观看| 91国产精品91| 99精品视频在线免费播放| 国产乱码精品一区二区三区日韩精品| 女人av一区| 成人短视频在线观看免费| 久久福利毛片| 欧美老女人bb| 欧美激情一区二区三区不卡| 久久丫精品久久丫| 欧美日韩另类国产亚洲欧美一级| 亚洲精品久久久久久动漫器材一区 | 欧美性猛交xx| 欧美国产日韩精品免费观看| 免费无遮挡无码永久在线观看视频| 色美美综合视频| 囯产精品久久久久久| 中文字幕亚洲综合久久| 国产极品在线观看| 亚洲一区二区三区sesese| 欧美人妖在线| 国产特级淫片高清视频| 激情图片小说一区| 免费视频91蜜桃| 精品美女久久久久久免费| 99视频在线观看免费| 伊人激情综合网| 亚洲人体影院| 精品国产免费人成电影在线观... 精品国产免费久久久久久尖叫 | 精品麻豆av| 欧美日本在线| 伊人国产精品视频| 中文字幕亚洲一区二区va在线| 国产剧情在线视频| 精品一区电影国产| av今日在线| 国产精品一区二区三区在线观| 亚洲一级淫片| 福利视频999| 国产精品日韩成人| 欧美男人天堂网| 亚洲人成网7777777国产| 欧美另类老肥妇| 久久99精品久久久久久青青日本 | 国产真实乱子伦| 91色九色蝌蚪| 日韩精品――中文字幕| 精品久久久久久久人人人人传媒| 成人av福利| 91成人理论电影| 国产精品porn| 国产精品二区视频| 亚洲女子a中天字幕| 一卡二卡三卡在线观看| 久久天堂电影网| 韩国三级大全久久网站| 青少年xxxxx性开放hg| 国内精品免费**视频| 九九热最新地址| 日韩欧美电影在线| 懂色av一区| 国内精品国语自产拍在线观看| 亚洲人www| 青青草成人免费视频| 欧美午夜无遮挡| 最新电影电视剧在线观看免费观看| 国产精品视频一区二区三区四| 日韩亚洲一区在线| 捷克做爰xxxⅹ性视频| 夜夜揉揉日日人人青青一国产精品| av网站免费大全| 欧美交受高潮1| 欧洲vs亚洲vs国产| 一区二区三区韩国| 综合婷婷亚洲小说| 风流少妇一区二区三区91| 欧美一级在线亚洲天堂| 国产中文精品久高清在线不| 在线观看亚洲色图| 一区二区三区成人| 亚洲日本国产精品| 国产精品视频地址| 国产精品vip| 中文字幕被公侵犯的漂亮人妻| 欧美在线免费观看视频| 免费av在线网址| 91九色视频在线观看| 国产日韩1区| 国产黄色片在线| 欧美va在线播放| 另类专区亚洲| 免费看啪啪网站| 91香蕉视频黄| 一级黄色短视频| 午夜精品三级视频福利| 欧洲美女日日| 国产精品偷伦视频免费观看了| 欧美日韩亚洲天堂| 久久亚洲天堂| 蜜桃精品久久久久久久免费影院 | 国产在线观看精品| 99xxxx成人网| 午夜成人亚洲理伦片在线观看| 精品国产污污免费网站入口| 国产v综合v| 五月丁香综合缴情六月小说| 国产精品免费视频网站| 色综合免费视频| 91美女片黄在线观|