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

來聊聊去中心化 Redis 集群節點如何完成通信

數據庫 Redis
本文將從源碼的角度分析redis集群節點如何利用Gossip協議完成節點間的通信與傳播,希望對你有幫助。

一、寫在文章開頭

今天我們來聊點有意思的,關于redis中集群間通信的設計與實現,本文將從源碼的角度分析redis集群節點如何利用Gossip協議完成節點間的通信與傳播,希望對你有幫助。

二、詳解Redis集群節點通信的設計與實現

1. 詳解Gossip協議

在此之前我們先簡單介紹一下Gossip協議,該協議是分布式集群的一種通信協議,我們都知道管理集群的方式有中心化和去中心化兩種方式,中心化的方式是通過第一個第三方的管理中心,例如zookeeper等來維護一份集群節點的信息、狀態:

而redis采用的是去中心化的方式實現集群節點通信,即通過Gossip協議進行節點通信,讓各個節點之間兩兩通信,廣播與自己保持交流的節點,由此將節點串聯起來構成一張關系網:

我們以一個簡單的場景為例介紹一下Gossip協議,默認情況下我們的當前有3個節點的集群,各個節點彼此按照通信要求發送自己的信息和與自己保持交流的節點,由此將有限的資源共享出去構成一個集群。

此時,我們需要橫向擴展一個節點4,我們只需配置/redis-cli --cluster add-node 新節點IP:新節點端口 任意存活節點IP:任意存活節點端口,這個存活節點后續和其他節點通信時,就會將當前新添加的節點4發送出去,由此其他節點收到這個消息并存儲下來,經過各個節點的不斷反復通信,這個集群中的各個節點就會擁有集群中所有節點的信息。

2. 集群消息協定

任何通信都是需要按照協議規范進行,redis集群也一樣,為了保證節點間通信的規范,redis要求集群節點通信的消息的類型可以是以下幾種:

  • ping消息,用來向其他節點發送節點信息。
  • 回復ping的pong消息。
  • 如果當前節點中存在新添加的節點,則通過meet格式的消息發送給其他節點。
  • 如果節點出現故障,則發送fail消息告知集群其他節點。

對此我們給出消息的宏定義代碼,位于cluster.h中:

//集群中的ping
#define CLUSTERMSG_TYPE_PING 0          /* Ping */
//集群中的pong
#define CLUSTERMSG_TYPE_PONG 1          /* Pong (reply to Ping) */
//想加入集群的節點
#define CLUSTERMSG_TYPE_MEET 2          /* Meet "let's join" message */
//某個節點有故障
#define CLUSTERMSG_TYPE_FAIL 3          /* Mark node xxx as failing */

3. 集群節點消息體

后續集群都會通過clusterMsg來表示一條消息,它記錄消息長度以及發送節點名稱、負責的slots以及節點端口號等信息:

typedef struct {
    char sig[4];       
    //消息總長度
    uint32_t totlen;  
   //......
    //消息類型
    uint16_t type;     
    //......
    //發送節點的名稱
    char sender[REDIS_CLUSTER_NAMELEN]; 
    //發送節點負責的slots
    unsigned char myslots[REDIS_CLUSTER_SLOTS/8];
    //......
    char notused1[32];  
    //節點端口
    uint16_t port;     
    //......
    //記錄消息的消息體
    union clusterMsgData data;
} clusterMsg;

這里我們對這個消息體clusterMsgData進行展開說明一下,可以看到他用一段共用體維護各種類型消息的結構,這其中我們只需要了解的是ping消息,從注釋可以看到ping消息這個結構體可以發送ping、meet、pong等類型消息,ping消息類型其內部用clusterMsgDataGossip數組維護,這一點這個消息可以包含多個節點信息存于數組中:

union clusterMsgData {
   //可以發送ping meet pong的消息,該結構體內部有clusterMsgDataGossip數組,這意味這個結構體可以存放多個節點的消息
    struct {
        /* Array of N clusterMsgDataGossip structures */
        clusterMsgDataGossip gossip[1];
    } ping;

    //......
};

步入clusterMsgDataGossip即可看到這個結構體存儲的是需要發送給它人的節點名稱、ping和收到ping的時間以及端口號等信息:

typedef struct {
    char nodename[REDIS_CLUSTER_NAMELEN];//節點名稱
    uint32_t ping_sent; //發送ping的事件
    uint32_t pong_received;//收到pong的事件
    char ip[REDIS_IP_STR_LEN];  //廣播的節點ip
    uint16_t port;          //節點與客戶端進行通信的端口
    //......
} clusterMsgDataGossip;

我們來簡單小結一下,假設我們的某個節點向其他節點發送ping消息告知自己維護的節點信息和狀態,那么對應的消息格式大體如下圖所示:

4. 詳解集群節點ping流程

集群節點的指向流程也是交由redis的時間事件serverCron執行,它會每個100ms執行一次集群的定任務clusterCron方法,其內部會檢查這個定時任務是否執行了10次,一旦執行10次(也就是100ms*10即每1秒)后就會隨機從當前節點維護的其他節點信息字典表中抽取5個節點,找到最早回復pong給當前節點發送一條ping消息:

對此我們給出定時執行的serverCron函數,可以看到其內部每100ms執行一次集群定時任務clusterCron:

int serverCron(struct aeEventLoop *eventLoop, long long id, void *clientData) {
    //......
    //100ms執行一次集群的函數 
    run_with_period(100) {
        if (server.cluster_enabled) clusterCron();
    }
 //......
}

我們步入clusterCron即可看到,該定時任務會隨機抽取5個節點然后找到最早給該節點發送pong的節點發送ping消息包:

void clusterCron(void) {
   //......
    // 每10次即每過去1s執行一次這段邏輯
    if (!(iteration % 10)) {
        int j;

       
        //隨機選出5個節點
        for (j = 0; j < 5; j++) {
            de = dictGetRandomKey(server.cluster->nodes);
            clusterNode *this = dictGetVal(de);

            /* Don't ping nodes disconnected or with a ping currently active. */
            //斷連、或者自己、或者正在握手的節點不處理
            if (this->link == NULL || this->ping_sent != 0) continue;
            if (this->flags & (REDIS_NODE_MYSELF|REDIS_NODE_HANDSHAKE))
                continue;
            //選擇最早收到pong的節點    
            if (min_pong_node == NULL || min_pong > this->pong_received) {
                min_pong_node = this;
                min_pong = this->pong_received;
            }
        }
        //向最早收到pong的調用clusterSendPing發送消息
        if (min_pong_node) {
            redisLog(REDIS_DEBUG,"Pinging node %.40s", min_pong_node->name);
            clusterSendPing(min_pong_node->link, CLUSTERMSG_TYPE_PING);
        }
    }

   //......
}

步入clusterSendPing即可看到我們所說的核心邏輯,即按照公式計算出要發送給最早回復pong的節點對應節點數,然后封裝成消息發送出去:

void clusterSendPing(clusterLink *link, int type) {
    //......
    //我們希望添加的最大節點數,集群總是減去自己和正在握手的
    int freshnodes = dictSize(server.cluster->nodes)-2;

      //......
    //計算wanted
    wanted = floor(dictSize(server.cluster->nodes)/10);
    if (wanted < 3) wanted = 3;
    if (wanted > freshnodes) wanted = freshnodes;

      //......

    /* Populate the header. */
    //設置ping消息頭,構建端口號、slot等信息
    if (link->node && type == CLUSTERMSG_TYPE_PING)
        link->node->ping_sent = mstime();
    clusterBuildMessageHdr(hdr,type);

    /* Populate the gossip fields */
    int maxiterations = wanted*3;
    //基于maxiterations進行循環隨機抽取自己維護的節點信息并組裝
    while(freshnodes > 0 && gossipcount < wanted && maxiterations--) {
        dictEntry *de = dictGetRandomKey(server.cluster->nodes);
        clusterNode *this = dictGetVal(de);
        clusterMsgDataGossip *gossip;
        int j;

       //如果是自己則跳過
        if (this == myself) continue;

       //故障節點不發送
        if (maxiterations > wanted*2 &&
            !(this->flags & (REDIS_NODE_PFAIL|REDIS_NODE_FAIL)))
            continue;

        //....

       
        freshnodes--;
        
        //組裝當前節點的名稱、ip、端口等信息存到hdr所指向的消息結構體
        
        //指向gossip某個索引位置設置名稱、ip、端口等
        gossip = &(hdr->data.ping.gossip[gossipcount]);
        memcpy(gossip->nodename,this->name,REDIS_CLUSTER_NAMELEN);
        gossip->ping_sent = htonl(this->ping_sent);
        gossip->pong_received = htonl(this->pong_received);
        memcpy(gossip->ip,this->ip,sizeof(this->ip));
        gossip->port = htons(this->port);
        gossip->flags = htons(this->flags);
        gossip->notused1 = 0;
        gossip->notused2 = 0;
        gossipcount++;
    }

     //......
     //創建一個發送事件提交給redis發送出去
    clusterSendMessage(link,buf,totlen);
    zfree(buf);
}

