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

Redis+Node.js實現一個能處理海量數據的異步任務隊列系統

開發 前端 其他數據庫 Redis
本文通過探索 Redis + NodeJS 結合的方式,構造出了一個異步任務隊列處理系統,能較好地完成最初方案的設想,但依然有很多問題需要改進。

 在最近的業務中,接到了一個需要處理約十萬條數據的需求。這些數據都以字符串的形式給到,并且處理它們的步驟是異步且耗時的(平均處理一條數據需要 25s 的時間)。如果以串行的方式實現,其耗時是相當長的:

總耗時時間 = 數據量 × 單條數據處理時間

T = N * t (N = 100,000; t = 25s)

總耗時時間 = 2,500,000 秒 ≈ 695 小時 ≈ 29 天

顯然,我們不能簡單地把數據一條一條地處理。那么有沒有辦法能夠減少處理的時間呢?經過調研后發現,使用異步任務隊列是個不錯的辦法。

一、異步任務隊列原理

我們可以把“處理單條數據”理解為一個異步任務,因此對這十萬條數據的處理,就可以轉化成有十萬個異步任務等待進行。我們可以把這十萬條數據塞到一個隊列里面,讓任務處理器自發地從隊列里面去取得并完成。

任務處理器可以有多個,它們同時從隊列里面把任務取走并處理。當任務隊列為空,表示所有任務已經被認領完;當所有任務處理器完成任務,則表示所有任務已經被處理完。

其基本原理如下圖所示:

首先來解決任務隊列的問題。在這個需求中,任務隊列里面的每一個任務,都包含了待處理的數據,數據以字符串的形式存在。為了方便起見,我們可以使用 Redis 的 List 數據格式來存放這些任務。

由于項目是基于 NodeJS 的,我們可以利用 PM2 的 Cluster 模式來啟動多個任務處理器,并行地處理任務。以一個 8 核的 CPU 為例,如果完全開啟了多進程,其理論處理時間將提升 8 倍,從 29 天縮短到 3.6 天。

接下來,我們會從實際編碼的角度來講解上述內容的實現過程。

二、使用 NodeJS 操作 Redis

異步任務隊列使用 Redis 來實現,因此我們需要部署一個單獨的 Redis 服務。在本地開發中為了快速完成 Redis 的安裝,我使用了 Docker 的辦法(默認機器已經安裝了 Docker)。

Docker 拉取 Redis 鏡像   

  1. docker pull redis:latest 

Docker 啟動 Redis   

  1. docker run -itd --name redis-local-p 6379:6379 redis 

此時我們已經使用 Docker 啟動了一個 Redis 服務,其對外的 IP 及端口為 127.0.0.1:6379。此外,我們還可以在本地安裝一個名為 Another Redis DeskTop Manager的 Redis 可視化工具,來實時查看、修改 Redis 的內容。

在 NodeJS 中,我們可以使用 node-redis 來操作 Redis。新建一個 mqclient.ts 文件并寫入如下內容: 

  1. import* asRedisfrom'redis'  
  2. const client = Redis.createClient({  
  3.   host: '127.0.0.1',  
  4.   port: 6379  
  5. })  
  6. exportdefault client 

Redis 本質上是一個數據庫,而我們對數據庫的操作無非就是增刪改查。node-redis 支持 Redis 的所有交互操作方式,但是操作結果默認是以回調函數的形式返回。為了能夠使用 async/await,我們可以新建一個 utils.ts 文件,把 node-redis 操作 Redis 的各種操作都封裝成 Promise 的形式,方便我們后續使用。   

  1. import client from'./mqClient'  
  2.    // 獲取 Redis 中某個 key 的內容  
  3.    exportconst getRedisValue = (key: string): Promise<string| null> => newPromise(resolve => client.get(key, (err, reply) => resolve(reply)))  
  4.    // 設置 Redis 中某個 key 的內容  
  5.    exportconst setRedisValue = (key: string, value: string) => newPromise(resolve => client.set(key, value, resolve))  
  6.    // 刪除 Redis 中某個 key 及其內容  
  7.    exportconst delRedisKey = (key: string) => newPromise(resolve => client.del(key, resolve)) 

除此之外,還能在 utils.ts 中放置其他常用的工具方法,以實現代碼的復用、保證代碼的整潔。

