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

來聊聊 Redis 集群數據遷移

數據庫 Redis 開發
本文將是筆者對于Redis源碼分析的一個階段的最后一篇,將從源碼分析的角度讓讀者深入了解redis節點遷移的工作流程,希望對你有幫助。

一、詳解redis cluster數據遷移過程

1. 節點基本結構定義

redis集群提供16384個slot,我們可以按需分配給節點上,后續進行鍵值對存儲時,我們就可以按照算法將鍵值對存到對應slot上的redis服務器上:

集群節點本質就是通過slots這個數組記錄當前節點的所管理的情況,這里我們可以看到slots是一個char 數組,長度為REDIS_CLUSTER_SLOTS(16384)除8,這樣做的原因是因為:

  • char占1個字節,每個字節8位。
  • 每個char可以記錄8個slot的情況,如果是自己的slot則對應char的某一個位置記錄為1:

我們以node-1為例,因為它負責0-5460的節點,所以它的slots0-5460都為1,對應的圖解如下所示,可以看到筆者這里省略了后半部分,僅僅表示了0-15位置為1:

對此我們也給出這段redis中節點的定義,即位于cluster.h中的clusterNode這個結構體中,可以看slots這段定義:

typedef struct clusterNode {
  //......
    //記錄集群負責的槽,總的為16384
    unsigned char slots[REDIS_CLUSTER_SLOTS/8]; 
    //......
}

2. 設置slot后續節點遷移

以本文示例為例,我們希望后續節點2的數據全部存到節點1中,那么我們首先需要鍵入如下兩條配置:

# 在節點1上執行,將節點2數據導入到節點1上
 CLUSTER SETSLOT 3 IMPORTING node2
 # 在節點2上執行,將自己的數據遷移到節點1
 CLUSTER SETSLOT 3 MIGRATING node1

這兩條指最終都會被各自的服務端解析,并調用clusterCommand執行,我們以節點1導入為例,假設我們執行clusterCommand解析到setslot 關鍵字和importing關鍵字,即知曉要導入其他節點的數據。對應的節點1就會通過importing_slots_from數組標記自己將導入這個slot的數據,而節點2也會通過migrating_slots_to數組標記自己要將數據導出給其他節點的slot:

對此我們給出clusterCommand的執行流程,可以看到該函數解析出migrating或者importing關鍵字時就會將對的migrating_slots_to或者importing_slots_from數組對應slot位置的索引位置設置為當前上述命令傳入的node id:

void clusterCommand(redisClient *c) {
     //......

        if (!strcasecmp(c->argv[3]->ptr,"migrating") && c->argc == 5) {//處理遷出的邏輯
            //看看自己是否有遷出的slot,沒有則報錯
            if (server.cluster->slots[slot] != myself) {
                addReplyErrorFormat(c,"I'm not the owner of hash slot %u",slot);
                return;
            }
            //查看自己是否知曉這個node id,如果沒有則報錯
            if ((n = clusterLookupNode(c->argv[4]->ptr)) == NULL) {
                addReplyErrorFormat(c,"I don't know about node %s",
                    (char*)c->argv[4]->ptr);
                return;
            }
            //標記遷出到slot為傳入的node
            server.cluster->migrating_slots_to[slot] = n;
        } else if (!strcasecmp(c->argv[3]->ptr,"importing") && c->argc == 5) {//處理遷入的邏輯
            //查看遷入的slot是否已經配置,如果有則報錯
            if (server.cluster->slots[slot] == myself) {
                addReplyErrorFormat(c,
                    "I'm already the owner of hash slot %u",slot);
                return;
            }
            //查看自己是否知曉要遷入數據的node的信息,如果不知道則報錯
            if ((n = clusterLookupNode(c->argv[4]->ptr)) == NULL) {
                addReplyErrorFormat(c,"I don't know about node %s",
                    (char*)c->argv[3]->ptr);
                return;
            }
            //標記遷入slot位置為傳入的nodeid
            server.cluster->importing_slots_from[slot] = n;
        } //......
}

3. 請求重定向問題

后續的我們假設還是將set key value請求發送到節點2,因為上述命令的原因,節點會返回move/ask告知客戶端這個鍵值對現在要存到節點1上。對應節點1收到這個key請求時,通過key計算得slot正是自己,它就會將這個鍵值對存儲到自己的數據庫中:

這里我們以節點1的角度查看這個問題,當客戶端收到move指令后,繼續向節點1發送指令,節點1通過收到指令調用processCommand,其內部調用getNodeByQuery獲取當前key對應的slot,發現是自己則直接存儲數據到當前節點的內存數據庫中:

int processCommand(redisClient *c) {
    //......
    //如果開啟了集群模式,且發送者不是master且參數帶key則進入邏輯
    if (server.cluster_enabled &&
        !(c->flags & REDIS_MASTER) &&
        !(c->flags & REDIS_LUA_CLIENT &&
          server.lua_caller->flags & REDIS_MASTER) &&
        !(c->cmd->getkeys_proc == NULL && c->cmd->firstkey == 0))
    {
        int hashslot;

        if (server.cluster->state != REDIS_CLUSTER_OK) {
           //......
        } else {
            int error_code;
            //查找鍵值對對應的slot和這個slot負責的節點
            clusterNode *n = getNodeByQuery(c,c->cmd,c->argv,c->argc,&hashslot,&error_code);
            //如果為空且或者非自己,則轉交出去給別人處理
            if (n == NULL || n != server.cluster->myself) {
                flagTransaction(c);
                clusterRedirectClient(c,n,hashslot,error_code);
                return REDIS_OK;
            }
        }
    }
 //......
 //將鍵值對存儲到當前數據庫中
}

我們以節點的視角再次直接步入getNodeByQuery查看這段邏輯,可以看到其內部會基于key計算slot然后將得到對應的node,然后進行如下判斷:

  • 如果本次客戶端請求是一個批量的請求,且第一個key定位不到響應的slot,直接返回錯誤。
  • 如果key的slot屬于當前節點,且當前節點正在遷出并且當前節點查不到這個key,則響應一個ask標識告知客戶端到遷出的節點詢問一下是否有數據。
  • 如果是key屬于當前節點且正在進行導入,且key定位不到則響應異常,反之說明當前節點導入成功,直接返回當前節點信息。
  • 如果定位到的slot屬于別的節點,則響應一個move告知客戶端到別的節點獲取鍵值對。

對應的我們給出這段代碼函數getNodeByQuery,對應的邏輯和筆者上述給出的核心分支一致:

clusterNode *getNodeByQuery(redisClient *c, struct redisCommand *cmd, robj **argv, int argc, int *hashslot, int *error_code) {
   //.......

   
    //如果是exec命令則用mstate封裝這些命令
    if (cmd->proc == execCommand) {
        /* If REDIS_MULTI flag is not set EXEC is just going to return an
         * error. */
        if (!(c->flags & REDIS_MULTI)) return myself;
        ms = &c->mstate;
    } else {
        //為了一個原子指向,創建一個假的multi記錄這些指令
        ms = &_ms;
        _ms.commands = &mc;
        //命令個數1
        _ms.count = 1;
        //命令參數
        mc.argv = argv;
        //命令參數個數
        mc.argc = argc;
        //對應的命令
        mc.cmd = cmd;
    }

    
    //遍歷命令
    for (i = 0; i < ms->count; i++) {
      //.......
        //解析出key以及個數
        keyindex = getKeysFromCommand(mcmd,margv,margc,&numkeys);
        for (j = 0; j < numkeys; j++) {
            //拿到key
            robj *thiskey = margv[keyindex[j]];
            //計算slot
            int thisslot = keyHashSlot((char*)thiskey->ptr,
                                       sdslen(thiskey->ptr));
   
            if (firstkey == NULL) {
              
                firstkey = thiskey;
                slot = thisslot;
                //拿著slot找到對應的集群節點
                n = server.cluster->slots[slot];

                //如果當前查詢的key是第一個key且找不到,則將錯誤碼設置為REDIS_CLUSTER_REDIR_DOWN_UNBOUND并返回空
                if (n == NULL) {
                    getKeysFreeResult(keyindex);
                    if (error_code)
                        *error_code = REDIS_CLUSTER_REDIR_DOWN_UNBOUND;
                    return NULL;
                }

                //如果就是當前節點正在做遷出或者遷入,則migrating_slot/importing_slot設置為1
                if (n == myself &&
                    server.cluster->migrating_slots_to[slot] != NULL)
                {
                    migrating_slot = 1;
                } else if (server.cluster->importing_slots_from[slot] != NULL) {
                    importing_slot = 1;
                }
            } else {
             //.......
            }

         
            //如果正在做遷出或者嵌入找不到當前db找不到key的位置,則missing_keys++
            if ((migrating_slot || importing_slot) &&
                lookupKeyRead(&server.db[0],thiskey) == NULL)
            {
                missing_keys++;
            }
        }
        getKeysFreeResult(keyindex);
    }

   
    //所有key都沒有對應slot節點,直接返回當前節點
    if (n == NULL) return myself;

  //.......
    //正在遷出且key找不到位置,錯誤碼設置為ask并返回遷出的目標節點,讓客戶端到別的節點嘗試看看
    if (migrating_slot && missing_keys) {
        if (error_code) *error_code = REDIS_CLUSTER_REDIR_ASK;
        return server.cluster->migrating_slots_to[slot];
    }

 //如果是節點正在導入且key找不到則返回,標識當前集群不穩定
    if (importing_slot &&
        (c->flags & REDIS_ASKING || cmd->flags & REDIS_CMD_ASKING))
    {
        if (multiple_keys && missing_keys) {
            if (error_code) *error_code = REDIS_CLUSTER_REDIR_UNSTABLE;
            return NULL;
        } else {
         //反之說明導入成功則告知自己可以找到這個鍵值對
            return myself;
        }
    }

  //......
    //返回其他節點,error_code設置為move
    if (n != myself && error_code) *error_code = REDIS_CLUSTER_REDIR_MOVED;
    return n;
}

