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

聊聊 Redis 哨兵選舉與故障轉移的實現

數據庫 Redis
這一篇我們將接著之前的思路,將哨兵獲取客觀下線結果并結合raft協議完成哨兵leader選舉完成故障轉移的流程分析完成,希望對你有幫助。

上一篇文章我們將哨兵主觀下線的核心流程都分析完成,這一篇我們將接著之前的思路,將哨兵獲取客觀下線結果并結合raft協議完成哨兵leader選舉完成故障轉移的流程分析完成,希望對你有幫助。

詳解哨兵選舉與故障轉移流程

1. 獲取客觀下線結果判斷

當前哨兵主觀認定master下線之后,為了明確知曉master節點是否真的下線,哨兵節點還會通過cc即異步命令指針所維護的socket連接發起is-master-down-by-addr的sentinel指令進行詢問,其他哨兵所回復的結果都會通過回調函數sentinelReceiveIsMasterDownReply函數處理。

這段請求最終會被其他哨兵sentinel命令所對應的函數sentinelCommand執行,他們各自會在內部查看自己對于master判斷是否是主觀下線,如果是則返回1。

最后我們的哨兵收到這個結果1,則通過位運算加master節點狀態flags類加上客觀下線的判斷標識64,這里redis為了提升運算效率,采用的二進制|=運算,這一點我們在閱讀大量的redis中源碼都會看到二進制運算這一點優化:

對此我們也給出哨兵處理每一個master實例的函數入口,可以看到在調用sentinelCheckSubjectivelyDown完成主觀下線的檢查之后,又會調用sentinelAskMasterStateToOtherSentinels并傳入SENTINEL_NO_FLAGS即僅僅檢查其他哨兵對于當前master的主觀判斷結果:

//這個入參包含恰哨兵實例和當前主節點的從節點信息
void sentinelHandleRedisInstance(sentinelRedisInstance *ri) {
   //......
    //3. 主觀判斷是否下線
    sentinelCheckSubjectivelyDown(ri);

   //......

    /* Only masters */
    if (ri->flags & SRI_MASTER) {
      
       //......
        //傳入master信息ri以及標識SENTINEL_NO_FLAGS意味僅了解其他哨兵對于master節點狀態的判斷
        sentinelAskMasterStateToOtherSentinels(ri,SENTINEL_NO_FLAGS);
    }
}

步入sentinelAskMasterStateToOtherSentinels即可看到哨兵詢問其他哨兵對于master判斷的邏輯,可以看到它遍歷出每一個哨兵實例,通過異步連接cc指針所指向的連接發起SENTINEL is-master-down-by-addr指令獲取其他哨兵節點對于master下線的看法,并注冊sentinelReceiveIsMasterDownReply函數處理返回結果:

#define SENTINEL_ASK_FORCED (1<<0)
void sentinelAskMasterStateToOtherSentinels(sentinelRedisInstance *master, int flags) {
    dictIterator *di;
    dictEntry *de;

    di = dictGetIterator(master->sentinels);
    //遍歷哨兵實例
    while((de = dictNext(di)) != NULL) {
        sentinelRedisInstance *ri = dictGetVal(de);
        //......

        /* Ask */
        ll2string(port,sizeof(port),master->addr->port);
        //發送is-master-down-by-addr命令獲取其他哨兵客觀下線的結果,并通過sentinelReceiveIsMasterDownReply作為回調處理接收結果
        retval = redisAsyncCommand(ri->cc,
                    sentinelReceiveIsMasterDownReply, NULL,
                    "SENTINEL is-master-down-by-addr %s %s %llu %s",
                    master->addr->ip, port,
                    sentinel.current_epoch,
                    //若大于SENTINEL_FAILOVER_STATE_NONE則說明執行故障切換,傳入server.runid  
                    (master->failover_state > SENTINEL_FAILOVER_STATE_NONE) ?
                    server.runid : "*");
        if (retval == REDIS_OK) ri->pending_commands++;
    }
    dictReleaseIterator(di);
}

其他哨兵收到sentinel指令后就會調用sentinelCommand處理這條指令,其內部會判斷自己所維護的master的flags二進制位是否包含SRI_S_DOWN,如果是則說明被請求的哨兵節點同樣認為master已下線,則直接回復master的leaderid以及shared.cone即1(代表確認當前master確實下線):

