亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 數(shù)據(jù)庫 > Redis > 正文

詳解Redis用鏈表實現(xiàn)消息隊列

2020-10-28 21:38:59
字體:
供稿:網(wǎng)友

前言

Redis鏈表經(jīng)常會被用于消息隊列的服務(wù),以完成多程序之間的消息交換。個人認(rèn)為redis消息隊列有一個好處,就是可以實現(xiàn)分布式和共享,就和memcache作為mysql的緩存和mysql自帶的緩存一樣。

鏈表實現(xiàn)消息隊列

Redis鏈表支持前后插入以及前后取出,所以如果往尾部插入元素,往頭部取出元素,這就是一種消息隊列,也可以說是消費者/生產(chǎn)者模型??梢岳胠push和rpop來實現(xiàn)。但是有一個問題,如果鏈表中沒有數(shù)據(jù),那么消費者將要在while循環(huán)中調(diào)用rpop,這樣以來就浪費cpu資源,好在Redis提供一種阻塞版pop命令brpop或者blpop,用法為brpop/blpop list timeout, 當(dāng)鏈表為空的時候,brpop/blpop將阻塞,直到設(shè)置超時時間到或者list插入一個元素。

用法如下:

charles@charles-Aspire-4741:~/mydir/mylib/redis$ ./src/redis-cli127.0.0.1:6379> lpush list hello(integer) 1127.0.0.1:6379> brpop list 01) "list"2) "hello"127.0.0.1:6379> brpop list 0//阻塞在這里/* ---------------------------------------------------- *///當(dāng)我在另一個客戶端lpush一個元素之后,客戶端輸出為127.0.0.1:6379> brpop list 01) "list"2) "world"(50.60s)//阻塞的時間

當(dāng)鏈表為空的時候,brpop是阻塞的,等待超時時間到或者另一個客戶端lpush一個元素。接下來,看下源碼是如何實現(xiàn)阻塞brpop命令的。要實現(xiàn)客戶端阻塞,只需要服務(wù)器不給客戶端發(fā)送消息,那么客戶端就會阻塞在read調(diào)用中,等待消息到達(dá)。這是很好實現(xiàn)的,關(guān)鍵是如何判斷這個客戶端阻塞的鏈表有數(shù)據(jù)到達(dá)以及通知客戶端解除阻塞?Redis的做法是,將阻塞的鍵以及阻塞在這個鍵上的客戶端鏈表存儲在一個字典中,然后每當(dāng)向數(shù)據(jù)庫插入一個鏈表時,就判斷這個新插入的鏈表是否有客戶端阻塞,有的話,就解除這個阻塞的客戶端,并且發(fā)送剛插入鏈表元素給客戶端,客戶端就這樣解除阻塞。

先看下有關(guān)數(shù)據(jù)結(jié)構(gòu),以及server和client有關(guān)屬性

//阻塞狀態(tài)typedef struct blockingState { /* Generic fields. */ mstime_t timeout;  /* 超時時間 */ /* REDIS_BLOCK_LIST */ dict *keys;    /* The keys we are waiting to terminate a blocking        * operation such as BLPOP. Otherwise NULL. */ robj *target;   /* The key that should receive the element,        * for BRPOPLPUSH. */ /* REDIS_BLOCK_WAIT */ int numreplicas;  /* Number of replicas we are waiting for ACK. */ long long reploffset; /* Replication offset to reach. */} blockingState;//繼續(xù)列表typedef struct readyList { redisDb *db;//就緒鍵所在的數(shù)據(jù)庫 robj *key;//就緒鍵} readyList;//客戶端有關(guān)屬性typedef struct redisClient { int btype;    /* Type of blocking op if REDIS_BLOCKED. */ blockingState bpop;  /* blocking state */}//服務(wù)器有關(guān)屬性struct redisServer {  /* Blocked clients */ unsigned int bpop_blocked_clients; /* Number of clients blocked by lists */ list *unblocked_clients; /* list of clients to unblock before next loop */ list *ready_keys;  /* List of readyList structures for BLPOP & co */}//數(shù)據(jù)庫有關(guān)屬性typedef struct redisDb {  //keys->redisCLient映射  dict *blocking_keys;  /* Keys with clients waiting for data (BLPOP) */ dict *ready_keys;   /* Blocked keys that received a PUSH */}redisDB