4. 完成節點遷移

上述操作僅僅針對新節點的告知要處理的新的slot,對于舊的節點的舊有slot數據我們就需要通過節點2鍵入CLUSTER GETKEYSINSLOT slot count要遷移的舊的key的slot,然后通過MIGRATE host port key dbid timeout [COPY | REPLACE]將數據遷移到節點1上。 這里我們補充一下MIGRATE 中copy和replace的區別,前者是遇到重復直接報錯,后者是遷移時直接覆蓋。 最終這條指令回基于要遷移的key而生成一條RESTORE-ASKING key ttl serialized-value [REPLACE] [ABSTTL] [IDLETIME seconds] [FREQ frequency]指令發送給導入的節點,以本文例子來說就是節點1:

這里我們給出MIGRATE 指令對應的處理函數migrateCommand,邏輯和我上文說的差不多,基于指令解析出replace或者copy等信息,然后用argv[3]即我們的key得出這個鍵值對的信息生成RESTORE指令將鍵值對轉存給節點1:

/* 命令 MIGRATE host port key dbid timeout [COPY | REPLACE] */
void migrateCommand(redisClient *c) {
   
    //......
    //解析拷貝和替代選項,前者重復會報錯
    for (j = 6; j < c->argc; j++) {
        if (!strcasecmp(c->argv[j]->ptr,"copy")) {
            copy = 1;
        } else if (!strcasecmp(c->argv[j]->ptr,"replace")) {
            replace = 1;
        } else {
            addReply(c,shared.syntaxerr);
            return;
        }
    }

  //......
    //查看要遷移的key是否存在嗎,如果不存則直接報錯返回
    if ((o = lookupKeyRead(c->db,c->argv[3])) == NULL) {
        addReplySds(c,sdsnew("+NOKEY\r\n"));
        return;
    }

    /* Connect */
    //建立socket連接
    cs = migrateGetSocket(c,c->argv[1],c->argv[2],timeout);
    //......

    //cmd初始化一個buf緩沖區
    rioInitWithBuffer(&cmd,sdsempty());

    /* Send the SELECT command if the current DB is not already selected. */
    //如果尚未選擇當前DB,則發送SELECT命令。
    int select = cs->last_dbid != dbid; /* Should we emit SELECT? */
    if (select) {
        redisAssertWithInfo(c,NULL,rioWriteBulkCount(&cmd,'*',2));
        redisAssertWithInfo(c,NULL,rioWriteBulkString(&cmd,"SELECT",6));
        redisAssertWithInfo(c,NULL,rioWriteBulkLongLong(&cmd,dbid));
    }

    /* Create RESTORE payload and generate the protocol to call the command. */
    //獲取key的過期時效
    expireat = getExpire(c->db,c->argv[3]);
    if (expireat != -1) {
        ttl = expireat-mstime();
        if (ttl < 1) ttl = 1;
    }
 
    //集群用RESTORE-ASKING發送key給目標
    if (server.cluster_enabled)
        redisAssertWithInfo(c,NULL,
            rioWriteBulkString(&cmd,"RESTORE-ASKING",14));
    else
        redisAssertWithInfo(c,NULL,rioWriteBulkString(&cmd,"RESTORE",7));
   //填充key和value ttl等
    redisAssertWithInfo(c,NULL,sdsEncodedObject(c->argv[3]));
    redisAssertWithInfo(c,NULL,rioWriteBulkString(&cmd,c->argv[3]->ptr,
            sdslen(c->argv[3]->ptr)));
    redisAssertWithInfo(c,NULL,rioWriteBulkLongLong(&cmd,ttl));

   //......
    //遷移指令字符串寫入緩沖區
    redisAssertWithInfo(c,NULL,rioWriteBulkString(&cmd,payload.io.buffer.ptr,
                                sdslen(payload.io.buffer.ptr)));
   //......
    //如果是replace發出 REPLACE
    if (replace)
        redisAssertWithInfo(c,NULL,rioWriteBulkString(&cmd,"REPLACE",7));

  

 //......
}