5. 等待pong消息回復并解析

每個集群的節點都會定時檢查和對端鏈接的連接是否斷開,如果斷開的嘗試異步非阻塞向其發送建立連接請求,并注冊一個處理器clusterReadHandler處理對端的ping等消息,所以我們上文的ping消息實際上就是通過這個函數進行解析讀取:

對此我們給出這段源碼的入口即可集群的定時任務clusterCron方法,可以看到其內部會便利當前節點通信的節點,查看連接是否為空,若為空則發起連接并注冊clusterReadHandler處理消息:

void clusterCron(void) {
    //......

    
    di = dictGetSafeIterator(server.cluster->nodes);
    //遍歷與當前節點保持通信的節點
    while((de = dictNext(di)) != NULL) {
        clusterNode *node = dictGetVal(de);

        //如果連接為空則非阻塞發起連接,然后注冊clusterReadHandler處理對端節點的消息
        if (node->link == NULL) {
            int fd;
            mstime_t old_ping_sent;
            clusterLink *link;

            fd = anetTcpNonBlockBindConnect(server.neterr, node->ip,
                node->port+REDIS_CLUSTER_PORT_INCR, REDIS_BIND_ADDR);
            //......
            //創建鏈接對應存儲數據的空間
            link = createClusterLink(node);
            link->fd = fd;
            node->link = link;
            //為這個鏈接注冊clusterReadHandler處理發送的消息
            aeCreateFileEvent(server.el,link->fd,AE_READABLE,
                    clusterReadHandler,link);
            //......
        }
    }
    
}

步入clusterReadHandler即可看到redis服務端解析消息存儲到buf并通過clusterProcessPacket解析的邏輯:

void clusterReadHandler(aeEventLoop *el, int fd, void *privdata, int mask) {
    //......

    while(1) { /* Read as long as there is data to read. */
       //......
       //hdr指向link->rcvbuf
       hdr = (clusterMsg*) link->rcvbuf;
        //讀取消息到buf即link->rcvbuf中
        nread = read(fd,buf,readlen);
        //......

        
        if (rcvbuflen >= 8 && rcvbuflen == ntohl(hdr->totlen)) {
            //調用clusterProcessPacket解析這個連接的消息,即 link->rcvbuf
            if (clusterProcessPacket(link)) {
                sdsfree(link->rcvbuf);
                link->rcvbuf = sdsempty();
            } else {
                return; /* Link no longer valid. */
            }
        }
    }
}

而clusterProcessPacket即是該方法的核心所在,它會將對端節點發送的消息進行解析與處理,這里我們就以收到pong消息為例說明一下流程,假設回復pong的是master節點,它會更新收到這條網絡連接pong響應時間,然后解析報文內容,如果發現有個節點不在我們的節點列表中,將其存入node字典表中:

int clusterProcessPacket(clusterLink *link) {
    //......

    /* Perform sanity checks */
    //消息完整性校驗
   //......

    /* Check if the sender is a known node. */
    //檢查發送節點是否是已知節點
    sender = clusterLookupNode(hdr->sender);
    //......

   //......

    /* PING, PONG, MEET:消息處理邏輯 */
    if (type == CLUSTERMSG_TYPE_PING || type == CLUSTERMSG_TYPE_PONG ||
        type == CLUSTERMSG_TYPE_MEET)
    {
      //......
  
  //如果收到pong則更新pong_received為當前時間
        if (link->node && type == CLUSTERMSG_TYPE_PONG) {
            link->node->pong_received = mstime();
            link->node->ping_sent = 0;

           //......
        }

      
  //......

       
        //如果當前節點是已知節點,則調用clusterProcessGossipSection查看當前pong消息中的內容是否包含未知的、新加入的節點
        if (sender) clusterProcessGossipSection(hdr,link);
    } else if (type == CLUSTERMSG_TYPE_FAIL) {
        //......
    }
 //......    
    return 1;
}

