精品欧美一区二区三区在线观看 _久久久久国色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技術棧公眾號

色999日韩欧美国产| 欧美色图一区二区三区| 国产精品区一区二区三在线播放| 日韩 欧美 精品| 国产一区二区三区91| 91精品国产一区二区三区 | 国产男女无遮挡猛进猛出| 在线免费av导航| 久久综合久久综合九色| 91精品一区二区| 亚洲免费激情视频| 日韩www.| 亚洲激情在线观看视频免费| 超碰在线人人爱| 丁香花在线观看完整版电影| 欧美经典三级视频一区二区三区| 91aaaa| 亚洲性猛交富婆| 99国内精品| 欧美噜噜久久久xxx| 韩国女同性做爰三级| 亚洲精品高潮| 欧美日韩高清一区| 国产精品一区二区免费在线观看| av网址在线| 国产精品久久久久一区 | 久久精品无码一区二区三区毛片| 国产盗摄——sm在线视频| 中文字幕一区二区5566日韩| 久久99精品久久久久久青青日本| 国产日韩欧美中文字幕| 日本特黄久久久高潮| 性色av香蕉一区二区| 在线观看美女av| 日韩午夜电影网| 亚洲人成亚洲人成在线观看| v天堂中文在线| 一区二区三区四区高清视频| 7777精品伊人久久久大香线蕉超级流畅 | 手机看片福利在线观看| 成人中文字幕电影| 99热在线播放| av综合在线观看| 国产乱子伦视频一区二区三区| 国产精品极品美女在线观看免费| 久久国产黄色片| 在线视频精品| 欧美又大又粗又长| 欧美一级片免费在线观看| 精品96久久久久久中文字幕无| 久久综合免费视频| 希岛爱理中文字幕| 亚洲影视一区二区三区| 久久天天躁狠狠躁夜夜躁| 老司机福利在线观看| 日韩av在线播放网址| 搡老女人一区二区三区视频tv| 久久午夜精品视频| 日韩久久综合| www.亚洲天堂| 日韩一级片av| 亚洲激情国产| 91av国产在线| 99re国产在线| 美腿丝袜亚洲三区| 91亚洲国产精品| 亚洲精品成av人片天堂无码| 成人性视频网站| 久久人人视频| 蜜桃av中文字幕| 在线电影一区| 欧美最顶级的aⅴ艳星| 日本少妇在线观看| 国产日产高清欧美一区二区三区| 97精品伊人久久久大香线蕉| 四虎成人在线观看| 看电视剧不卡顿的网站| 91成人免费在线观看| 丁香六月天婷婷| 暴力调教一区二区三区| 久久影院理伦片| a√资源在线| 亚洲色图欧洲色图| 又大又硬又爽免费视频| 中文字幕成在线观看| 欧美日韩色综合| 天天爽夜夜爽视频| 中国av一区| 久久亚洲精品网站| 少妇一级淫片免费放中国| 日韩电影免费一区| 国产成人免费观看| 国产私人尤物无码不卡| 亚洲欧美激情在线| 大j8黑人w巨大888a片| 久久人体av| 亚洲国产精品成人一区二区| 我不卡一区二区| 国产主播精品| 国产精品美女www| 午夜精品无码一区二区三区| 久久精品免费在线观看| 国产一二三四区在线观看| 超碰成人av| 欧美精选一区二区| 人妻丰满熟妇aⅴ无码| 国产精品久久久久久久免费观看| 久久久久久久国产| 在线免费看av片| 99re这里只有精品6| 伊人久久大香线蕉综合75| a级片在线免费| 欧美日韩二区三区| www.自拍偷拍| 激情另类综合| 99re6热在线精品视频播放速度| 日本福利午夜视频在线| 亚洲黄一区二区三区| 男人插女人下面免费视频| 亚洲日本一区二区三区在线| 色99之美女主播在线视频| 精品国产一区二区三区四| 国产精品18久久久久久vr| 亚洲国产欧美一区二区三区不卡| f2c人成在线观看免费视频| 91精品国产综合久久蜜臀| 亚洲a v网站| 亚洲男女自偷自拍| 国产欧美一区二区视频| 超碰免费在线播放| 欧美日韩午夜精品| 一级黄色录像毛片| 天堂影院一区二区| 免费国产在线精品一区二区三区| 丰满诱人av在线播放| 欧美一级高清片在线观看| 国产破处视频在线观看| 七七婷婷婷婷精品国产| 欧美日产一区二区三区在线观看| 欧美a级在线观看| 亚洲白拍色综合图区| 国产亚洲欧美精品久久久久久| 国产一区不卡视频| 欧美 国产 精品| 99er精品视频| 操日韩av在线电影| 999精品国产| 亚洲精品高清视频在线观看| 亚洲一级片av| 欧美成人嫩草网站| 国产精品theporn88| 爱情岛亚洲播放路线| 精品国产成人在线影院 | 大色综合视频网站在线播放| 欧美在线免费视频| 久草福利在线| 欧美日韩国产小视频在线观看| 婷婷综合在线视频| 极品少妇一区二区三区精品视频| 男女h黄动漫啪啪无遮挡软件| 亚洲免费看片| 久精品免费视频| 日本人妻熟妇久久久久久 | 伊人久久成人网| 国产精品久久久久精k8| 精品国产乱码久久久久久1区二区| 五月天综合网站| 97在线中文字幕| 免费不卡av| 亚洲第一av网站| 免费黄色网址在线| 国产女人水真多18毛片18精品视频| 五月天婷婷激情视频| 99热在线成人| 国产美女精品在线观看| 亚洲少妇视频| 自拍偷拍亚洲精品| 亚洲成人一二三区| 欧美日韩亚洲视频一区| 欧美精品日韩在线| 国产成人精品一区二区三区网站观看| 国产精品久久久久久久乖乖| 一区二区三区日本久久久| 国产精品久久久久久久久久三级| 日本高清视频在线观看| 亚洲成人久久久| 中文字幕在线网址| 亚洲第一狼人社区| 先锋影音av在线| 国产91精品一区二区| 欧美精品一区二区三区免费播放| 欧美独立站高清久久| av日韩免费电影| a屁视频一区二区三区四区| 欧美日韩国产成人在线观看| 黄色小视频在线免费观看| 欧美一级爆毛片| 亚洲黄网在线观看| 亚洲综合一区二区三区| 国产美女永久免费无遮挡| 国产成人av一区二区三区在线观看| 亚洲熟女乱色一区二区三区| 欧美在线网址| 亚洲aⅴ天堂av在线电影软件| 在这里有精品| 国产日产久久高清欧美一区| 男人的天堂免费在线视频| 久久精品99国产精品酒店日本| 手机看片1024国产| 欧美一区三区四区| 波多野结衣一区二区三区在线 | 中文字幕亚洲一区在线观看| 内射无码专区久久亚洲| 欧美丰满高潮xxxx喷水动漫| 日韩成人一区二区三区| 中文字幕亚洲成人| 韩国三级hd中文字幕| 99riav久久精品riav| 免费观看黄网站| 免费观看久久久4p| 女性隐私黄www网站视频| 欧美日韩一区二区国产| 亚洲第一精品区| 欧美综合一区| 免费在线成人av| 国产精品视屏| 成人在线视频网址| 日韩精品三级| 亚洲在线视频福利| 99亚洲男女激情在线观看| 国产精品一区=区| 91桃色在线| 久久久久久18| 黑人精品视频| 欧美人交a欧美精品| 97超碰在线公开在线看免费| 久久精品美女视频网站| 日本不卡视频| zzjj国产精品一区二区| 91xxx在线观看| 亚洲欧美制服丝袜| 国产中文字幕在线看| 国产亚洲视频在线观看| 激情小视频在线| 中文字幕久热精品视频在线| www.在线视频.com| 在线看福利67194| 日本美女在线中文版| 久久精品亚洲精品| av网站大全在线| 久久久久久国产| 97人澡人人添人人爽欧美| 国色天香2019中文字幕在线观看| 国产理论电影在线| 91av在线播放视频| 久久毛片亚洲| 国产精品一区久久久| 日本亚洲欧洲无免费码在线| 国产裸体写真av一区二区 | 久久涩涩网站| 国产成人黄色| 特级毛片在线免费观看| 欧美日韩免费| 欧美在线观看www| 久色成人在线| 中文字幕 欧美日韩| 国产精品一区一区三区| 国产精品成人免费一区久久羞羞| 成人高清av在线| 日本xxxxxxxxx18| 国产精品乱码一区二区三区软件| 日韩av手机在线免费观看| 一区二区三区鲁丝不卡| 国产成人无码精品| 欧美视频完全免费看| 国产999久久久| 日韩电影中文字幕| av在线免费观看网| 欧美日韩成人黄色| 欧美freesex| 91久久久久久久久久久久久| 第四色中文综合网| 日韩电影免费观看高清完整| 亚洲精品国产首次亮相| 草草视频在线免费观看| 秋霞成人午夜伦在线观看| 人妻精品久久久久中文字幕69| 不卡一区中文字幕| 18啪啪污污免费网站| 亚洲综合在线观看视频| 亚洲图片欧美日韩| 欧美xxxxxxxx| av黄色在线观看| 久久久久久91| 亚洲国产伊人| 久久99精品久久久久久秒播放器| 日韩三级在线| 91免费视频网站在线观看| 国产一区二区三区观看| 真实乱视频国产免费观看| 亚洲精品亚洲人成人网| 91麻豆精品在线| 亚洲国产欧美一区二区丝袜黑人| 在线看的av网站| 青青久久aⅴ北条麻妃| 日本精品视频| 亚洲精品欧洲精品| 一本久道综合久久精品| 天天操夜夜操很很操| 国产人妖乱国产精品人妖| 日韩免费一级片| 欧美一区二区日韩一区二区| 超碰97在线免费观看| 91精品国产99| 午夜免费欧美电影| 亚洲一区二区精品在线观看| 国产日韩视频| 逼特逼视频在线观看| 亚洲三级小视频| 最近中文字幕免费观看| 精品亚洲国产视频| 成人一级福利| 不卡日韩av| 午夜精品久久久久99热蜜桃导演 | 九九九九免费视频| 东方欧美亚洲色图在线| 国产大片免费看| 69堂亚洲精品首页| 在线观看免费黄视频| 国产精品wwww| 一本色道久久综合亚洲精品酒店| 日本a视频在线观看| 岛国一区二区三区| 久青草视频在线观看| 日韩欧美精品在线视频| 中文字幕在线观看网站| 亚洲999一在线观看www| 午夜欧美在线| 污污视频网站在线| 亚洲欧美激情小说另类| 99久久国产免费| 欧美另类第一页| 福利片在线一区二区| 久久久久久www| av在线一区二区| av黄色在线看| 亚洲色图25p| 日本一区二区电影| 亚洲高清资源综合久久精品| 日本视频免费一区| 极品尤物一区二区| 欧美剧情片在线观看| 成人在线观看亚洲| 国产精品夜夜夜一区二区三区尤| 亚洲特色特黄| 久久一区二区电影| 日本久久精品电影| 中国日本在线视频中文字幕| 成人激情视频在线观看| 永久亚洲成a人片777777| 亚洲少妇一区二区| 婷婷六月综合网| 国产在线中文字幕| 91精品美女在线| 好吊日精品视频| jizz欧美性20| 欧美日韩在线一区二区| 成人福利在线观看视频| aa日韩免费精品视频一| 亚洲欧美日韩一区在线观看| 国产探花视频在线播放| 911国产精品| 高清电影在线观看免费| 日本精品一区| 国产二区国产一区在线观看| 日本少妇激情视频| 一个色综合导航| 午夜久久av| 美女喷白浆视频| 亚洲一区二区中文在线| 欧美一区二区视频| 成人国产精品一区| 国产日韩免费| 日韩一区二区不卡视频| 亚洲精品国精品久久99热| 2019年精品视频自拍| 国产一级片91| 久久精品人人做人人爽人人| av网站免费播放| 日本欧美国产在线| 欧美a级片网站| 一区二区黄色片| 日韩午夜在线观看| 免费成人美女女| 日本老太婆做爰视频| 91视频com| 亚洲第一精品网站| 国产精品久久久久久久久久久不卡 | 日韩av片在线看| 亚洲人成小说网站色在线 |