為了在 Redis 中創建任務隊列,我們可以單獨寫一個 createTasks.ts 的腳本,用于往隊列中塞入自定義的任務。 

  1. import{ TASK_NAME, TASK_AMOUNT, setRedisValue, delRedisKey } from'./utils'  
  2.   import client from'./mqClient'  
  3.   client.on('ready', async() => {  
  4.   await delRedisKey(TASK_NAME)  
  5.   for(let i = TASK_AMOUNT; i > 0; i--) {  
  6.       client.lpush(TASK_NAME, `task-${i}`)  
  7.   }  
  8.     client.lrange(TASK_NAME, 0, TASK_AMOUNT, async(err, reply) => {  
  9.   if(err) {  
  10.         console.error(err)  
  11.   return  
  12.   }  
  13.       console.log(reply)  
  14.       process.exit()  
  15.   })  
  16.   }) 

在這段腳本中,我們從 utils.ts 中獲取了各個 Redis 操作的方法,以及任務的名稱 TASKNAME (此處為 localtasks)和任務的總數 TASKAMOUNT(此處為 20 個)。通過 LPUSH 方法往 TASKNAME 的 List 當中塞入內容為 task-1 到 task-20 的任務,如圖所示:

三、異步任務處理

首先新建一個 index.ts 文件,作為整個異步任務隊列處理系統的入口文件。   

  1. import taskHandler from'./tasksHandler'  
  2.    import client from'./mqClient'  
  3.    client.on('connect', () => {  
  4.      console.log('Redis is connected!')  
  5.    })  
  6.    client.on('ready', async() => {  
  7.      console.log('Redis is ready!')  
  8.    await taskHandler()  
  9.    })  
  10.    client.on('error', (e) => {  
  11.      console.log('Redis error! '+ e)  
  12.    }) 

在運行該文件時,會自動連接 Redis,并且在 ready 狀態時執行任務處理器 taskHandler()。

在上一節的操作中,我們往任務隊列里面添加了 20 個任務,每個任務都是形如 task-n 的字符串。為了驗證異步任務的實現,我們可以在任務處理器 taskHandler.ts 中寫一段 demo 函數,來模擬真正的異步任務: 

  1. function handleTask(task: string) {  
  2.  returnnewPromise((resolve) => {  
  3.        setTimeout(async() => {  
  4.          console.log(`Handling task: ${task}...`)  
  5.          resolve()  
  6.  }, 2000)  
  7.  })  
  8.  } 

上面這個 handleTask() 函數,將會在執行的 2 秒后打印出當前任務的內容,并返回一個 Promise,很好地模擬了異步函數的實現方式。接下來我們將會圍繞這個函數,來處理隊列中的任務。

其實到了這一步為止,整個異步任務隊列處理系統已經基本完成了,只需要在 taskHandler.ts 中補充一點點代碼即可:   

  1. import{ popTask } from'./utils'  
  2.     import client from'./mqClient'  
  3.     function handleTask(task: string) { /* ... */}  
  4.     exportdefaultasyncfunction tasksHandler() {  
  5.     // 從隊列中取出一個任務  
  6.     const task = await popTask()  
  7.     // 處理任務  
  8.     await handleTask(task)  
  9.     // 遞歸運行  
  10.     await tasksHandler()  
  11.     } 

最后,我們使用 PM2 啟動 4 個進程,來試著跑一下整個項目:   

  1. pm2 start ./dist/index.js -i 4&& pm2 logs 

可以看到,4 個任務處理器分別處理完了隊列中的所有任務,相互之前互不影響。

事到如今已經大功告成了嗎?未必。為了測試我們的這套系統到底提升了多少的效率,還需要統計完成隊列里面所有任務的總耗時。

四、統計任務完成耗時

要統計任務完成的耗時,只需要實現下列的公式即可:

總耗時 = 最后一個任務的完成時間 - 首個任務被取得的時間

首先來解決“獲取首個任務被取得的時間”這個問題。

由于我們是通過 PM2 的 Cluster 模式來啟動應用的,且從 Redis 隊列中讀取任務是個異步操作,因此在多進程運行的情況下無法直接保證從隊列中讀取任務的先后順序,必須通過一個額外的標記來判斷。其原理如下圖:

如圖所示,綠色的 worker 由于無法保證運行的先后順序,所以編號用問號來表示。當第一個任務被取得時,把黃色的標記值從 false 設置成 true。當且僅當黃色的標記值為 false 時才會設置時間。這樣一來,當其他任務被取得時,由于黃色的標記值已經是 true 了,因此無法設置時間,所以我們便能得到首個任務被取得的時間。

在本文的例子中,黃色的標記值和首個任務被取得的時間也被存放在 Redis 中,分別被命名為 localtasksSETFIRST 和 localtasksBEGINTIME。

原理已經弄懂,但是在實踐中還有一個地方值得注意。我們知道,從 Redis 中讀寫數據也是一個異步操作。由于我們有多個 worker 但只有一個 Redis,那么在讀取黃色標記值的時候很可能會出現“沖突”的問題。舉個例子,當 worker-1 修改標記值為 true 的同時, worker-2 正好在讀取標記值。由于時間的關系,可能 worker-2 讀到的標記值依然是 false,那么這就沖突了。為了解決這個問題,我們可以使用 node-redlock 這個工具來實現“鎖”的操作。

顧名思義,“鎖”的操作可以理解為當 worker-1 讀取并修改標記值的時候,不允許其他 worker 讀取該值,也就是把標記值給鎖住了。當 worker-1 完成標記值的修改時會釋放鎖,此時才允許其他的 worker 去讀取該標記值。

node-redlock 是 Redis 分布式鎖 Redlock 算法的 JavaScript 實現,關于該算法的講解可參考 https://redis.io/topics/distlock。值得注意的是,在 node-redlock 在使用的過程中,如果要鎖一個已存在的 key,就必須為該 key 添加一個前綴 locks:,否則會報錯。

回到 utils.ts,編寫一個 setBeginTime() 的工具函數: 

  1. exportconst setBeginTime = async(redlock: Redlock) => {  
  2.  // 讀取標記值前先把它鎖住  
  3.  constlockawait redlock.lock(`lock:${TASK_NAME}_SET_FIRST`, 1000)  
  4.  const setFirst = await getRedisValue(`${TASK_NAME}_SET_FIRST`)  
  5.  // 當且僅當標記值不等于 true 時,才設置起始時間  
  6.  if(setFirst !== 'true') {  
  7.      console.log(`${pm2tips} Get the first task!`)  
  8.  await setRedisValue(`${TASK_NAME}_SET_FIRST`, 'true')  
  9.  await setRedisValue(`${TASK_NAME}_BEGIN_TIME`, `${new Date().getTime()}`)  
  10.  }  
  11.  // 完成標記值的讀寫操作后,釋放鎖  
  12.  awaitlock.unlock().catch(e => e)  
  13.  } 

然后把它添加到 taskHandler() 函數里面即可: 

  1. exportdefaultasyncfunction tasksHandler() {  
  2.   +  // 獲取第一個任務被取得的時間  
  3.   +  await setBeginTime(redlock)  
  4.   // 從隊列中取出一個任務  
  5.   const task = await popTask()  
  6.   // 處理任務  
  7.   await handleTask(task)  
  8.   // 遞歸運行  
  9.   await tasksHandler()  
  10.   } 

接下來解決“最后一個任務的完成時間”這個問題。

類似上一個問題,由于任務執行的先后順序無法保證,異步操作的完成時間也無法保證,因此我們也需要一個額外的標識來記錄任務的完成情況。在 Redis 中創建一個初始值為 0 的標識 localtasksCURINDEX,當 worker 完成一個任務就讓標識加。由于任務隊列的初始長度是已知的(為 TASKAMOUNT 常量,也寫入了 Redis 的 localtasksTOTAL 中),因此當標識的值等于隊列初始長度的值時,即可表明所有任務都已經完成。

如圖所示,被完成的任務都會讓黃色的標識加一,任何時候只要判斷到標識的值等于隊列的初始長度值,即可表明任務已經全部完成。