void sentinelCommand(redisClient *c) {
    //......
    else if (!strcasecmp(c->argv[1]->ptr,"is-master-down-by-addr")) {//處理客觀下線請求
        //......
       

       
        //如果master主觀判定下線即flags包含SRI_S_DOWN這個主觀下線標識,則isdown設置為1
        if (!sentinel.tilt && ri && (ri->flags & SRI_S_DOWN) &&
                                    (ri->flags & SRI_MASTER))
            isdown = 1;

        //上文isdown 設置為1,返回 shared.cone告知對應leaderid的master被我方認定為下線
        //響應3部分內容,下線狀態、leader id以及當前leader的紀元
        addReplyMultiBulkLen(c,3);
        addReply(c, isdown ? shared.cone : shared.czero);
        addReplyBulkCString(c, leader ? leader : "*");
        addReplyLongLong(c, (long long)leader_epoch);
        if (leader) sdsfree(leader);
    } //......
    return;
//......
}

最終我們的sentinel的回調函數sentinelReceiveIsMasterDownReply處理對端的結果,發現返回值為1,說明該節點對于我們的來說客觀認為master下線了。

所以我們的哨兵就需要記錄這個消息,因為我們維護master->sentinels的字典記錄其他哨兵信息,所以定位到其他哨兵客觀下線的回復后,我們就會從這個字典中找到這個哨兵的結構體將其flags累加一個SRI_MASTER_DOWN的常數值64,意味這個哨兵客觀認定這個master下線了:

void sentinelReceiveIsMasterDownReply(redisAsyncContext *c, void *reply, void *privdata) {
  //......


    if ( //......)
    {
    //更新上次響應時間
        ri->last_master_down_reply_time = mstime();
        if (r->element[0]->integer == 1) {//如果返回(cone默認設置為1)1則說明其他哨兵認為master下線,累加將當前維護的哨兵字段的flags累加SRI_MASTER_DOWN
            ri->flags |= SRI_MASTER_DOWN;
        } else {
           //......
        }
        //......
    }
}

2. 啟動故障轉移

上一步收集其他哨兵的判斷并更新到各自的flags位后,當前哨兵的定時任務再次遍歷master調用sentinelHandleRedisInstance處理當前master,其內部會遍歷當前哨兵維護的哨兵數組獲取這些哨兵對于master下線的看法,如果累加到的哨兵對于下線的看法大于或者等于我們配置quorum之后,則會判定會客觀下線:

我們還是從sentinelHandleRedisInstance方法查看方法入口,可以看到哨兵定時執行該方法時會調用sentinelCheckObjectivelyDown檢查客觀下線狀態:

void sentinelHandleRedisInstance(sentinelRedisInstance *ri) {
   //......
    if (ri->flags & SRI_MASTER) {
       //......
       //檢查其當前是否客觀下線
        sentinelCheckObjectivelyDown(ri);
        //......
    }
}

步入其內部即可看到筆者所說的,遍歷哨兵查看下線結果并更新master下線狀態的邏輯:

void sentinelCheckObjectivelyDown(sentinelRedisInstance *master) {
   //......
    //如果是主觀下線,步入該邏輯
    if (master->flags & SRI_S_DOWN) {
        //自己的票數設置進去,quorum為1
        quorum = 1; /* the current sentinel. */
      
      
        //遍歷其他哨兵,如果為客觀下線則累加quorum
        di = dictGetIterator(master->sentinels);
        while((de = dictNext(di)) != NULL) {
            sentinelRedisInstance *ri = dictGetVal(de);

            if (ri->flags & SRI_MASTER_DOWN) quorum++;
        }
       //如果投票數大于配置的quorum,則odown 為1,即說明客觀認定下線了
       
        if (quorum >= master->quorum) odown = 1;
    }

    //如果明確客觀下線,則廣播+odown事件
    if (odown) {
        if ((master->flags & SRI_O_DOWN) == 0) {
            sentinelEvent(REDIS_WARNING,"+odown",master,"%@ #quorum %d/%d",
                quorum, master->quorum);
         //累加標識,并更新master下線時間
            master->flags |= SRI_O_DOWN;
            master->o_down_since_time = mstime();
        }
    } else {
       //......
    }
}

3. 發起新紀元leader選舉

基于上述結果redis會判斷是否發起故障轉移,若需要則通知其他哨兵進行leader選舉,收到通知的哨兵會檢查當前紀元是否小于發起選舉的哨兵紀元,若符合要求且在此期間沒有別的哨兵發起選舉,則向其投票。

后續我們的哨兵收到并收集這些響應之后,更新自己所維護的哨兵數組中的leader_epoch,通過遍歷這個哨兵數組中的leader_epoch是否和自己所生成的leader_epoch一致,如果統計結果超過半數,則說明自己當選leader,由此開始進行故障轉移:

(1) 選舉源碼入口

我們還是以sentinelHandleRedisInstance作為程序入口,可以看到其內部調用sentinelStartFailoverIfNeeded判斷是否需要進行故障轉移,然后調用sentinelAskMasterStateToOtherSentinels并傳入SENTINEL_ASK_FORCED發起leader選舉請求:

//這個入參包含恰哨兵實例和當前主節點的從節點信息
void sentinelHandleRedisInstance(sentinelRedisInstance *ri) {
    //......
    if (ri->flags & SRI_MASTER) {
          //......
        //  判斷是否要進行故障切換,若需要則調用sentinelAskMasterStateToOtherSentinels傳入SENTINEL_ASK_FORCED進行leader選舉
        if (sentinelStartFailoverIfNeeded(ri))
            sentinelAskMasterStateToOtherSentinels(ri,SENTINEL_ASK_FORCED);
        // 執行故障切換
        sentinelFailoverStateMachine(ri);
       //......
    }
}

(2) 確認故障轉移

我們步入sentinelStartFailoverIfNeeded即可看到其對于是否進行故障轉移的判斷,邏輯比較簡單:

  • 明確是否客觀認定下線。
  • 明確是否處于故障轉移。
  • 近期是否有進行故障轉移。

如果傷處條件都排除則:

  • failover_state 即故障轉移狀態設置為等待故障轉移,后續的函數狀態機會根據這個標識進行故障轉移處理。
  • flags標識累加處于故障轉移中。
  • 更新master紀元為哨兵紀元+1,用于后續哨兵leader選舉后更新紀元使用。

對此我們給出sentinelStartFailoverIfNeeded的判斷,可以看到它會按照上文所說的流程進行判斷,明確排除三種情況后調用sentinelStartFailover設置故障轉移狀態:

int sentinelStartFailoverIfNeeded(sentinelRedisInstance *master) {
   //是否客觀下線,若不是則返回0
    if (!(master->flags & SRI_O_DOWN)) return 0;

   //是否處于故障轉移中,如果是則直接返回0
    if (master->flags & SRI_FAILOVER_IN_PROGRESS) return 0;

   
    //距離上次故障轉移時間是否小于2倍的超時時間,如果是則返回0
    if (mstime() - master->failover_start_time <
        master->failover_timeout*2)
    {
        if (master->failover_delay_logged != master->failover_start_time) {
            time_t clock = (master->failover_start_time +
                            master->failover_timeout*2) / 1000;
            char ctimebuf[26];

            ctime_r(&clock,ctimebuf);
            ctimebuf[24] = '\0'; /* Remove newline. */
            master->failover_delay_logged = master->failover_start_time;
            redisLog(REDIS_WARNING,
                "Next failover delay: I will not start a failover before %s",
                ctimebuf);
        }
        return 0;
    }
    //啟動故障轉移 并返回1
    sentinelStartFailover(master);
    return 1;
}

步入sentinelStartFailover即可看到我們上文所說故障轉移狀態更新:

void sentinelStartFailover(sentinelRedisInstance *master) {
    redisAssert(master->flags & SRI_MASTER);
    //故障轉移等待啟動
    master->failover_state = SENTINEL_FAILOVER_STATE_WAIT_START;
    //設置為正在故障轉移
    master->flags |= SRI_FAILOVER_IN_PROGRESS;
    //更新紀元
    master->failover_epoch = ++sentinel.current_epoch;
   //......
}
(3) 發起投票

結果上述步驟明確知曉redis需要進行故障轉移之后,哨兵會再次調用sentinelAskMasterStateToOtherSentinels方法傳入當前哨兵的server.runid向其他哨兵發起投票請求,并通過sentinelReceiveIsMasterDownReply處理響應結果:

void sentinelAskMasterStateToOtherSentinels(sentinelRedisInstance *master, int flags) {
    //遍歷其他哨兵
    di = dictGetIterator(master->sentinels);
    while((de = dictNext(di)) != NULL) {
     

       //......
       //因為failover_state 在上一步已經改為傳入自己的SENTINEL_FAILOVER_STATE_WAIT_START即等待故障轉移,故大于SENTINEL_FAILOVER_STATE_NONE,于是傳入哨兵的server.runid發起投票選舉
        retval = redisAsyncCommand(ri->cc,
                    sentinelReceiveIsMasterDownReply, NULL,
                    "SENTINEL is-master-down-by-addr %s %s %llu %s",
                    master->addr->ip, port,
                    sentinel.current_epoch,
                    //若大于SENTINEL_FAILOVER_STATE_NONE則說明執行故障切換,傳入server.runid  
                    (master->failover_state > SENTINEL_FAILOVER_STATE_NONE) ?
                    server.runid : "*");
        if (retval == REDIS_OK) ri->pending_commands++;
    }
    dictReleaseIterator(di);
}

(4) 對端哨兵處理發起選舉的投票結果

上述步驟發起投票的哨兵節點發起投票后,收到投票請求的哨兵實例就會進行如下檢查:

  • master紀元小于發起投票請求的哨兵紀元req_epoch。
  • 當前哨兵紀元小于req_epoch。

如果符合要求則說明發起投票請求的哨兵可以作為leader,當前實例將leader 設置為該節點,然后回復結果給發送結果的實例:

char *sentinelVoteLeader(sentinelRedisInstance *master, uint64_t req_epoch, char *req_runid, uint64_t *leader_epoch) {
    //發起選舉的哨兵紀元大于當前紀元,則修改當前紀元
    if (req_epoch > sentinel.current_epoch) {
        sentinel.current_epoch = req_epoch;
        sentinelFlushConfig();
        sentinelEvent(REDIS_WARNING,"+new-epoch",master,"%llu",
            (unsigned long long) sentinel.current_epoch);
    }
    //如果master紀元小于發起選舉的紀元且當前哨兵紀元小于等于發起選舉的紀元
    if (master->leader_epoch < req_epoch && sentinel.current_epoch <= req_epoch)
    {
        sdsfree(master->leader);
        //設置當前的master為candidate的runid
        master->leader = sdsnew(req_runid);
        //更新紀元
        master->leader_epoch = sentinel.current_epoch;
        sentinelFlushConfig();
        //投票給發起選舉的人
        sentinelEvent(REDIS_WARNING,"+vote-for-leader",master,"%s %llu",
            master->leader, (unsigned long long) master->leader_epoch);
        /* If we did not voted for ourselves, set the master failover start
         * time to now, in order to force a delay before we can start a
         * failover for the same master. */
        if (strcasecmp(master->leader,server.runid))
            master->failover_start_time = mstime()+rand()%SENTINEL_MAX_DESYNC;
    }

    *leader_epoch = master->leader_epoch;
    return master->leader ? sdsnew(master->leader) : NULL;
}

(5) 處理投票結果

收到響應后sentinelReceiveIsMasterDownReply回調函數就會解析出其他哨兵的leader_epoch 信息,作為后續選舉leader的依據,如果半數以上的leader_epoch 為當前哨兵所設置的run_id,則說明當前哨兵作為leader進行故障轉移:

void sentinelReceiveIsMasterDownReply(redisAsyncContext *c, void *reply, void *privdata) {
    sentinelRedisInstance *ri = c->data;
    redisReply *r;
    REDIS_NOTUSED(privdata);

    //......
        if (strcmp(r->element[1]->str,"*")) {//不為*則采集投票結果
           //......
            //基于返回結果更新當前哨兵維護的哨兵數組中leader的leader_epoch 信息(記錄的是作為leader的哨兵的run_id),作為后續選舉leader使用
            ri->leader = sdsnew(r->element[1]->str);
            ri->leader_epoch = r->element[2]->integer;
        }
    }
}
(6) 選舉出leader并廣播通告