必須對上述的數(shù)據(jù)結(jié)構(gòu)足夠了解,否則很難看懂下面的代碼,因為這些代碼需要操作上述的數(shù)據(jù)結(jié)構(gòu)。先從brpop命令執(zhí)行函數(shù)開始分析,brpop命令執(zhí)行函數(shù)為

void brpopCommand(redisClient *c) { blockingPopGenericCommand(c,REDIS_TAIL);}//++++++++++++++++++++++++++++++++++++++++++++++++++void blockingPopGenericCommand(redisClient *c, int where) { robj *o; mstime_t timeout; int j; if (getTimeoutFromObjectOrReply(c,c->argv[c->argc-1],&timeout,UNIT_SECONDS)  != REDIS_OK) return;//將超時時間保存在timeout中 for (j = 1; j < c->argc-1; j++) {  o = lookupKeyWrite(c->db,c->argv[j]);//在數(shù)據(jù)庫中查找操作的鏈表  if (o != NULL) {//如果不為空   if (o->type != REDIS_LIST) {//不是鏈表類型    addReply(c,shared.wrongtypeerr);//報錯    return;   } else {    if (listTypeLength(o) != 0) {//鏈表不為空     /* Non empty list, this is like a non normal [LR]POP. */     char *event = (where == REDIS_HEAD) ? "lpop" : "rpop";     robj *value = listTypePop(o,where);//從鏈表中pop出一個元素     redisAssert(value != NULL);     //給客戶端發(fā)送pop出來的元素信息     addReplyMultiBulkLen(c,2);     addReplyBulk(c,c->argv[j]);     addReplyBulk(c,value);     decrRefCount(value);     notifyKeyspaceEvent(REDIS_NOTIFY_LIST,event,          c->argv[j],c->db->id);     if (listTypeLength(o) == 0) {//如果鏈表為空,從數(shù)據(jù)庫刪除鏈表      dbDelete(c->db,c->argv[j]);      notifyKeyspaceEvent(REDIS_NOTIFY_GENERIC,"del",           c->argv[j],c->db->id);     }     /* 省略一部分 */    }   }  } }  /* 如果鏈表為空,則阻塞客戶端 */  blockForKeys(c, c->argv + 1, c->argc - 2, timeout, NULL);}

從源碼可以看出,brpop可以操作多個鏈表變量,例如brpop list1 list2 0,但是只能輸出第一個有元素的鏈表。如果list1沒有元素,而list2有元素,則輸出list2的元素;如果兩個都有元素,則輸出list1的元素;如果都沒有元素,則等待其中某個鏈表插入一個元素,之后在2返回。最后調(diào)用blockForyKeys阻塞