步入clusterProcessGossipSection即可看到該函數會遍歷消息中的節點,一旦發現該節點是新添加節點則調用clusterStartHandshake其存入nodes字典表中:

void clusterProcessGossipSection(clusterMsg *hdr, clusterLink *link) {
    uint16_t count = ntohs(hdr->count);
    //解析當前節點gossip消息內容
    clusterMsgDataGossip *g = (clusterMsgDataGossip*) hdr->data.ping.gossip;
    clusterNode *sender = link->node ? link->node : clusterLookupNode(hdr->sender);
 //遍歷node
    while(count--) {
     //......
     //打印當前節點信息
        redisLog(REDIS_DEBUG,"GOSSIP %.40s %s:%d %s",
            g->nodename,
            g->ip,
            ntohs(g->port),
            ci);
      
        node = clusterLookupNode(g->nodename);
        if (node) {//已知節點處理,如果不可通信才握手重連
           //......
        } else {//未知節點則發起握手,若握手建立通信成功則將其存入nodes字典中
            //......
            if (sender &&
                !(flags & REDIS_NODE_NOADDR) &&
                !clusterBlacklistExists(g->nodename))
            {
                clusterStartHandshake(g->ip,ntohs(g->port));
            }
        }

      //走到下一個節點
        g++;
    }
}

我們給出clusterStartHandshake中將其存入server的cluster的nodes字典表的邏輯:

int clusterStartHandshake(char *ip, int port) {
    //......
 //如果處于握手中,則說明之前已經發現并進行通信了,直接返回
    if (clusterHandshakeInProgress(norm_ip,port)) {
        errno = EAGAIN;
        return 0;
    }

 //基于消息創建node結構其,并調用clusterAddNode將其存入server.cluster->nodes字典表中
    n = createClusterNode(NULL,REDIS_NODE_HANDSHAKE|REDIS_NODE_MEET);
    memcpy(n->ip,norm_ip,sizeof(n->ip));
    n->port = port;
    clusterAddNode(n);
    return 1;
}

三、小結

來簡單小結一下Redis集群節點如何通過Gossip協議構建集群網絡的:

  • 新節點通過meet和集群中某個節點a建立連接。
  • 當前節點執行clusterCron定時任務時,隨機抽取5個節點并找到最早回復pong的實例,假設是節點a,發送ping消息。
  • 注冊clusterReadHandler處理器其他節點發送的消息。
  • 收到節點a的pong消息回復,判斷查看該節點是否是已知節點,如果是則調用clusterProcessGossipSection解析報文內容,如果存在新節點則進行握手通信,如果連接建立成功則將該節點存入當前實例的nodes節點中。
責任編輯:趙寧寧 來源: 寫代碼的SharkChili
相關推薦

2022-08-28 19:36:15

數據分片KafkaRocketMQ

2025-02-24 10:07:09

Redis節點遷移集群

2022-12-08 10:49:43

2025-02-17 11:07:10

2024-11-04 15:49:43

Redis?數據遷移

2018-01-12 05:37:52

2022-02-09 15:36:49

Redis主從模式哨兵模式

2022-05-06 16:26:40

區塊鏈去中心化加密貨幣

2020-04-21 22:59:50

Redis搭建選舉

2023-04-07 15:33:09

2019-01-10 13:24:46

去中心化區塊鏈監管

2023-10-30 08:00:00

區塊鏈去中心化

2025-02-13 11:11:53

Redis哨兵代碼

2024-02-04 09:00:00

向量查詢數據檢索MyScale

2021-02-24 10:02:19

存儲云存儲去中心化存儲

2021-02-05 10:03:31

區塊鏈技術智能

2023-04-06 08:00:36

VPC虛擬私有云Amazon

2025-02-21 15:43:29

slotredis集群

2018-09-05 14:39:05

2021-04-06 11:01:06

比特幣加密貨幣去中心化
點贊
收藏

51CTO技術棧公眾號