5. 最后調整

最后我們只需在節點1和2都執行CLUSTER SETSLOT <SLOT> NODE <NODE ID> 完成slot指派,這指令最終就會走到clusterCommand中,節點1和節點2各自的處理邏輯為:

  • 節點2看看遷移的key的數量未0且migrating_slots_to數據不為空,若符合要求,則說明本次遷移完成但狀態未修改,直接將migrating_slots_to置空完成指派最后調整。
  • 節點1查看節點id是否是自己,且importing_slots_from是否有數據,若有則說明節點導入完成,直接將importing_slots_from置空。
void clusterCommand(redisClient *c) {
    //......
     else if (!strcasecmp(c->argv[1]->ptr,"setslot") && c->argc >= 4) {//處理setslot指令
          //......
   else if (!strcasecmp(c->argv[3]->ptr,"node") && c->argc == 5) {
            /* CLUSTER SETSLOT <SLOT> NODE <NODE ID> 標記最終遷移的節點 */
            clusterNode *n = clusterLookupNode(c->argv[4]->ptr);

           //......
            //如果發現對應的key為0,且migrating_slots_to不為空,則說明遷出完成但狀態還未修改,節點2會將migrating_slots_to設置為空
            if (countKeysInSlot(slot) == 0 &&
                server.cluster->migrating_slots_to[slot])
                server.cluster->migrating_slots_to[slot] = NULL;

           //如果是節點1則會看指令的nodeid是否是自己且importing_slots_from是否有數據,若有則說明導入成功直接將importing_slots_from設置為空
            if (n == myself &&
                server.cluster->importing_slots_from[slot])
            {
              //......
                server.cluster->importing_slots_from[slot] = NULL;
            }
           
        }
  //......
}

二、小結

自此我們將redis集群中的所有核心設計都分析完成,我們來簡單小結一下整體過程:

  • 通過CLUSTER IMPORTING/MIGRATING 進行slot遷入或遷出,redis服務端通過一個數組維護遷入和遷出的slot的信息。
  • 后續客戶端發起請求獲取對應的slot的信息時,會通過上述兩個數組獲知節點遷移情況已做出結果響應。
  • 通過步驟1能夠告知對應的slot的新數據的存儲指向,對于舊數據我們還是需要通過指令完成遷移,其本質就是服務端定位到對應slot上的key然后生成RESP規范的協議指令通知到遷移的節點上。
  • 以遷出節點為例,看到自己對應slot的key為0且遷出數組非空,則說明遷出完成。

由此完成一次集群的遷移。

責任編輯:趙寧寧 來源: 寫代碼的SharkChili
相關推薦

2024-11-04 15:49:43

Redis?數據遷移

2025-03-03 10:25:10

2022-02-06 21:14:57

Redis命令

2022-02-09 15:36:49

Redis主從模式哨兵模式

2020-04-21 22:59:50

Redis搭建選舉

2024-09-11 20:05:56

2025-02-17 11:07:10

2022-08-28 19:36:15

數據分片KafkaRocketMQ

2024-02-04 09:00:00

向量查詢數據檢索MyScale

2024-02-21 08:19:54

2021-06-26 07:40:45

Greenplum集群部署

2018-02-02 16:15:02

Hadoop數據遷移集群

2022-05-09 07:35:48

動態集群限流

2024-01-15 16:51:03

Redis數據存儲

2022-03-03 09:51:11

RedisCouchbase數據存儲

2020-04-09 11:56:10

Elasticsear集群硬件

2023-02-01 13:22:00

數據庫表連接SQL

2021-01-26 07:11:26

Redis數據同步數據遷移

2020-09-24 06:49:34

PythonRedis

2025-07-09 07:30:00

點贊
收藏

51CTO技術棧公眾號

国产精品一区二区黑丝| 国产精品极品在线观看| 中文欧美字幕免费| 3d精品h动漫啪啪一区二区| 九九视频免费在线观看| 久久91麻豆精品一区| 欧美精品成人一区二区三区四区| 800av在线免费观看| 国产永久av在线| 国产老妇另类xxxxx| 欧美有码在线观看| 国产这里有精品| 国产亚洲第一伦理第一区| 欧美一二三区在线观看| 青青在线免费观看视频| 暖暖在线中文免费日本| 欧美韩国日本一区| 国产免费一区| 国产精品无码久久av| 久久国产精品亚洲77777| 美国十次了思思久久精品导航 | 国产美女高潮在线观看| 国产精品美女一区二区在线观看| 国产精品一区二区免费| 夜夜嗨aⅴ一区二区三区| 国产欧美二区| 蜜臀久久99精品久久久久久宅男| 中文字幕第4页| 久9re热视频这里只有精品| 91精品蜜臀在线一区尤物| 国产午夜福利视频在线观看| 黑人极品ⅴideos精品欧美棵| 国产精品理伦片| 欧美一级爱爱| 欧美日本韩国一区二区| 99精品久久免费看蜜臀剧情介绍 | 色狠狠久久av综合| 日韩精品一区二区三区四区视频 | 亚洲无限av看| 免费a v网站| 99re91这里只有精品| 欧美精品一二三四| 亚洲免费一级视频| 992tv国产精品成人影院| 色综合天天天天做夜夜夜夜做| 91精品国产91久久久久麻豆 主演| v片在线观看| 亚洲日本乱码在线观看| 影音欧美亚洲| 国产三区在线观看| 亚洲色图制服诱惑| 青青草综合视频| 青青青国内视频在线观看软件| 亚洲六月丁香色婷婷综合久久| 伊人狠狠色丁香综合尤物| 在线观看免费黄色| 成人免费在线播放视频| 亚洲第一精品区| 国产精品久久麻豆| 亚洲黄色小说网站| 亚洲精品久久在线| 日韩国产欧美一区| 成人影视在线播放| 国产精品免费人成网站| 亚洲日本精品国产第一区| 8888四色奇米在线观看| 成人免费一区二区三区在线观看| 在线观看一区欧美| 视频在线这里都是精品| 亚洲福利国产精品| 日本熟妇人妻xxxxx| 国产一区二区主播在线| 欧美乱妇一区二区三区不卡视频| www.亚洲自拍| 国产精东传媒成人av电影| 亚洲国产精品高清久久久| mm131美女视频| 日韩理论片av| 欧美丰满老妇厨房牲生活| 日韩精品乱码久久久久久| 天堂久久久久va久久久久| 国产精品欧美日韩一区二区| 国产日本精品视频| 97久久超碰国产精品| 天堂资源在线亚洲视频| av在线免费网址| 福利视频导航一区| 制服丝袜中文字幕第一页| 我要色综合中文字幕| 亚洲精品国精品久久99热一| 99精品全国免费观看| 欧美久色视频| 国产成人综合亚洲| 成人1区2区3区| 久久综合九色综合97_久久久| 亚洲亚洲精品三区日韩精品在线视频| aa在线视频| 日韩欧美极品在线观看| 激情文学亚洲色图| 亚洲另类春色校园小说| 久久影院资源网| 久久久午夜影院| 韩国女主播成人在线观看| 开心色怡人综合网站| 成人高清免费在线| 欧美性xxxxx极品娇小| 性久久久久久久久久久久久久| 加勒比久久高清| 国产一区二区三区久久精品 | 亚洲一区二区在线免费看| 国产精品欧美激情在线观看| 精品一区二区三区中文字幕| 亚洲人成电影网站色| 国产在线免费视频| 激情五月播播久久久精品| 欧美精品国产精品久久久| 懂色av一区| 在线播放欧美女士性生活| 在线免费观看成年人视频| 亚洲草久电影| 国产精品人成电影在线观看| 亚洲人妻一区二区三区| 一区二区三区四区亚洲| 在线观看国产中文字幕| 九九亚洲精品| 2019亚洲日韩新视频| 亚洲国产精品欧美久久| √…a在线天堂一区| caopor在线视频| 久久av国产紧身裤| 欧美极品美女电影一区| www日本在线| 亚洲欧美视频在线观看视频| 国产高潮免费视频| 欧美艳星介绍134位艳星| 欧美一区亚洲一区| 日韩在线无毛| 色综合久久综合| 五级黄高潮片90分钟视频| 在线亚洲欧美| 久久精品丝袜高跟鞋| 理论片午夜视频在线观看| 精品美女一区二区三区| 免费在线视频观看| 国产成人午夜高潮毛片| 少妇一晚三次一区二区三区| 蜜桃精品视频| 欧美国产激情18| 亚洲乱色熟女一区二区三区| 一区二区三区精品视频| 香蕉视频1024| 影音先锋久久资源网| 国产日韩一区欧美| 咪咪网在线视频| 亚洲男人天堂久| 国产主播第一页| 欧美激情一区不卡| 色综合色综合色综合色综合| 日韩久久综合| 亚洲自拍偷拍一区| 牛牛精品视频在线| 亚洲精品按摩视频| 亚洲精品久久久久久久蜜桃| 亚洲国产精品ⅴa在线观看| 九九九在线观看视频| 99久久99热这里只有精品| 亚洲va电影大全| 国产黄色大片在线观看| 日韩精品视频观看| 亚洲国产av一区二区三区| 国产精品视频一二三区| 欧美高清精品一区二区| 亚洲经典三级| 日韩欧美激情一区二区| 亚洲国产一区二区久久| 欧美日韩999| 奇米影视888狠狠狠777不卡| 欧美日韩一区二区三区四区五区| 免费国产羞羞网站美图| 99久久精品免费看国产| 日本一极黄色片| 在线电影一区二区| 免费日韩av电影| 中文成人在线| 136fldh精品导航福利| 成人在线高清视频| 日韩免费视频一区二区| 久久精品久久久久久久| 亚洲激情一二三区| 青青草视频成人| 国产精品一区二区在线看| 日韩欧美一区三区| 午夜精品毛片| 免费日韩电影在线观看| 欧美欧美在线| 国产精品久久久久久久久久久久 | 亚洲一区二三区| 日本美女xxx| 懂色av一区二区夜夜嗨| www.色就是色| 99精品免费网| 操bbb操bbb| 欧美日韩国产传媒| 国产精品中出一区二区三区| 欧美高清xxx| 欧洲成人在线观看| 婷婷色在线资源| 丝袜美腿亚洲一区二区| 天堂av资源网| 日韩视频一区二区三区| 99成人精品视频| 欧美日韩黄色大片| 免费一级肉体全黄毛片| 国产精品电影院| 国产成人一区二区在线观看| 99在线精品免费| 丰满少妇中文字幕| 精品影院一区二区久久久| 成人黄色片视频| 亚洲国产一区二区三区a毛片| 国产av不卡一区二区| 欧美午夜精彩| 日韩av电影免费观看| 人妖一区二区三区| 国产精品香蕉视屏| 亚洲码欧美码一区二区三区| 成人激情视频在线播放| 国产韩日精品| 国产成人精品视频在线| 色戒汤唯在线观看| 91国产精品视频在线| 超碰97免费在线| 欧美乱大交xxxxx| 黄在线免费看| 久久伊人色综合| a毛片在线播放| 久久视频免费在线播放| 日韩大片在线永久免费观看网站| 国产一区二区三区18 | 欧美大胆a视频| 蜜桃视频在线观看www社区 | 99自拍偷拍视频| 国产日韩欧美不卡在线| 蜜桃传媒一区二区亚洲| 国产亚洲欧洲997久久综合| wwwwww日本| 久久精品一区二区三区四区| 亚洲第一成人网站| 久久精品日产第一区二区三区高清版 | 亚洲一区二区精品在线| 水蜜桃久久夜色精品一区| 亚洲一卡二卡三卡| 艳女tv在线观看国产一区| www.-级毛片线天内射视视| 香港欧美日韩三级黄色一级电影网站| 亚洲一区精彩视频| 一区二区三区四区日韩| 91看片淫黄大片91| 在线日韩欧美| 99精品人妻少妇一区二区| 久久看片网站| 中文字幕22页| 国产成人在线免费| 亚洲少妇18p| 国产欧美精品一区aⅴ影院| 青青青手机在线视频| 亚洲女人****多毛耸耸8| 男女免费视频网站| 欧美丝袜第一区| 中文字幕 视频一区| 51精品秘密在线观看| 国产91绿帽单男绿奴| 国产偷亚洲偷欧美偷精品| av天在线观看| 欧美激情视频免费观看| 亚洲日本天堂| 91九色精品视频| 国产人妖ts一区二区| 日韩电影在线播放| 一区二区三区四区电影| 国自产拍偷拍精品啪啪一区二区| 久久久噜噜噜| 51自拍视频在线观看| 99久久99久久综合| 久久一级免费视频| 性感美女久久精品| 伊人22222| 亚洲国产91色在线| 日本a级在线| 97在线日本国产| 96sao精品免费视频观看| 国产亚洲第一区| 外国成人免费视频| 黄色动漫网站入口| 国产精品乡下勾搭老头1| 欧美色图亚洲激情| 夜夜精品视频一区二区| 在线观看 亚洲| 欧美videos中文字幕| av亚洲在线| 91av在线播放视频| 免费看一区二区三区| 日韩福利影院| 亚洲黑丝一区二区| 亚洲综合123| 国产三区在线成人av| 国产大片中文字幕| 欧美性高清videossexo| 三级网站在线看| 久久伊人精品视频| 欧美一级在线| 日本精品一区二区三区高清 久久| 欧美精品一线| 国产精品探花在线播放| 亚洲国产精品精华液2区45| 91视频免费网址| 日韩欧美在线1卡| 麻豆影视国产在线观看| 国产成人午夜视频网址| 美国成人xxx| 青春草国产视频| 国产乱码精品一区二区三区五月婷 | av在线com| 久久成人免费电影| 日本污视频网站| 91电影在线观看| 免费国产在线观看| 91av网站在线播放| 全国精品免费看| xxxx18hd亚洲hd捆绑| 国产aⅴ综合色| 欧美成人一二三区| 欧美一二三四区在线| www红色一片_亚洲成a人片在线观看_| 国产欧美日韩高清| 久久中文字幕av一区二区不卡| 91淫黄看大片| 国产日产欧美一区| jizz国产在线| 一区二区三区视频在线| www成人在线视频| 日韩福利在线| 青草国产精品久久久久久| 69xxx免费| 欧美精品1区2区| 爆操欧美美女| 99久久国产免费免费| 欧美日本一区| 国产伦精品一区二区免费| 五月天国产精品| 亚洲 美腿 欧美 偷拍| 日本久久精品视频| av影片在线一区| 色一情一区二区三区| 亚洲日本青草视频在线怡红院| www.天天干.com| 国模叶桐国产精品一区| 伦理一区二区三区| 一本大道熟女人妻中文字幕在线 | 国产日产精品一区二区三区的介绍| 欧美日韩综合在线| 高潮毛片在线观看| 国产精品一国产精品最新章节| 国产一区二区你懂的| www色com| 日韩一区二区三区在线| av老司机在线观看| 欧美激情视频一区二区三区| 日本不卡不码高清免费观看| av资源在线免费观看| 精品国产乱码久久久久久蜜臀 | 亚洲色图插插| 无码成人精品区在线观看| 色综合色综合色综合色综合色综合| 91社区在线| 成人动漫视频在线观看免费| 国产精品五区| 手机看片国产日韩| 精品久久久久久久久久久久包黑料 | 国产一区网站| 日本高清免费在线视频| 欧美日韩精品在线观看| 9色在线视频网站| 国产精品果冻传媒潘| 巨乳诱惑日韩免费av| 国产少妇在线观看| 日韩激情第一页| 91嫩草国产线观看亚洲一区二区 | 色综合666| 国产精品99久| 久草视频在线免费| 欧美国产高跟鞋裸体秀xxxhd| 九九精品在线| 国模无码视频一区| 欧美日韩综合在线| 自拍偷拍欧美视频| av久久久久久| 国产精品人成在线观看免费| 午夜av免费在线观看| 91视频国产高清|