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

欧美日韩一级在线观看| 欧美日韩国产一区二区三区地区| 日韩欧美一级精品久久| 欧美不卡三区| 欧美成欧美va| 偷拍自拍亚洲色图| 国产美女精品一区二区三区| 欧美日本在线视频| 成人午夜视频免费观看| 中文字幕av无码一区二区三区| 加勒比视频一区| 综合网在线视频| 国产精品精品视频一区二区三区| 亚洲成人av免费在线观看| 在线观看三级视频| 国产精品精品国产一区二区| 色婷婷综合久久久久中文| 国产91视觉| 青青操视频在线播放| 神马久久av| 91精品福利在线一区二区三区| 日日夜夜精品网站| wwwwww在线观看| 国产亚洲一区二区三区不卡| 五月激情六月综合| 久久99精品久久久久久久久久| 久久中文字幕在线观看| 精品视频在线一区| 一区二区三区在线播| 91中文精品字幕在线视频| 久久嫩草捆绑紧缚| 国产精品欧美一区二区三区不卡| 亚洲欧洲色图综合| 欧美日产一区二区三区在线观看| 久久青青草原亚洲av无码麻豆| 亚洲一区二区三区日本久久九| 亚洲蜜臀av乱码久久精品| 91丝袜脚交足在线播放| 国产一级在线免费观看| 韩国女主播一区二区三区| 亚洲成人av在线电影| 精品蜜桃传媒| 日韩精品一区不卡| 日本黄色精品| 欧美一区二区三区婷婷月色| 国产自偷自偷免费一区 | 国产精品资源| 亚洲成人性视频| 夜夜添无码一区二区三区| 天天色综合久久| 日韩专区欧美专区| 久久精彩免费视频| 欧美激情第四页| 免费不卡av| 久久嫩草精品久久久精品一| 国产精品亚洲美女av网站| 波多野结衣家庭教师| 北条麻妃在线一区二区免费播放 | 久久精品女人毛片国产| 一区二区三区在线| 精品国产亚洲在线| 无码人妻丰满熟妇区五十路百度| 国产女人在线观看| 国产酒店精品激情| 亚洲综合成人婷婷小说| 99热这里只有精品5| 亚洲精选在线| 中文字幕在线精品| youjizz.com国产| 日韩免费小视频| 亚洲天堂av老司机| 欧美成人dvd在线视频| 四虎精品成人影院观看地址| 韩国一区二区三区| 欧美亚洲日本网站| 91视频综合网| 欧美精品一级| 尤物yw午夜国产精品视频明星| 最好看的中文字幕| 欧美日韩免费看片| 亚洲国产一区二区视频| 伊人狠狠色丁香综合尤物| 亚洲欧美一区二区三| 精品一区二区三区香蕉蜜桃| 97超级碰碰人国产在线观看| 一起操在线播放| 欧美美女一区| 日韩黄色高清视频| 9191在线视频| 天堂99x99es久久精品免费| 亚洲日本中文字幕免费在线不卡| 日本wwwxx| 久久久亚洲欧洲日产| 一区二区三区精品99久久| 欧美大片xxxx| 久久精品日产第一区二区| 欧美日韩ab片| 波多野结衣亚洲色图| 1024日韩| 国产精品美女久久久久av超清| 日本一区二区不卡在线| 欧美在线网址| 久久久精品国产| 亚洲 欧美 视频| 亚洲激情午夜| 国产欧美最新羞羞视频在线观看| 无码免费一区二区三区| 国产一区视频网站| 欧美日韩亚洲一区二区三区在线观看 | 国产一区二区免费电影| 亚洲天堂手机在线| 久久精品卡一| 国产精品一区二区欧美| 国产黄色美女视频| 久久久国产精华| 欧美在线一区二区三区四区| 五月天婷婷视频| 1024精品合集| 国产偷人视频免费| 卡通欧美亚洲| 日本韩国一区二区三区视频| 亚洲色欲综合一区二区三区| 四虎国产精品免费久久5151| 欧美三级电影在线看| 国产裸体免费无遮挡| 亚洲天堂中文字幕在线观看| 丝袜情趣国产精品| 国产真实乱在线更新| 久久亚洲色图| 日韩免费在线免费观看| 国产午夜麻豆影院在线观看| 国产成人啪免费观看软件| 91在线观看网站| 97最新国自产拍视频在线完整在线看| 国产精品高潮呻吟| 成人在线免费观看网址| 色呦呦在线看| 精品久久久久久国产91| 91精品人妻一区二区三区四区| 国产精品久久久久久久久久白浆| 久久精品精品电影网| 91视频久久久| 国产精品一区二区视频| 亚洲欧洲国产日韩精品| 岛国成人毛片| 五月天激情小说综合| 69久久精品无码一区二区| 91日韩在线| 久久久久久久久国产| 日本天堂网在线观看| 丁香六月综合激情| 欧美日韩日本网| 在线观看涩涩| 欧美日韩电影一区| 丰满的亚洲女人毛茸茸| 在线看片不卡| 91成人免费视频| 超碰超碰在线| 精品国产一区久久| 久久久久久久99| 91在线porny国产在线看| 日韩久久精品一区二区三区| 天天干在线视频论坛| 日韩三级电影网址| 亚洲第一视频区| 日本亚洲天堂网| 国产精品对白一区二区三区| 色呦呦网站在线观看| 日韩成人性视频| 中文字幕在线播| 国产精品毛片久久久久久久| 日韩xxxx视频| 天美av一区二区三区久久| 日本一欧美一欧美一亚洲视频| 成年人在线观看| 午夜精品久久久久久久久久 | 日韩电影在线播放| 啪啪av大全导航福利综合导航| 久久久www成人免费精品张筱雨| 精品欧美一区二区精品少妇| 久久久久免费观看| 99热这里只有精品在线播放| 国产精品白浆| 欧美在线激情网| 成人爽a毛片一区二区| 国产精品色婷婷久久58| 日本高清免费观看| 欧美亚洲一区| 国产精品视频免费一区| 成人av三级| 久久亚洲国产精品成人av秋霞| 99re国产在线| 亚洲婷婷在线视频| 久久久久久久久免费看无码 | 亚洲无码精品在线观看| 一区二区三区国产精品| 在线观看免费视频高清游戏推荐| 成人在线视频福利| 日本毛片在线观看| 一区二区三区波多野结衣在线观看| 北京富婆泄欲对白| 免费av成人在线| 亚洲国产精品一区二区第一页| 精品91福利视频| 国产成人精品999| 欧美午夜黄色| 日韩欧美一区二区三区久久| 国产黑丝一区二区| 国产欧美日韩一级| 秋霞在线一区二区| 精品99re| 国产精品欧美风情| 在线观看v片| 欧美精品电影在线| 黄色在线观看网站| 日韩美女视频在线| 国产一级片一区二区| 午夜久久久影院| 永久久久久久久| 国产精品每日更新在线播放网址 | 国产免费黄色av| 欧美三级自拍| 欧美中文字幕在线| 人人澡人人添人人爽一区二区| 日韩在线观看视频免费| 欧美18xxxxx| 欧美视频一区在线| 欧美色视频一区二区三区在线观看 | 国产精品96久久久久久| 91九色美女在线视频| 日韩高清中文字幕| 亚洲伦理在线观看| 欧美一级电影网站| 国产精品欧美久久久久天天影视| 亚洲视频资源在线| 欧美日韩中文字幕视频| 国产午夜精品一区二区| 亚洲一区二区三区观看| 国产精品mm| 欧美与动交zoz0z| 狠狠一区二区三区| 国产91免费视频| 国产96在线亚洲| 国产精品国模大尺度私拍| 日韩av综合| 欧美一级大片视频| 黄色aa久久| 综合欧美国产视频二区| 成人动漫在线播放| 中文字幕亚洲一区在线观看 | 欧美极品xxx| 无码人妻一区二区三区在线视频| 久久超级碰视频| 涩多多在线观看| 国产精品嫩草99av在线| 3d动漫一区二区三区| 久久一区二区中文字幕| 亚洲精品国产精品国自产| 日韩理论电影院| 精品国产免费人成电影在线观...| 粉嫩的18在线观看极品精品| 国产欧美一区二区三区不卡高清| 成人资源在线| 女同一区二区| av伊人久久| 欧美三级午夜理伦三级老人| 国色天香一区二区| 在线精品日韩| 欧美成人69av| heyzo亚洲| 日韩精彩视频在线观看| 日本美女视频一区| 成人听书哪个软件好| 国产精品一区二区入口九绯色| 国产亚洲自拍一区| 女人18毛片毛片毛片毛片区二| 亚洲精品免费在线播放| 国产做受高潮漫动| 欧美性xxxxxx少妇| 亚洲第一色网站| 欧美一区二区在线免费播放| 亚洲国产www| 亚洲欧美国产精品专区久久| 国产黄色高清视频| 精品爽片免费看久久| 成人久久精品人妻一区二区三区| 亚洲精品国产精品久久清纯直播 | 天堂中文在线播放| 国产精品日韩电影| 成人看片黄a免费看视频| 欧美一卡2卡3卡4卡无卡免费观看水多多 | caoporn91| 色就色 综合激情| 国产男男gay体育生白袜| 欧美最猛性xxxxx直播| 成人免费看片98欧美| 亚洲午夜三级在线| 日韩一级片中文字幕| 日韩美女一区二区三区四区| 日本亚洲一区| 欧美国产第一页| 在线观看av免费| 国产大片精品免费永久看nba| 精品一区二区三区在线观看视频 | 日本欧美国产| 成人一级生活片| 欧美日本一区二区视频在线观看| 国产综合av在线| 在线看片一区| 91九色丨porny丨国产jk| 日韩精品国产精品| 50一60岁老妇女毛片| 中文字幕亚洲视频| 国产成人无码av| 欧美变态tickle挠乳网站| www.av在线.com| 在线成人免费网站| 九色porny自拍视频在线播放| 羞羞色国产精品| 午夜影院在线观看国产主播| 999视频在线观看| 国内欧美日韩| 成人黄在线观看| 国产免费久久| 日韩欧美国产免费| 成人免费黄色在线| 我家有个日本女人| 欧美精品久久99久久在免费线| 99热这里只有精品3| 一本一本久久a久久精品牛牛影视 一本色道久久综合亚洲精品小说 一本色道久久综合狠狠躁篇怎么玩 | 2019中文字幕全在线观看| 97se亚洲| 日本香蕉视频在线观看| 国产一区不卡在线| 三级黄色录像视频| 欧美日韩国产综合久久 | 窝窝社区一区二区| 日韩国产欧美亚洲| www.亚洲人| 伊人影院综合网| 91福利在线看| 国产精品久久一区二区三区不卡 | 欧美91在线|欧美| 视频一区二区精品| 免费的成人av| 成年人免费视频播放| 亚洲天堂成人在线观看| 亚洲综合网av| 久热国产精品视频| 99综合99| 精品午夜一区二区三区| 日韩午夜免费| 一级黄色特级片| 中文无字幕一区二区三区| 欧美日韩一级在线观看| 欧美成人video| aa级大片免费在线观看| 国产伦精品一区二区三区视频孕妇| 国产精品v欧美精品v日本精品动漫| 91大神免费观看| 亚洲一区二区在线免费看| 特级丰满少妇一级aaaa爱毛片| 欧美激情高清视频| 精品国内亚洲2022精品成人| 日韩a∨精品日韩在线观看| 不卡在线视频中文字幕| 日韩在线视频免费看| 日韩亚洲欧美成人一区| av毛片午夜不卡高**水| 久久伦理网站| 久久99精品国产91久久来源| 中文字幕电影av| 亚洲变态欧美另类捆绑| 免费看av不卡| 一区二区日本| 天堂一区二区在线| 青青草自拍偷拍| 色综合久久久久综合体| 啊v在线视频| 91观看网站| 久久不射中文字幕| 国产精品精品软件男同| 欧美大片一区二区| 欧美色999| 男人天堂网站在线| 91婷婷韩国欧美一区二区| 欧美一区二区三区爽爽爽| 亚洲变态欧美另类捆绑| 国产极品一区| 日本一区二区三区视频在线播放| 久久66热re国产| 久久久久久久99| 日韩网站免费观看| 欧美与亚洲与日本直播| 久久亚洲免费| 极品少妇xxxx精品少妇偷拍| 91香蕉在线视频| 色偷偷av一区二区三区乱| 日韩成人av在线资源| 亚洲色图欧美自拍|