最后基于狀態機模式,根據當前master狀態為SENTINEL_FAILOVER_STATE_WAIT_START于是調用sentinelFailoverWaitStart選舉leader

void sentinelFailoverStateMachine(sentinelRedisInstance *ri) {
    redisAssert(ri->flags & SRI_MASTER);

    if (!(ri->flags & SRI_FAILOVER_IN_PROGRESS)) return;

    switch(ri->failover_state) {
        //如果狀態為SENTINEL_FAILOVER_STATE_WAIT_START,則調用sentinelFailoverWaitStart選舉出leader
        case SENTINEL_FAILOVER_STATE_WAIT_START:
            sentinelFailoverWaitStart(ri);
            break;
       //......
    }
}

步入sentinelFailoverWaitStart即可看到該方法調用sentinelGetLeader,如果發現是自己則發送廣播告知自己為leader進行故障轉移:

void sentinelFailoverWaitStart(sentinelRedisInstance *ri) {
   //......
    //獲取leader
    leader = sentinelGetLeader(ri, ri->failover_epoch);
    isleader = leader && strcasecmp(leader,server.runid) == 0;
    sdsfree(leader);

    //......
    //告知當選的leader是自己
    sentinelEvent(REDIS_WARNING,"+elected-leader",ri,"%@");
    ri->failover_state = SENTINEL_FAILOVER_STATE_SELECT_SLAVE;
    ri->failover_state_change_time = mstime();
    sentinelEvent(REDIS_WARNING,"+failover-state-select-slave",ri,"%@");
}