回到 taskHandler() 函數,加入下列內容:   

  1. exportdefaultasyncfunction tasksHandler() {  
  2.    +  // 獲取標識值和隊列初始長度  
  3.    +  let curIndex = Number(await getRedisValue(`${TASK_NAME}_CUR_INDEX`))  
  4.    +  const taskAmount = Number(await getRedisValue(`${TASK_NAME}_TOTAL`))  
  5.    +  // 等待新任務  
  6.    +  if(taskAmount === 0) {  
  7.    +    console.log(`${pm2tips} Wating new tasks...`)  
  8.    +    await sleep(2000)  
  9.    +    await tasksHandler()  
  10.    +    return  
  11.    +  }  
  12.    +  // 判斷所有任務已經完成  
  13.    +  if(curIndex === taskAmount) {  
  14.    +    const beginTime = await getRedisValue(`${TASK_NAME}_BEGIN_TIME`)  
  15.    +    // 獲取總耗時  
  16.    +    const cost = newDate().getTime() - Number(beginTime)  
  17.    +    console.log(`${pm2tips} All tasks were completed! Time cost: ${cost}ms. ${beginTime}`)  
  18.    +    // 初始化 Redis 的一些標識值  
  19.    +    await setRedisValue(`${TASK_NAME}_TOTAL`, '0')  
  20.    +    await setRedisValue(`${TASK_NAME}_CUR_INDEX`, '0')  
  21.    +    await setRedisValue(`${TASK_NAME}_SET_FIRST`, 'false')  
  22.    +    await delRedisKey(`${TASK_NAME}_BEGIN_TIME`)  
  23.    +    await sleep(2000)  
  24.    +    await tasksHandler()  
  25.    }  
  26.    // 獲取第一個任務被取得的時間  
  27.    await setBeginTime(redlock)  
  28.    // 從隊列中取出一個任務  
  29.    const task = await popTask()  
  30.    // 處理任務  
  31.    await handleTask(task)  
  32.    + // 任務完成后需要為標識位加一  
  33.    +  try{  
  34.    +    constlockawait redlock.lock(`lock:${TASK_NAME}_CUR_INDEX`, 1000)  
  35.    +    curIndex = await getCurIndex()  
  36.    +    await setCurIndex(curIndex + 1)  
  37.    +    awaitlock.unlock().catch((e) => e)  
  38.    +  } catch(e) {  
  39.    +    console.log(e)  
  40.    +  }  
  41.    +  // recursion  
  42.    +  await tasksHandler()  
  43.    +}  
  44.    // 遞歸運行  
  45.    await tasksHandler()  
  46.    } 

到這一步為止,我們已經解決了獲取“最后一個任務的完成時間”的問題,再結合前面的首個任務被取得的時間,便能得出運行的總耗時。

最后來看一下實際的運行效果。我們循例往隊列里面添加了 task-1 到 task-20 這 20 個任務,然后啟動 4 個進程來跑:

運行狀況良好。從運行結果來看,4 個進程處理 20 個平均耗時 2 秒的任務,只需要 10 秒的時間,完全符合設想。

五、小結

當面對海量的異步任務需要處理的時候,多進程 + 任務隊列的方式是一個不錯的解決方式。本文通過探索 Redis + NodeJS 結合的方式,構造出了一個異步任務隊列處理系統,能較好地完成最初方案的設想,但依然有很多問題需要改進。比如說當任務出錯了應該怎么辦,系統能否支持不同類型的任務,能否運行多個隊列等等,都是值得思考的問題。 

 

責任編輯:龐桂玉 來源: 前端教程
相關推薦

2011-10-25 09:28:30

Node.js

2023-03-01 09:39:40

調度系統

2020-08-07 10:40:56

Node.jsexpress前端

2022-01-05 12:09:16

異步隊列集群

2021-12-25 22:29:57

Node.js 微任務處理事件循環

2013-03-18 10:31:22

JS異常

2025-06-27 10:41:04

Redis數據庫集群

2021-09-07 07:53:43

工具

2024-03-15 15:20:10

并發服務IP

2022-09-21 12:01:22

消息隊列任務隊列任務調度

2010-12-01 14:34:59

AsyncTask異步處理任務Android

2011-06-01 10:59:59

Oceanbase海量數據庫

2025-07-11 08:09:07

Node.jsAPI權限

2021-04-06 10:15:29

Node.jsHooks前端

2025-01-13 00:00:00

2011-12-23 13:58:57

node.js

2024-12-09 09:25:30