void blockForKeys(redisClient *c, robj **keys, int numkeys, mstime_t timeout, robj *target) { dictEntry *de; list *l; int j; c->bpop.timeout = timeout;//超時時間賦值給客戶端blockingState屬性 c->bpop.target = target;//這屬性適用于brpoplpush命令的輸入對象,如果是brpop, //則target為空 if (target != NULL) incrRefCount(target);//不為空,增加引用計數(shù) for (j = 0; j < numkeys; j++) {  /* 將阻塞的key存入c.bpop.keys字典中 */  if (dictAdd(c->bpop.keys,keys[j],NULL) != DICT_OK) continue;  incrRefCount(keys[j]);  /* And in the other "side", to map keys -> clients */  //將阻塞的key和客戶端添加進(jìn)c->db->blocking_keys  de = dictFind(c->db->blocking_keys,keys[j]);  if (de == NULL) {   int retval;   /* For every key we take a list of clients blocked for it */   l = listCreate();   retval = dictAdd(c->db->blocking_keys,keys[j],l);   incrRefCount(keys[j]);   redisAssertWithInfo(c,keys[j],retval == DICT_OK);  } else {   l = dictGetVal(de);  }  listAddNodeTail(l,c);//添加到阻塞鍵的客戶點鏈表中 } blockClient(c,REDIS_BLOCKED_LIST);//設(shè)置客戶端阻塞標(biāo)志}

blockClient函數(shù)只是簡單的設(shè)置客戶端屬性,如下

void blockClient(redisClient *c, int btype) { c->flags |= REDIS_BLOCKED;//設(shè)置標(biāo)志 c->btype = btype;//阻塞操作類型 server.bpop_blocked_clients++;}

由于這個函數(shù)之后,brpop命令執(zhí)行函數(shù)就結(jié)束了,由于沒有給客戶端發(fā)送消息,所以客戶端就阻塞在read調(diào)用中。那么如何解開客戶端的阻塞了?

插入一個元素解阻塞

任何指令的執(zhí)行函數(shù)都是在processCommand函數(shù)中調(diào)用call函數(shù),然后在call函數(shù)中調(diào)用命令執(zhí)行函數(shù),lpush也一樣。當(dāng)執(zhí)行完lpush之后,此時鏈表不為空,回到processCommand調(diào)用中,執(zhí)行以下語句

if (listLength(server.ready_keys))   handleClientsBlockedOnLists();

這兩行代碼是先檢查server.ready_keys是否為空,如果不為空,說明已經(jīng)有一些就緒的鏈表,此時可以判斷是否有客戶端阻塞在這個鍵值上,如果有,則喚醒;現(xiàn)在問題又來了,這個server.ready_keys在哪更新鏈表了?

原來是在dbAdd函數(shù)中,當(dāng)往數(shù)據(jù)庫中添加的值類型為REDIS-LIST時,這時就要調(diào)用signalListAsReady函數(shù)將鏈表指針添加進(jìn)server.ready_keys:

//db.cvoid dbAdd(redisDb *db, robj *key, robj *val) { sds copy = sdsdup(key->ptr); int retval = dictAdd(db->dict, copy, val);//將數(shù)據(jù)添加進(jìn)數(shù)據(jù)庫 redisAssertWithInfo(NULL,key,retval == REDIS_OK); //判斷是否為鏈表類型,如果是,調(diào)用有鏈表已經(jīng)ready函數(shù) if (val->type == REDIS_LIST) signalListAsReady(db, key); if (server.cluster_enabled) slotToKeyAdd(key); }//t_list.cvoid signalListAsReady(redisDb *db, robj *key) { readyList *rl; /* 沒有客戶端阻塞在這個鍵上,則直接返回. */ if (dictFind(db->blocking_keys,key) == NULL) return; /* 這個鍵已近被喚醒了,所以沒必要重新入隊 */ if (dictFind(db->ready_keys,key) != NULL) return; /* Ok, 除了上述兩情況,把這個鍵放入server.ready_keys */ rl = zmalloc(sizeof(*rl)); rl->key = key; rl->db = db; incrRefCount(key); listAddNodeTail(server.ready_keys,rl);//添加鏈表末尾 /* We also add the key in the db->ready_keys dictionary in order  * to avoid adding it multiple times into a list with a simple O(1)  * check. */ incrRefCount(key); //同時將這個阻塞鍵放入db->ready_keys redisAssert(dictAdd(db->ready_keys,key,NULL) == DICT_OK);}

OK,這時server.ready_keys上已經(jīng)有就緒鍵了,這時就調(diào)用processCommand函數(shù)中的handleClientsBlockedOnLists()函數(shù)來處理阻塞客戶端,在這個函數(shù)中,

void handleClientsBlockedOnLists(void) { while(listLength(server.ready_keys) != 0) {  list *l;  /* 將server.ready_keys賦給一個新的list,再將server.ready_keys清空 */  l = server.ready_keys;  server.ready_keys = listCreate();  /* 迭代每一個就緒的每一個readyList */  while(listLength(l) != 0) {   listNode *ln = listFirst(l);//獲取第一個就緒readyList   readyList *rl = ln->value;   /* 從rl所屬的數(shù)據(jù)庫中刪除rl */   dictDelete(rl->db->ready_keys,rl->key);   /* 查詢rl所屬的數(shù)據(jù)庫查找rl->key ,給阻塞客戶端回復(fù)rl->key鏈表中的第一個元素*/   robj *o = lookupKeyWrite(rl->db,rl->key);   if (o != NULL && o->type == REDIS_LIST) {    dictEntry *de;    /* 在rl->db->blocking_keys查找阻塞在rl->key的客戶端鏈表 */    de = dictFind(rl->db->blocking_keys,rl->key);    if (de) {     list *clients = dictGetVal(de);//轉(zhuǎn)換為客戶端鏈表     int numclients = listLength(clients);     while(numclients--) {//給每個客戶端發(fā)送消息      listNode *clientnode = listFirst(clients);      redisClient *receiver = clientnode->value;//阻塞的客戶端      robj *dstkey = receiver->bpop.target;//brpoplpush命令目的鏈表      int where = (receiver->lastcmd &&          receiver->lastcmd->proc == blpopCommand) ?         REDIS_HEAD : REDIS_TAIL;//獲取取出的方向      robj *value = listTypePop(o,where);//取出就緒鏈表的元素      if (value) {       /* Protect receiver->bpop.target, that will be        * freed by the next unblockClient()        * call. */       if (dstkey) incrRefCount(dstkey);       unblockClient(receiver);//設(shè)置客戶端為非阻塞狀態(tài)       if (serveClientBlockedOnList(receiver,        rl->key,dstkey,rl->db,value,        where) == REDIS_ERR)       {        /* If we failed serving the client we need         * to also undo the POP operation. */         listTypePush(o,value,where);       }//給客戶端回復(fù)鏈表中的元素內(nèi)容       if (dstkey) decrRefCount(dstkey);       decrRefCount(value);      } else {       break;      }     }    }    //如果鏈表為空,則從數(shù)據(jù)庫中刪除    if (listTypeLength(o) == 0) dbDelete(rl->db,rl->key);    /* We don't call signalModifiedKey() as it was already called     * when an element was pushed on the list. */   }   /* 回收rl */   decrRefCount(rl->key);   zfree(rl);   listDelNode(l,ln);  }  listRelease(l); /* We have the new list on place at this point. */ }}

從這個源碼可知,如果有兩個客戶端,同時阻塞在一個鏈表上面,那么如果鏈表插入一個元素之后,只有先阻塞的那個客戶端收到消息,后面阻塞的那個客戶端繼續(xù)阻塞,這也是先阻塞先服務(wù)的思想。handleClientsBlockedOnLists函數(shù)調(diào)用了unblockClient(receiver) ,該函數(shù)功能為接觸客戶端阻塞標(biāo)志,以及找到db阻塞在key上的客戶端鏈表,并將接觸阻塞的客戶端從鏈表刪除。然后調(diào)用serveClientBlockOnList給客戶端回復(fù)剛在鏈表插入的元素。

int serveClientBlockedOnList(redisClient *receiver, robj *key, robj *dstkey, redisDb *db, robj *value, int where){ robj *argv[3]; if (dstkey == NULL) {  /* Propagate the [LR]POP operation. */  argv[0] = (where == REDIS_HEAD) ? shared.lpop :           shared.rpop;  argv[1] = key;  propagate((where == REDIS_HEAD) ?   server.lpopCommand : server.rpopCommand,   db->id,argv,2,REDIS_PROPAGATE_AOF|REDIS_PROPAGATE_REPL);  /* BRPOP/BLPOP */  addReplyMultiBulkLen(receiver,2);  addReplyBulk(receiver,key);  addReplyBulk(receiver,value); } else {  /* BRPOPLPUSH */   /* 省略 */ }}

propagate函數(shù)主要是將命令信息發(fā)送給aof和slave。函數(shù)中省略部分是brpoplpush list list1 0命令的目的鏈表list1非空時,將從list鏈表pop出來的元素插入list1中。當(dāng)給客戶端發(fā)送消息之后,客戶端就從read函數(shù)調(diào)用中返回,變?yōu)椴蛔枞?/p>

通過超時時間解阻塞

如果鏈表一直沒有數(shù)據(jù)插入,那么客戶端將會一直阻塞下去,這肯定是不行的,所以brpop還支持超時阻塞,即阻塞時間超過一定值之后,服務(wù)器返回一個空值,這樣客戶端就解脫阻塞了。

對于時間超時,都放在了100ms執(zhí)行一次的時間事件中;超時解脫阻塞函數(shù)也在serverCron中;在serverCron->clientsCron->clientsCronHandleTimeout

int clientsCronHandleTimeout(redisClient *c, mstime_t now_ms) { time_t now = now_ms/1000; //.......... else if (c->flags & REDIS_BLOCKED) {  /* Blocked OPS timeout is handled with milliseconds resolution.   * However note that the actual resolution is limited by   * server.hz. */  if (c->bpop.timeout != 0 && c->bpop.timeout < now_ms) {   /* Handle blocking operation specific timeout. */   replyToBlockedClientTimedOut(c);   unblockClient(c);  } } //.............

把這個函數(shù)不相干的代碼刪除,主要部分先判斷這個客戶端是否阻塞,如果是,超時時間是否到期,如果是,則調(diào)用replyToBlockedClientTimedOut給客戶端回復(fù)一個空回復(fù),以及接觸客戶端阻塞。

總結(jié)

鏈表消息隊列實現(xiàn)暫時分析到這了,大家都學(xué)會了嗎?希望這篇文章給大家能帶來一定的幫助,如果有疑問可以留言交流。

發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
日韩福利视频导航| 99久久er热在这里只有精品15| 国产精品va在线播放我和闺蜜| 国产无遮挡aaa片爽爽| 伊人青青综合网| 韩日精品一区二区| 色综合视频二区偷拍在线| 99精品视频在线| 91一区二区三区在线观看| 国产日韩亚洲| 福利欧美精品在线| 伊人av在线com| 成人好色电影| 欧美大黑帍在线播放| 久久综合伊人77777尤物| 日韩免费观看视频| 欧美韩日亚洲| 天天射综合网视频| 国产精品视频一| 国产精品888| 欧美性xxxxxxxx| 日韩久久精品电影| 在线一区二区三区精品| 经典三级一区二区| 性爽视频在线| 精品国模一区二区三区| 日韩中字在线观看| 欧美一级片在线免费观看| 一本色道久久综合亚洲精品婷婷| 日韩精品视频网址| 欧美另类videos黑人极品| 手机av在线网| 91中文字幕网| 鲁鲁视频www一区二区| 午夜电影久久久| 99精品视频免费观看视频| 免费一级全黄少妇性色生活片| 欧美日韩国产一区二区三区| 最新中文字幕在线观看| 精品av久久久久电影| 亚洲精品午夜国产va久久成人| 亚洲无玛一区| 国产精品一区二区欧美黑人喷潮水| 麻豆精品新av中文字幕| 日韩av高清在线播放| 99xxxx成人网| caoporn国产精品免费公开| 国产精品av一区| 一区二区三区网站| 久久精品国产99| 国产日韩亚洲欧美在线| 国产一级一级片| 国产精品影视在线| 婷婷中文字幕综合| 国产成人午夜| 5566中文字幕一区二区电影| 午夜精品美女自拍福到在线| 91女人18毛片水多国产| 日本精品性网站在线观看| 亚洲成年人网站在线观看| 色婷婷久久一区二区| 中文字幕综合在线观看| 香蕉久久99| 国产精品卡一卡二卡三| 免费成人性网站| 日韩中文字幕免费看| segui88久久综合9999| 欧美精品黄色| 国产精品久久中文| 三级黄色的网站| 日韩在线中文视频| 亚洲欧美成人网| 情趣视频在线观看| 欧美精品一区二区三区很污很色的| 成年人精品视频| 日韩精品专区在线影院重磅| 国产精品亚洲成在人线| 男人的天堂网av| 激情内射人妻1区2区3区| 91在线第一页| 亚洲av成人无码久久精品老人| 97人人在线视频| 国产主播在线资源| 国产剧情在线观看| 在线国产伦理一区| **欧美日韩vr在线| 色悠久久久久综合欧美99| 免费人成网站在线观看欧美高清| 男人的天堂avav| 亚洲第一在线| 国精产品一区一区三区免费视频| 大地资源网3页在线观看| 香蕉久久精品| 欧美一级视频一区二区| 最近免费中文字幕中文高清百度| 成人黄色在线电影| 欧美成年人视频| 国产欧美一二三区| 四虎影视18库在线影院| 九色91视频| 无码人妻精品一区二区蜜桃色欲| 欧美极度另类性三渗透| 国产精品剧情一区二区在线观看| 91精品婷婷国产综合久久性色| 中文字幕在线中文字幕二区| caoporn-草棚在线视频最| 中文字幕久久亚洲| 日本久久天堂| 国产极品视频| 电影一区二区| 欧美一区二区精品| 91视频福利网| 99热com| 日韩视频在线观看一区二区| 人人九九精品| 成熟了的熟妇毛茸茸| 国产精品初高中精品久久| 色涩成人影视在线播放| 午夜精品久久久久久久爽| 日韩一级免费视频| 精品国产一区二区亚洲人成毛片| 精品精品国产高清一毛片一天堂| 日韩经典中文字幕在线观看| 亚洲先锋成人| 69久久夜色精品国产69| 精品高清在线| 一区二区三区在线电影| 日本高清好狼色视频| 91啪九色porn原创视频在线观看| 久久网这里都是精品| 欧美日韩国产999| 欧美这里只有精品| 欧美色偷偷大香| 制服.丝袜.亚洲.中文.综合懂| 久久久久久激情| 色欲av永久无码精品无码蜜桃| 一本色道久久综合亚洲精品不卡| 欧美精品18videos性欧| 性欧美最新另类| 狠狠色狠狠色综合系列| jizz视频| 极品白嫩的小少妇| 欧美日韩成人一区二区三区| 亚洲美女区一区| 亚洲成人免费视频| 精品深夜av无码一区二区老年| 欧美一a一片一级一片| 中文在线官网天堂| 97精品国产97久久久久久| 狠狠干夜夜草| 久久精品国内一区二区三区水蜜桃| 中文字幕av专区| 日本一区二区三区精品| 6699嫩草久久久精品影院| 桥本有菜av在线| 在线欧美日韩精品| 九七影院理伦片| 久久裸体网站| 国产精品无码一区二区三区| 韩日视频在线| 国产精品推荐精品| 3344国产永久在线观看视频| 精品一区二区三区中文字幕视频| 国产精品情侣呻吟对白视频| 中文字幕4区| 污视频网站在线观看| 国产精品自拍毛片| 欧美在线观看成人| 国产精品区一区二区三含羞草| 影音先锋中文字幕在线播放| 99久久er热在这里只有精品15| 91免费视频观看| 日韩欧美精品网站| 免费网站成人| 国产巨乳在线观看| 66视频精品| 中文精品在线| 在线观看国产原创自拍视频| 日韩av三级在线观看| 超碰国产精品久久国产精品99| av大片免费看| 欧美日韩精品免费观看视欧美高清免费大片| 日韩av网站在线观看| 日产精品久久久久| 欧美日韩电影在线观看| 国产丝袜在线观看视频| 亚洲精品成a人ⅴ香蕉片| 性生生活大片免费看视频| 亚洲精品乱码久久久久久动漫| 日本欧美色图| 少妇被躁爽到高潮无码文| 亚洲在线激情| 亚洲精品tv久久久久久久久| 欧美va亚洲va在线观看蝴蝶网| 最近更新的2019中文字幕| 日韩动漫在线观看| 色综合视频二区偷拍在线| 亚洲第一精品久久忘忧草社区| av地址在线观看| 影音先锋男人在线资源| 国产三级精品在线不卡| 日本24小时在线高清视频| 色爱综合av| 亚洲AV无码成人精品区东京热| 国产精品偷伦视频免费观看国产| 色中色综合影院手机版在线观看| 欧美精品黑人猛交高潮| 亚洲最大成人综合| 亚洲电影成人av99爱色| 91影院在线免费观看| 蜜桃视频久久一区免费观看入口| 成人亲热视频网站| 久久综合狠狠综合久久综合88| 777色狠狠一区二区三区| 一区二区高清视频在线观看| 久久综合综合久久综合| 免费h片在线| 免费搞黄视频| 国产黄视频在线| 国产麻豆综合| 色狠狠久久av五月综合| 三级网站在线播放| 色婷婷精品久久二区二区蜜臀av| 黄色av免费在线观看| thepron国产精品| 久久精品一偷一偷国产| 正在播放亚洲| 欧美三级日韩三级国产三级| 亚洲成a人片综合在线| 中文字幕久久综合| 国产乱码精品一区二三赶尸艳谈| 丰满人妻av一区二区三区| 亚洲视频网在线直播| 午夜私人影院久久久久| 国产人成网在线播放va免费| 中文字幕97| 无遮挡h肉3d动漫在线观看| 欧美片第1页综合| 免费视频一区| 翔田千里一区二在线观看| 爽爽淫人综合网网站| 中国xxxx自拍视频| 99久久免费看精品国产一区| 亚洲一区二区在线播放相泽| 女人被狂躁c到高潮| 激情无码人妻又粗又大| www 久久久| 欧美黑人一区二区三区| 大黑人xxx| 国产在线一区不卡| 午夜在线视频观看日韩17c| 国产日韩在线不卡| 国产精品探花一区二区在线观看| 97精品国产91久久久久久| 熟女少妇一区二区三区| bl视频在线免费观看| 久久综合九色综合久久久精品综合| 国产精品麻豆免费版现看视频| 日本久久精品电影| 三年片观看免费观看大全视频下载| 色噜噜狠狠狠综合曰曰曰| 青青热久免费精品视频在线18| 大乳在线免费观看| 美乳视频一区二区| 中文字幕亚洲图片| 偷拍视频一区二区三区| 日韩精品在线观看一区| 丰满的护士2在线观看高清| 欧美亚洲日本在线观看| 亚洲春色一区二区三区| 久久黄色精品视频| 美女黄色片网站| 亚洲最新合集| 亚洲欧美日韩在线不卡| 青青青草原在线| 黄色网址大全在线观看| 日韩高清在线一区二区| 久久亚洲AV成人无码国产野外| 一区在线中文字幕| 黄色网页在线播放| 在线观看免费视频一区| 97超碰在线资源站| 曰本一区二区三区视频| 欧美丰满少妇xxxx| 久久久国产精华液999999| 色综合天天综合给合国产| 亚洲经典一区二区三区| 五月天国产在线| 51精品久久久久久久蜜臀| 日韩伦理电影网站| 亚洲黄色小说视频| 欧美**vk| 国产小视频在线| 欧美69精品久久久久久不卡| 午夜亚洲伦理| 国模大尺度视频| 国产福利小视频| 亚洲砖区区免费| 成人综合电影| 日日夜夜免费精品视频| 青青草免费在线视频| 日韩中文字幕区一区有砖一区| 秋霞综合在线视频| 亚洲天堂中文字幕在线| 激情亚洲影院在线观看| 神马午夜在线视频| 欧美1区免费| 婷婷伊人综合中文字幕| 国产亚洲小视频| 丁香亚洲综合激情啪啪综合| 国产乱码精品一区二区三区五月婷| 国产精品一区二区午夜嘿嘿嘿小说| 国产成人免费视频精品含羞草妖精| 国产日韩欧美第一页| 亚洲成人av免费看| 亚洲最大在线| 亚洲精品国产a| 久久成人免费电影| 亚洲色图日韩av| 亚洲污视频在线观看| 超碰在线免费97| 国产日韩av高清| 欧美日本不卡| 亚洲永久在线| 亚洲自拍欧美另类| 国产一区在线不卡| 国产日韩欧美视频| 欧美撒尿777hd撒尿|