對此我們也給出選舉哨兵leader的核心方法sentinelGetLeader,核心步驟為:

  • 如果投票結果給出的leader值不為空(這個leader記錄的是其他哨兵投票的實例的run_id)且紀元和當前選舉紀元一致,則給對應的leader票數+1。
  • 將這個投票結果存入counter這個字典中。
  • 遍歷counter如果這個值大于配置的quorum或哨兵的半數以上,則將其設置為winner,即最后的leader,由此讓這個leader哨兵進行故障轉移:

對應的我們也給出這段代碼的實現:

char *sentinelGetLeader(sentinelRedisInstance *master, uint64_t epoch) {
  //......
   //設置voters 為哨兵數+1
    voters = dictSize(master->sentinels)+1; /* All the other sentinels and me. */

 /* Count other sentinels votes */
    //根據紀元遍歷其他哨兵的選票結果
    di = dictGetIterator(master->sentinels);
    while((de = dictNext(di)) != NULL) {
        sentinelRedisInstance *ri = dictGetVal(de);
        //如果其他哨兵投票的leader值不為空,且紀元和當前投票紀元一致,則給這個leader的對應的run_id對應的投票數做個自增
        if (ri->leader != NULL && ri->leader_epoch == sentinel.current_epoch)
            sentinelLeaderIncr(counters,ri->leader);
    }

//......
//找到得票最多的
    di = dictGetIterator(counters);
    while((de = dictNext(di)) != NULL) {
        uint64_t votes = dictGetUnsignedIntegerVal(de);

        if (votes > max_votes) {
            max_votes = votes;
            winner = dictGetKey(de);
        }
    }
    dictReleaseIterator(di);

   //......
   
   //如果票數大于一半+1或大于配置的quorum則設置為leader
    voters_quorum = voters/2+1;
    if (winner && (max_votes < voters_quorum || max_votes < master->quorum))
        winner = NULL;

    winner = winner ? sdsnew(winner) : NULL;
    //......
    return winner;
}

小結

自此我們來小結一下哨兵選舉與故障轉移的大體過程:

  • 當前哨兵主觀認定下線之后,通過異步連接詢問其它哨兵是否客觀認定master下線。
  • 超過半數的哨兵認為下線則當前哨兵就認為master下線于是開啟發起投票選舉。
  • 更新自己的紀元并攜帶runid到其它哨兵節點上拉票。
  • 基于回調函數獲取其它哨兵選票結果進行遍歷匯總,用以一個字典以哨兵runid為key,投票值為value進行維護。
  • 匯總后通知全局哨兵leader。
  • leader進行故障轉移。
責任編輯:趙寧寧 來源: 寫代碼的SharkChili
相關推薦

2025-02-17 11:07:10

2020-04-21 22:59:50

Redis搭建選舉

2022-05-17 22:20:41

哨兵Redis機制

2018-11-01 14:50:01

RedisNoSQL數據庫

2025-02-25 09:29:34

2025-03-20 09:54:47

2009-02-03 17:50:03

服務器虛擬化VMware

2025-05-22 08:15:00

2012-07-03 11:38:32

FacebookHadoop

2019-12-05 10:00:03

架構Redis服務器

2015-07-23 13:43:43

vSphereHA虛擬化

2011-05-26 13:07:29