亚洲丁香婷深爱综合| 亚洲综合一二三区| 国产综合香蕉五月婷在线| 最新日韩免费视频| 国产伦理久久久久久妇女| 黄网站色欧美视频| 一本一道久久a久久综合精品| 国产熟女一区二区三区四区| 在线视频日韩| 久久精品99久久香蕉国产色戒| 男人的天堂免费| 肉色欧美久久久久久久免费看| 国产精品成人一区二区艾草 | 欧美激情亚洲综合一区| 国产精品久久精品| 粉嫩av免费一区二区三区| 久久久久久少妇| 亚洲精彩视频| 国产亚洲免费的视频看| 亚洲欧美日韩色| 久久99久久久精品欧美| 无码av免费一区二区三区试看| 日韩一二三区不卡在线视频| 国产成人手机在线| 麻豆精品视频在线| 热草久综合在线| 欧美日韩人妻精品一区二区三区| 国产欧美日韩免费观看 | 日韩一区二区三区不卡视频| sm性调教片在线观看| 一区二区中文字幕在线| 欧美日韩高清在线一区| 亚洲国产精品二区| 国产在线视频一区二区三区| 国产精品高清免费在线观看| 国产免费av一区二区| 欧美激情1区2区3区| 日韩在线观看视频免费| 天天干天天舔天天操| 日韩福利视频一区| 亚洲国产精品专区久久| 色欲欲www成人网站| 96sao精品免费视频观看| 欧美亚一区二区| 乱子伦视频在线看| 日韩电影大全网站| 日韩欧美中文在线| 黄色免费视频大全| 牛牛精品一区二区| 精品福利在线观看| 欧美视频在线播放一区| av资源中文在线天堂| 亚洲五月六月丁香激情| 99在线免费视频观看| 日日夜夜天天综合入口| 一区二区三区小说| www.欧美黄色| 午夜羞羞小视频在线观看| 一区二区三区四区乱视频| 久久天天东北熟女毛茸茸| a级毛片免费观看在线| 亚洲欧美日韩精品久久久久| 婷婷视频在线播放| 最新超碰在线| 亚洲高清久久久| 六月丁香激情网| 另类专区亚洲| 欧美日韩极品在线观看一区| 日本人69视频| 亚洲国产aⅴ精品一区二区| 欧美不卡激情三级在线观看| 妖精视频一区二区| 亚洲精品国产精品粉嫩| 在线亚洲国产精品网| sm捆绑调教视频| 欧美 日韩 国产精品免费观看| 欧美激情中文网| 制服.丝袜.亚洲.中文.综合懂色| 亚洲一区二区伦理| 国产精品黄色av| av一级黄色片| 91色乱码一区二区三区| 相泽南亚洲一区二区在线播放| 暖暖日本在线观看| 亚洲mv在线观看| 美女网站免费观看视频| 亚洲成人毛片| 亚洲国产91精品在线观看| 91国模少妇一区二区三区| 欧美激情欧美| 久久久久久久久久久亚洲| 香蕉污视频在线观看| 激情综合色播激情啊| 国产免费一区二区三区| 国产高清在线观看| 一区二区理论电影在线观看| 无码人妻h动漫| 成人激情久久| 亚洲精品永久免费精品| 91精品少妇一区二区三区蜜桃臀| 影音先锋亚洲精品| 国产在线精品一区免费香蕉| 十八禁一区二区三区| 国产精品免费aⅴ片在线观看| 精品久久久无码人妻字幂| 亚洲不卡系列| 精品国产三级a在线观看| gv天堂gv无码男同在线观看| 亚洲二区在线| 91精品在线观看视频| 亚洲色偷精品一区二区三区| 日韩一区在线免费观看| a√天堂在线观看| 日韩精品中文字幕一区二区| 亚洲天堂男人天堂女人天堂| 精品肉丝脚一区二区三区| 久久精品国产77777蜜臀| 久久手机视频| 丁香花在线观看完整版电影| 欧美精品一卡两卡| 国产又粗又猛又爽又黄av| av成人毛片| 999精品在线观看| 欧美三级黄网| 欧美性色欧美a在线播放| 黄色性生活一级片| 欧美色图麻豆| 成人淫片在线看| 99青草视频在线播放视| 色综合久久综合网97色综合| a天堂视频在线观看| 欧美日韩天堂| 亚洲专区国产精品| 一区二区三区视频在线观看视频| 91国产免费看| japanese中文字幕| 免费欧美日韩| 美女亚洲精品| 性欧美xxx69hd高清| 亚洲第一综合天堂另类专| 欧美成人精品欧美一级| 国内精品免费**视频| 亚洲综合第一| 999精品嫩草久久久久久99| 精品久久久999| 国产一区二区波多野结衣| 国产精品久久三区| 五月天激情视频在线观看| 欧美少妇性xxxx| 国产精品久久在线观看| 成人精品一区二区三区校园激情 | www.玖玖玖| 西野翔中文久久精品字幕| 17婷婷久久www| 欧美色视频免费| 日本韩国一区二区| 无码少妇精品一区二区免费动态| 三级不卡在线观看| 亚洲看片网站| 国产va免费精品观看精品| 久久久精品电影| 精品国产亚洲一区二区麻豆| 亚洲图片自拍偷拍| 久久久久麻豆v国产精华液好用吗| 一本久道久久综合狠狠爱| 久久亚洲午夜电影| 在线国产成人影院| 久久精品视频在线观看| 午夜免费福利视频| 精品久久久久久亚洲国产300| 性色av蜜臀av色欲av| 日韩成人免费看| 影音先锋亚洲视频| 超碰成人97| 国产成人精品999| 国产盗摄在线观看| 日韩大片免费观看视频播放| 欧美三级网站在线观看| 亚洲欧美区自拍先锋| 超碰男人的天堂| 日韩av不卡一区二区| 成人短视频在线看| 欧美偷窥清纯综合图区| 国产精品男女猛烈高潮激情| bt在线麻豆视频| 日韩国产精品一区| 国产一区二区三区视频免费观看| 亚洲一区二区视频在线| 尤物视频最新网址| 精品一区二区三区久久久| 国产女主播自拍| av资源久久| 国产精品我不卡| 福利一区二区三区视频在线观看| 欧美激情免费视频| jizz在线免费观看| 亚洲国产精品字幕| 国产乱淫av片免费| 色综合久久99| 国产亚洲精品成人| 国产精品欧美精品| 搡老熟女老女人一区二区| 韩国三级在线一区| 欧美黄色一级片视频| 精品动漫3d一区二区三区免费| 日韩欧美精品一区二区三区经典| 99精品在免费线中文字幕网站一区| 国产精品a久久久久久| 黄色污污视频在线观看| 久久精品国产亚洲精品2020| 男人的天堂在线免费视频| 欧美mv和日韩mv的网站| 亚洲视频在线观看免费视频| 精品久久香蕉国产线看观看亚洲 | 99热免费精品| 国产成人免费高清视频| 成人影院在线| 免费亚洲一区二区| 国产精品白丝av嫩草影院| 91在线色戒在线| 欧美成人xxxx| 国产成人在线亚洲欧美| 成人欧美一区二区三区的电影| 九色成人免费视频| 免费超碰在线| 中文字幕视频一区二区在线有码| 少妇激情av一区二区| 亚洲国产黄色片| 欧美 日韩 国产 成人 在线| 日韩一区二区三区观看| 91国内精品视频| 欧美日韩一卡二卡三卡| 最好看的日本字幕mv视频大全| 日韩欧美成人区| 久久国产视频一区| 精品久久久久久久中文字幕| 日韩欧美国产亚洲| 五月天婷婷综合| 91久久国产视频| 精品动漫一区二区| 久久99精品波多结衣一区| 婷婷亚洲久悠悠色悠在线播放| 伊人国产在线观看| 午夜久久久久久| 国产成人在线播放视频| 婷婷丁香激情综合| 波多野结衣国产| 色噜噜狠狠成人中文综合| 久久久黄色大片| 91久久线看在观草草青青| 久久永久免费视频| 欧美日本一区二区三区| 国产裸体无遮挡| 日韩视频一区在线观看| 国产片在线播放| 精品国产91久久久久久久妲己| 欧洲精品久久一区二区| 日韩电影中文字幕在线观看| 青梅竹马是消防员在线| 国产亚洲成av人片在线观看桃| 成人午夜电影在线观看| xvideos亚洲人网站| 在线看一级片| 午夜精品美女自拍福到在线| 网友自拍亚洲| 成人激情在线播放| 成人高潮视频| 欧美日韩电影一区二区三区| 日韩av在线播放网址| 91免费视频黄| 国产亚洲午夜| 15—17女人毛片| 国产精品一区一区| 大乳护士喂奶hd| 国产欧美一区二区三区沐欲| 午夜三级在线观看| 亚洲高清免费观看高清完整版在线观看 | 亚洲精选免费视频| 成年人免费看毛片| 在线一区二区三区做爰视频网站| 一级黄色大片网站| 亚洲成成品网站| av网站在线免费观看| 欧美精品在线网站| 美女18一级毛片一品久道久久综合| 国产乱人伦真实精品视频| 国产一区二区三区亚洲| 欧美日韩在线精品一区二区三区| 91av精品| 蜜臀av午夜一区二区三区| 国内一区二区视频| 一区二区三区免费在线观看视频 | 在线观看亚洲视频啊啊啊啊| 极品中文字幕一区| 91欧美视频在线| 99久久久精品| 麻豆精品国产免费| 欧美性猛交xxxx| 国产草草影院ccyycom| 亚洲人线精品午夜| 丰满的护士2在线观看高清| 国产精品视频自在线| 久久97精品| 国产又粗又硬又长| 日韩 欧美一区二区三区| 99re这里只有| 亚洲美女偷拍久久| 亚洲av综合一区| 日韩大片在线观看视频| 欧美韩日亚洲| 成人国内精品久久久久一区| 综合国产视频| 国产精品裸体瑜伽视频| 国产在线乱码一区二区三区| 国产一二三四五区| 精品国产91久久久久久| 高潮一区二区三区乱码| 久久精品最新地址| 午夜av成人| 蜜桃久久精品乱码一区二区| 亚洲高清毛片| www.欧美com| 亚洲欧美视频在线观看视频| 又骚又黄的视频| 亚洲午夜激情免费视频| 天堂中文最新版在线中文| 国产精品9999久久久久仙踪林| 99热在线成人| 色婷婷成人在线| 国产日韩欧美精品综合| 免费观看日批视频| 亚洲精品有码在线| 亚洲欧美小说色综合小说一区| 国产女人水真多18毛片18精品| 狠狠噜噜久久| 不许穿内裤随时挨c调教h苏绵| 亚洲免费三区一区二区| 国产毛片毛片毛片毛片| 日韩在线观看免费全集电视剧网站 | 人人狠狠综合久久亚洲婷婷| 国产xxxxx视频| 国产三级一区二区三区| 亚洲天堂五月天| 国产亚洲a∨片在线观看| 亚洲日本在线观看视频| 日本视频一区二区不卡| 欧美a级一区二区| 成年人免费视频播放| 欧美日本国产一区| 国产网站在线免费观看| 3d动漫精品啪啪一区二区三区免费| 欧美成人69| www.四虎精品| 五月婷婷激情综合网| 完全免费av在线播放| 国产高清一区二区三区| 亚洲九九精品| 美女久久久久久久久久| 欧美性色综合网| 成人午夜在线影视| 国产精品久久久久久久免费大片| 伊人久久大香线蕉av超碰演员| 最近中文字幕无免费| 一本色道久久综合狠狠躁的推荐 | 青青草精品视频在线观看| 中文字幕精品三区| 国产男男gay网站| 久久久伊人欧美| 最新亚洲精品| 亚洲综合婷婷久久| 亚洲精品久久嫩草网站秘色| 日韩一区二区三区不卡| 琪琪亚洲精品午夜在线| 日韩三级在线| youjizz.com日本| 色综合久久久久网| 国产精品久久麻豆| 国产另类自拍| 日本va欧美va瓶| 久久久精品国产sm调教| 亚洲欧美在线免费| 9999精品免费视频| 看av免费毛片手机播放| 国产精品久久二区二区| 欧美一区,二区| 国产精品男女猛烈高潮激情| 激情视频一区| 国产aaaaaaaaa| 亚洲精品国产精品国自产观看浪潮 | 天堂网在线观看国产精品| 国产黑丝在线观看| 欧美日韩卡一卡二| 乱人伦视频在线| 中文字幕剧情在线观看一区| 97se亚洲国产综合自在线观| 一级黄色大片网站| 国产成人亚洲综合| 激情婷婷亚洲| 希岛爱理中文字幕| 亚洲丝袜在线视频|