2012-06-26 10:03:06

海量數據處理

2022-04-25 15:01:07

系統程序員調度

2023-09-16 18:16:57

Python系統
點贊
收藏

51CTO技術棧公眾號

激情综合激情五月| 国产一区二区三区高清播放| 成人福利视频在线看| 亚洲人成电影在线观看天堂色| 91丨九色丨国产在线| aa片在线观看视频在线播放| 亚洲区欧洲区| 久久中文亚洲字幕| 色综合欧美在线| 国产精品久久久久久免费观看| 欧美人妻一区二区三区| 欧美aa在线观看| 成人性生交大片免费看视频在线| 另类美女黄大片| 亚洲性图一区二区| 久蕉依人在线视频| 午夜在线精品偷拍| 日韩成人免费视频| 欧美牲交a欧美牲交| 亚洲h视频在线观看| 久久久久美女| 7777精品伊人久久久大香线蕉的| 婷婷四月色综合| 人妻中文字幕一区二区三区| 九一亚洲精品| 欧美午夜视频在线观看| 麻豆成人在线播放| 一级免费在线观看| 思热99re视热频这里只精品| 婷婷六月综合亚洲| 九9re精品视频在线观看re6| 国产精品xxxx喷水欧美| 911精品美国片911久久久| 日韩精品日韩在线观看| 韩国三级在线看| 国产美女一区视频| 波多野结衣一区二区三区 | 精品欧美一区二区久久久伦| 国产又黄又猛又爽| 亚洲欧美网站在线观看| 欧美一区二区私人影院日本| 妞干网这里只有精品| 国产人妖在线播放| 在线欧美福利| 精品爽片免费看久久| 日本三级免费观看| 午夜在线视频| 国产精品996| 26uuu亚洲国产精品| 99久久久无码国产精品衣服| 另类在线视频| 欧美日韩在线精品一区二区三区激情 | 强开小嫩苞一区二区三区网站| 97最新国自产拍视频在线完整在线看| 精品亚洲porn| 午夜精品一区二区三区在线视| 国产交换配乱淫视频免费| 成人免费一区| 亚洲一区国产视频| 日本欧美色综合网站免费| 亚洲综合精品视频| 日韩午夜免费| 日韩在线资源网| 精品人妻在线视频| 精品福利一区| 亚洲嫩模很污视频| 网站在线你懂的| 91色在线看| 国产精品乱码一区二三区小蝌蚪| 成人av资源网| 亚洲图片小说视频| 国产真实乱子伦精品视频| 亚洲a成v人在线观看| 亚洲成人第一网站| 欧美精品自拍| 日韩在线高清视频| 免费成人深夜夜行p站| 三级精品视频| 在线精品国产成人综合| 97超碰免费在线观看| 国产高清中文字幕在线| 最新日韩av在线| 欧美精品久久久| 狠狠综合久久av一区二区| 蜜桃一区二区三区在线观看| 97精品国产97久久久久久春色| 国产成人无码精品亚洲| 日本va欧美va欧美va精品| 91国产精品电影| 欧美毛片在线观看| 99久久99热这里只有精品| 日韩精品免费电影| 99国产精品无码| 精品国产一区二区三区香蕉沈先生| 欧美不卡一区二区三区四区| caoporm在线视频| 高清日韩中文字幕| 69堂亚洲精品首页| 黄色网址在线视频| 成人福利一区| 精品国产1区二区| 免费看三级黄色片| 国产成人ay| 国产视频自拍一区| 秋霞欧美一区二区三区视频免费| 欧美日韩一区二区综合| 久久国产加勒比精品无码| 国产白丝一区二区三区 | 91丨porny丨首页| 国产伦精品一区| 91精彩在线视频| 欧美日韩免费在线观看| 日韩中文字幕在线视频观看| 国产黄色一区| 亚洲一级一级97网| 99精品全国免费观看| 日本大胆欧美| 精品国产一区二区三区久久狼黑人 | www.久久色| 国产剧情在线观看一区二区| 91精品视频免费观看| 飘雪影视在线观看免费观看| 久久久精品日韩欧美| 国产高清在线一区| 天天射,天天干| 91亚洲精华国产精华精华液| 久久精品国产一区二区三区日韩| 日本成人一区二区三区| 亚洲在线免费播放| 一区二区传媒有限公司| 日本免费一区二区三区视频| 欧美videos大乳护士334| 国产一区二区三区视频播放| 欧美资源在线| 国产日韩精品在线| 国产日韩一级片| 亚洲国产精品t66y| 天天综合五月天| jizz久久久久久| 夜夜嗨av色综合久久久综合网 | 在线日本成人| 成人激情直播| 国产丝袜精品丝袜| 欧美不卡在线视频| 国产亚洲自拍av| 性色一区二区| 久久青青草原| 亚洲性色av| 欧美午夜影院一区| 最好看的中文字幕| 欧美一区二区三区免费看| 97色在线观看| 污污视频在线观看网站| 国产精品传媒视频| 你真棒插曲来救救我在线观看| 小黄鸭精品aⅴ导航网站入口| 欧美日韩综合在线| jizz18女人高潮| 久久er99热精品一区二区| 成人欧美一区二区| 黄色小说在线播放| 亚洲国产高潮在线观看| jizz日本在线播放| 99精品国产在热久久| 国产综合精品一区二区三区| 日本在线www| 欧美高清视频在线高清观看mv色露露十八| 国产精品19p| 亚洲高清成人| 欧洲国产精品| 9999精品视频| 夜夜嗨av色一区二区不卡| 欧美男人天堂网| 亚洲天堂福利av| 女性女同性aⅴ免费观女性恋| 4438五月综合| 久久99精品久久久久久噜噜| 无码人妻久久一区二区三区不卡| 国产福利一区在线观看| 免费不卡av在线| 精品国产一区探花在线观看| 国产主播精品在线| 波多野结衣中文字幕久久| 亚洲男人7777| 99产精品成人啪免费网站| 黄网站色欧美视频| 国产3级在线观看| 丁香婷婷深情五月亚洲| 久久久久久香蕉| 日本一道高清一区二区三区| 精品视频9999| 免费成人av电影| 欧美午夜影院在线视频| 貂蝉被到爽流白浆在线观看 | 成人av网站观看| 久久精品女人天堂av免费观看| 久久亚洲精品小早川怜子66| 亚洲欧美日韩免费| 56国语精品自产拍在线观看| 久草视频在线观| 不卡的av网站| 一区二区三区国产免费| 蜜桃成人av| 91久久精品一区二区别| 亚洲综合伊人久久大杳蕉| 欧美日韩国产综合一区二区 | 6080国产精品| 色88久久久久高潮综合影院| 国产精品视频内| 国产乱子伦三级在线播放| 91黄色免费观看| 精品无码国产污污污免费网站| 久久电影一区| 久久福利一区二区| jizz18欧美18| 成人高h视频在线| 韩国av网站在线| 日韩欧美国产午夜精品| 久久婷婷综合国产| 国产精品沙发午睡系列990531| 亚洲精品女人久久久| 国产福利精品一区二区| 成人亚洲视频在线观看| 三区四区不卡| 欧美日本韩国一区二区三区| 国产精品黄网站| 成人一区二区三区四区| 国产视频网站一区二区三区| 欧美国产在线视频| 午夜视频福利在线观看| 日韩一区二区在线看| 国产无套在线观看| 久久久久久麻豆| 中国免费黄色片| 久久精品亚洲一区二区| 六月婷婷在线视频| 亚洲第一网站| r级无码视频在线观看| 欧美日韩亚洲三区| 永久免费网站视频在线观看| 美女主播精品视频一二三四| 97在线资源站| 一区二区免费| 国产精品久久中文| 色8久久影院午夜场| xxx一区二区| 国内精品久久久久久野外| 色香阁99久久精品久久久| yiren22亚洲综合伊人22| 欧美一区二区三区免费大片 | 国产精品九九九九九九| 不卡高清视频专区| 久久久久亚洲无码| av不卡免费在线观看| 午夜两性免费视频| 国内视频精品| 亚洲第一导航| 成功精品影院| 久久久久久欧美精品色一二三四| 国产男人搡女人免费视频| 1024视频在线| 一区二区日韩精品| 里番在线观看网站| 精品奇米国产一区二区三区| 亚洲成人av综合| 亚洲精品mp4| 一级成人免费视频| 欧美精品久久久久久久多人混战 | 欧美日韩在线播放三区四区| 亚洲天堂2021av| 日韩欧美一区中文| 天堂中文在线资源| 国产亚洲一区精品| 麻豆传媒视频在线观看免费| 欧美俄罗斯乱妇| 91精品论坛| 欧美日韩不卡合集视频| 婷婷在线播放| 青草热久免费精品视频| 污视频在线看网站| 97在线看免费观看视频在线观看| 桃花岛成人影院| 亚洲一区二区在线| 日韩高清成人在线| 一本久久a久久精品vr综合| 欧美日韩导航| 亚洲在线欧美| 亚洲精品乱码| 亚洲中文字幕无码一区二区三区| 亚洲国内欧美| 亚洲最大天堂网| 日本vs亚洲vs韩国一区三区二区 | 欧美高清hd| 国产精品自拍视频| 456成人影院在线观看| 日韩免费观看视频| 神马午夜在线视频| 国产区精品视频| 日韩精品丝袜美腿| 警花观音坐莲激情销魂小说| 国产视频一区三区| 奇米影视亚洲色图| 久久久久亚洲| 国产91xxx| 国产在线视频精品一区| 中文字幕一二三四区| 99久久国产综合精品女不卡| 日韩一级片在线免费观看| 亚洲成人福利片| 中国一级片在线观看| 日韩美女视频19| 精品人妻一区二区色欲产成人| 日韩一区二区三区在线观看| 国产精品天堂| 777精品视频| a级日韩大片| 黄色一级大片免费| 精品无人区卡一卡二卡三乱码免费卡| 自拍偷拍中文字幕| 亚洲成人动漫av| 国产 日韩 欧美 精品| 日韩一区二区欧美| 成人在线中文| 日韩经典在线视频| 91久久国产| 538在线视频观看| 久久久久青草大香线综合精品| 男人的天堂久久久| 亚洲影视资源网| 国产精品无码久久av| 中文字幕免费精品一区| 精精国产xxxx视频在线| 国产精品久久久久9999| 91麻豆精品国产91久久久更新资源速度超快| 久久一区二区三区av| 91久久夜色精品国产九色| 成年人看片网站| 亚洲一区二区精品3399| 国产不卡精品视频| 日韩精品极品视频| 国产污视频在线播放| 国产精品免费一区二区三区在线观看 | 亚洲一区二区三区免费看| 视频一区二区三区中文字幕| 自拍偷拍21p| 中文字幕 久热精品 视频在线| 成年人视频免费| 日韩一区二区中文字幕| 毛片在线视频| 91九色露脸| 在线欧美三区| 超碰97人人干| 欧美在线看片a免费观看| 成人性爱视频在线观看| 国产精品久久久久久久久久东京| 欧美在线观看视频一区| 日本中文字幕二区| 亚洲丝袜另类动漫二区| 精品国产av鲁一鲁一区| 久久男人资源视频| 深夜日韩欧美| 欧美日韩精品免费在线观看视频| 午夜亚洲福利在线老司机| xxxxx在线观看| 欧美日韩国产a| 羞羞视频在线观看不卡| 国产欧美欧洲| 日韩国产精品久久久| 中文字幕人妻一区二区三区| 国产片一区二区| 久久久久国产精品夜夜夜夜夜| 亚洲成成品网站| 日韩电影免费观看高清完整版| 亚洲电影一二三区| 国产精品一区二区在线观看网站| 久久精品视频9| 亚洲欧美国产另类| 日本精品久久| 亚洲熟妇国产熟妇肥婆| 国产欧美精品一区二区色综合| 国产口爆吞精一区二区| 久久久久久久一| 日韩精品一区国产| 人妻熟妇乱又伦精品视频| 国产精品美女视频| 成人免费视频国产| 国产精品久久电影观看| 欧美人成在线| 国产又大又粗又爽的毛片| 日韩一区二区三区在线观看| 欧美xoxoxo| 国产午夜精品视频一区二区三区| 久久综合久久鬼色中文字| 国产精品第56页| 中文字幕亚洲欧美一区二区三区| heyzo欧美激情| 国产福利精品一区二区三区| 亚洲国产欧美另类丝袜| 天堂地址在线www| 韩国精品一区二区三区六区色诱|