數據庫切換故障轉移

2022-07-06 13:48:24

RedisSentinel機制

2024-07-16 08:38:06

2024-12-09 00:00:09

2023-12-01 08:49:29

哨兵模式自動恢復

2023-04-09 19:54:52

2024-04-29 08:06:19

Redis分布式系統

2023-03-15 08:30:37

2023-05-26 08:24:17

短信渠道模型
點贊
收藏

51CTO技術棧公眾號

亚洲人成网在线播放| 亚洲乱码一区二区三区在线观看| 青青草原一区二区| 手机看片日韩av| 国产一区 二区| 亚洲1区2区3区视频| 日韩不卡av| www.av导航| 久久一区中文字幕| 日韩中文字幕亚洲| 中文字幕日韩三级片| 男女啪啪999亚洲精品| 亚洲一级电影视频| 亚洲国产精品毛片| 天天爱天天干天天操| 久久精品国产久精国产| 国产做受69高潮| 色婷婷粉嫩av| 欧美偷窥清纯综合图区| 欧美一区日韩一区| 可以免费在线看黄的网站| 免费观看成人高潮| 国产无一区二区| 99精品在线直播| aaa在线视频| 欧美网站在线| 色偷偷9999www| 51妺嘿嘿午夜福利| 亚洲va久久久噜噜噜久久| 日韩一区二区三区四区五区六区 | 西西人体44www大胆无码| 精一区二区三区| 日韩美女激情视频| 六月丁香在线视频| 午夜日韩av| 丝袜美腿精品国产二区| 成年人在线观看av| 久久久久影视| 欧美成人a∨高清免费观看| 亚洲综合日韩欧美| 久久久一本精品| 无吗不卡中文字幕| 国产肉体ⅹxxx137大胆| 国产原创精品视频| 国产精品短视频| 午夜免费电影一区在线观看| 日本福利午夜视频在线| 波多野结衣中文字幕一区| 97自拍视频| 国产农村妇女毛片精品| 看国产成人h片视频| 国产精品h在线观看| 国产精品自拍99| 亚洲精品123区| 久久久久女教师免费一区| 91高清免费观看| 久久香蕉国产| www.美女亚洲精品| 91嫩草丨国产丨精品| 91影院成人| 日韩中文字幕在线播放| 制服丨自拍丨欧美丨动漫丨| 色综合天天综合网中文字幕| 色噜噜狠狠狠综合曰曰曰| 五月激情四射婷婷| 欧美第十八页| 久久综合久中文字幕青草| 69夜色精品国产69乱| 中文字幕免费精品| 久久91亚洲精品中文字幕奶水| 久久国产精品国语对白| 欧美成熟视频| 久久久之久亚州精品露出| 国产主播在线播放| 亚洲一区激情| 日本免费一区二区三区视频观看| 人人妻人人爽人人澡人人精品| 天堂蜜桃一区二区三区| 国产精品麻豆va在线播放| 中文字幕在线一| 精品一区二区综合| 99三级在线| 欧洲免费在线视频| 国产精品理论片在线观看| 成人在线免费观看网址| av第一福利在线导航| 一本色道亚洲精品aⅴ| 亚洲污视频在线观看| 国产日韩一区二区三免费高清| 精品久久99ma| 亚洲人成人无码网www国产 | 亚洲女人被黑人巨大进入al| 欧洲美熟女乱又伦| 午夜久久黄色| 青青久久av北条麻妃海外网| 一区二区三区播放| 粉嫩在线一区二区三区视频| 久久婷婷开心| 麻豆网站在线看| 五月天激情综合| 中文字幕第38页| 大奶一区二区三区| 国产亚洲精品激情久久| 可以直接看的黄色网址| 香蕉久久国产| 不卡视频一区二区三区| 国产综合在线观看| 亚洲精品国产精华液| 久久久久久久久久久免费视频| 色综合视频一区二区三区日韩| 精品国产精品一区二区夜夜嗨| 男人的天堂av网| 欧美久久视频| 国产精品自拍网| 视频在线不卡| 亚洲综合在线观看视频| 搡女人真爽免费午夜网站| 国产调教精品| 久久精品影视伊人网| 日韩视频在线观看一区| 高清成人免费视频| 亚洲午夜高清视频| 精品91久久| 欧美精品一区二区不卡| 神马久久精品综合| 免费日本视频一区| 久久久久资源| 俺来俺也去www色在线观看| 欧美三级资源在线| 97超碰在线资源| 亚洲国产日本| 99中文视频在线| 日本中文字幕在线播放| 日本丰满少妇一区二区三区| 日韩精品人妻中文字幕有码| 亚洲国产老妈| 国产精品自拍偷拍视频| 搞黄视频免费在线观看| 欧美性xxxx极品hd欧美风情| 久久久久久婷婷| 欧美在线1区| 国产免费一区二区三区在线能观看| 日韩资源在线| 精品日本美女福利在线观看| 日韩精品国产一区| 欧美理论在线| 97视频热人人精品| 日本性爱视频在线观看| 欧美一级高清片| 久久中文免费视频| 国内精品在线播放| 特级黄色录像片| 国产乱码精品一区二区三区亚洲人| 最新国产精品亚洲| 伊人亚洲综合网| 国产精品国产三级国产aⅴ入口| 欧美视频第三页| 色综合中文网| 国产欧美va欧美va香蕉在线| 最新97超碰在线| 欧美日韩一区二区三区高清| 国产一二三四视频| 精品无人区卡一卡二卡三乱码免费卡 | 免费看日b视频| 精品国产麻豆| 欧美激情第6页| 无码国产伦一区二区三区视频| 午夜国产精品一区| 无码人妻精品一区二区三应用大全| 国产欧美一区二区三区国产幕精品| 久久偷看各类wc女厕嘘嘘偷窃| av日韩电影| 中文字幕亚洲精品| 一区二区精品视频在线观看| 一区二区三区日韩| www男人天堂| 国产精品人人爽人人做我的可爱| 蜜桃狠狠色伊人亚洲综合网站| 视频在线日韩| 俺去啦;欧美日韩| 成人h动漫精品一区二区无码| 亚洲国产美国国产综合一区二区| 国产成人无码一区二区在线观看| 免费看亚洲片| 一区二区三区视频在线播放| 日韩中文一区二区| 5278欧美一区二区三区| eeuss影院www在线播放| 日韩一区二区电影在线| 中文字幕精品无码一区二区| 国产精品国产三级国产有无不卡| 中文字幕在线播放一区二区| 国产精品一区毛片| 亚洲一区二区在| 另类春色校园亚洲| 国产欧美精品在线播放| 97蜜桃久久| 中文字幕一精品亚洲无线一区 | 久久国产精品波多野结衣| 91丨porny丨蝌蚪视频| 一区二区三区免费播放| 欧美深夜福利| 色狠狠久久av五月综合|| 午夜精品在线| 国产成人综合一区二区三区| 亚洲wwwww| 中文字幕精品av| 免费观看国产视频| 欧美精选午夜久久久乱码6080| 亚洲激情视频一区| 国产精品第13页| 30一40一50老女人毛片| 国产黄色91视频| 91看片就是不一样| 欧美精品色网| 天天爽天天狠久久久| 国产一区二区三区不卡av| 国产中文字幕91| 黄色成人免费网| 高清欧美性猛交| 国内外激情在线| 亚洲欧美在线一区二区| 亚洲AV无码成人片在线观看 | 日韩精品免费一区二区三区竹菊 | 开心久久婷婷综合中文字幕| 免费电影一区二区三区| 久久久久国产精品一区| 香蕉视频国产在线观看| 国产视频一区在线| 男人天堂手机在线观看| 7777精品伊人久久久大香线蕉 | 91视频综合| 日本一区高清不卡| 日本韩国欧美超级黄在线观看| 91精品国产一区二区三区动漫| 国产综合色在线观看| 日本久久中文字幕| 伊人久久av| 992tv成人免费视频| 俄罗斯一级**毛片在线播放 | 婷婷激情四射网| 国产精品视频免费看| 久久美女免费视频| 久久精品日产第一区二区三区高清版| 久久久久久久人妻无码中文字幕爆| 国产老女人精品毛片久久| 亚洲欧美天堂在线| 激情欧美一区二区三区在线观看| 超碰在线97免费| 免费人成在线不卡| 亚洲视频一二三四| 久久精品国产网站| 97超碰成人在线| 久久www免费人成看片高清| 欧美伦理片在线观看| 日av在线不卡| 日本中文字幕二区| 狠狠v欧美v日韩v亚洲ⅴ| 亚洲精品国产一区二区三区| 精品一区二区影视| 视频区 图片区 小说区| 国产馆精品极品| 丰满少妇xbxb毛片日本| 99久久伊人久久99| 无码人妻aⅴ一区二区三区| 2023国产一二三区日本精品2022| 亚洲精品视频大全| 久久久777精品电影网影网| 国产美女免费网站| 国产精品久久久久影院老司| 成人免费精品动漫网站| 亚洲一卡二卡三卡四卡| 成人免费a视频| 欧美撒尿777hd撒尿| 国产又粗又猛又爽又黄的视频一| 6080午夜不卡| 日韩一级免费毛片| 亚洲欧美国产精品| 欧美高清视频| 欧美激情精品久久久久久| 日本在线啊啊| 国产精品香蕉国产| 91午夜精品| 欧美尤物一区| 91国语精品自产拍| 九一国产精品视频| 日韩激情一二三区| 在线成人精品视频| 国产亚洲综合在线| 国产av无码专区亚洲av毛网站| 亚洲第一主播视频| 中文字幕人妻一区二区三区视频| 日韩精品中文字幕在线一区| 日本福利午夜视频在线| 久久天天躁日日躁| 三级中文字幕在线观看| 成人激情视频在线观看| 麻豆一区二区| 伊人av成人| 国产精品入口| 色婷婷一区二区三区在线观看| www.成人网.com| 精品日韩在线视频| 午夜国产精品一区| 国产精品无码天天爽视频| 日韩av在线免费看| 黄色在线免费| 日韩免费黄色av| h视频久久久| 亚洲日本精品一区| 99这里有精品| 肉色超薄丝袜脚交| 国产亚洲成av人在线观看导航| 午夜69成人做爰视频| 欧美一a一片一级一片| 亚洲精品字幕在线观看| 日韩一级裸体免费视频| 波多野结衣亚洲| 成人三级在线| 五月婷婷亚洲| 亚洲综合色在线观看| 2023国产一二三区日本精品2022| 久草中文在线视频| 欧美精品v日韩精品v韩国精品v| 丝袜视频国产在线播放| 久久久久久91| 18国产精品| 欧美日韩视频免费在线观看| 日本视频在线一区| 无码人妻精品一区二区三应用大全| 一区二区三区成人| 国产欧美综合视频| 色妞色视频一区二区三区四区| 中文字幕在线直播| 国产伦精品一区二区三区高清| 亚洲美女视频| 国产精品嫩草影院8vv8 | 日韩欧美中文字幕制服| 日本不卡在线| 国产一区二区在线免费| 欧美日韩久久精品| 国产美女三级视频| aaa欧美色吧激情视频| 国产精品成人久久| 日韩精品专区在线| gratisvideos另类灌满| 国产精品乱子乱xxxx| 激情亚洲成人| 成人区人妻精品一区二| 亚洲电影在线播放| 五月婷婷丁香花| 欧美与欧洲交xxxx免费观看| 偷拍自拍亚洲色图| 成年人免费在线播放| 久久久精品影视| 欧美黄色一级大片| 国产亚洲精品美女久久久| 亚洲图片第一页| 日韩成人av影视| 我想看黄色大片| 欧美日韩另类一区| 精品视频在线一区二区| 欧美成人h版在线观看| 女人十八岁毛片| 欧美精品一区二区三区在线 | 欧美成人午夜77777| 国产精品久久久久9999爆乳| 成人av电影在线| 欧美日韩精品区| 亚洲人成网在线播放| 成人日韩av| 91九色国产ts另类人妖| 福利一区二区在线观看| 日韩大片免费在线观看| 日韩毛片在线观看| 久草综合在线| 日韩不卡视频一区二区| 成人av网站在线观看免费| 久久午夜免费视频| 日日骚久久av| 日韩一区网站| 日本wwww视频| 中文字幕在线不卡| 性一交一乱一乱一视频| 欧美亚洲一级片| 久久国产成人精品| 亚洲国产精品第一页| 欧美午夜电影在线| 久久77777| 精品国产_亚洲人成在线| 日韩成人一级大片| 麻豆chinese极品少妇| 日韩精品免费一线在线观看| 亚洲国产尤物| 91精品国产吴梦梦| 国产三级精品在线| www.色亚洲| 国产成人精品免高潮费视频| 欧美在线影院| 在线观看国产精品一区|