成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Redis 集群中如何處理非本節(jié)點(diǎn)的 slot

數(shù)據(jù)庫(kù) Redis
這篇文章就來(lái)聊聊當(dāng)某個(gè)節(jié)點(diǎn)處理到非它所負(fù)責(zé)的slot時(shí)是如何處理的,這一點(diǎn)很好的體現(xiàn)了redis對(duì)于raft協(xié)議良好的設(shè)計(jì)與實(shí)現(xiàn)。

我們都知道redis集群有16384個(gè)槽,它會(huì)因?yàn)槲覀兗簜€(gè)數(shù)配置的不同而分配不同的slot給各個(gè)節(jié)點(diǎn),而這篇文章就來(lái)聊聊當(dāng)某個(gè)節(jié)點(diǎn)處理到非它所負(fù)責(zé)的slot時(shí)是如何處理的,這一點(diǎn)很好的體現(xiàn)了redis對(duì)于raft協(xié)議良好的設(shè)計(jì)與實(shí)現(xiàn)。

一、詳解redis集群指令處理

1. 整體流程

假設(shè)我們現(xiàn)在集群中有個(gè)節(jié)點(diǎn),每個(gè)節(jié)點(diǎn)各自負(fù)責(zé)一部分槽,此時(shí)我們的客戶端向節(jié)點(diǎn)2發(fā)起一個(gè)set指令,而該指令對(duì)應(yīng)的key應(yīng)該是要存放到節(jié)點(diǎn)1中,對(duì)此節(jié)點(diǎn)2的做法是查看自己所維護(hù)的節(jié)點(diǎn)列表是否有負(fù)責(zé)該slot的節(jié)點(diǎn),如果發(fā)現(xiàn)了而回復(fù)給客戶端move指令,告知客戶端到指令的ip端口的節(jié)點(diǎn)進(jìn)行鍵值對(duì)存儲(chǔ):

了解完整體流程之后,我們通過(guò)源碼的方式來(lái)印證這些實(shí)現(xiàn)上的細(xì)節(jié),我們都知道redis客戶端發(fā)送的指令都會(huì)被redis的processCommand處理,該函數(shù)如果發(fā)現(xiàn)當(dāng)前是以集群的方式啟動(dòng)并且符合以下兩個(gè)條件則以集群的邏輯解析這條指令:

  • 發(fā)送指令的不是master服務(wù)器。
  • 參數(shù)中帶有key。

那么redis就會(huì)調(diào)用getNodeByQuery查詢重定向的節(jié)點(diǎn),如果發(fā)現(xiàn)查詢到的節(jié)點(diǎn)不是自己或者為空則調(diào)用clusterRedirectClient進(jìn)行重定向處理:

int processCommand(redisClient *c) {
    //......
    //如果開(kāi)啟了集群,且發(fā)送者不是master且參數(shù)帶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;
            //查找可以處理的節(jié)點(diǎn)
            clusterNode *n = getNodeByQuery(c,c->cmd,c->argv,c->argc,&hashslot,&error_code);
            //如果為空且或者非自己,則調(diào)用clusterRedirectClient進(jìn)行重定向
            if (n == NULL || n != server.cluster->myself) {
                flagTransaction(c);
                clusterRedirectClient(c,n,hashslot,error_code);
                return REDIS_OK;
            }
        }
    }

   //......
   //處理當(dāng)前請(qǐng)求指令并返回
}

2. 詳解節(jié)點(diǎn)定位步驟getNodeByQuery

步入getNodeByQuery即可看到查詢的核心流程,無(wú)論是單條還是多條客戶端指令,他都會(huì)封裝成multiState結(jié)構(gòu)體交由后續(xù)邏輯處理,而后續(xù)邏輯就會(huì)遍歷這些指令并計(jì)算出對(duì)應(yīng)的slot,然后執(zhí)行如下邏輯:

  • 如果發(fā)現(xiàn)定位到的節(jié)點(diǎn)是自己,且當(dāng)前節(jié)點(diǎn)正在做遷移,則做個(gè)遷移標(biāo)記,然后檢查當(dāng)前節(jié)點(diǎn)是否有這個(gè)槽,如果沒(méi)有則發(fā)送ASK指令告知客戶端重定向到另一個(gè)遷移的目標(biāo)槽試試看。
  • 如果對(duì)應(yīng)的key沒(méi)有找到對(duì)應(yīng)的槽,則直接返回當(dāng)前節(jié)點(diǎn)。
  • 找到目標(biāo)槽,直接返回MOVE指令和目標(biāo)槽的信息。

對(duì)應(yīng)我們給出getNodeByQuery的核心代碼段:

clusterNode *getNodeByQuery(redisClient *c, struct redisCommand *cmd, robj **argv, int argc, int *hashslot, int *error_code) {
    //......
    //如果是exec命令則用客戶端的multiState封裝這些命令
    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 {
       //如果不是exec則自己創(chuàng)建一個(gè)multiState封裝這單條指令保證后續(xù)邏輯一致
        ms = &_ms;
        _ms.commands = &mc;
        //命令個(gè)數(shù)1
        _ms.count = 1;
        //命令參數(shù)
        mc.argv = argv;
        //命令參數(shù)個(gè)數(shù)
        mc.argc = argc;
        //對(duì)應(yīng)的命令
        mc.cmd = cmd;
    }

    
    //遍歷multiState中的命令
    for (i = 0; i < ms->count; i++) {
        struct redisCommand *mcmd;
        robj **margv;
        int margc, *keyindex, numkeys, j;
  //解析出命令、參數(shù)個(gè)數(shù)、參數(shù)
        mcmd = ms->commands[i].cmd;
        margc = ms->commands[i].argc;
        margv = ms->commands[i].argv;
        //解析出key以及個(gè)數(shù)
        keyindex = getKeysFromCommand(mcmd,margv,margc,&numkeys);
        for (j = 0; j < numkeys; j++) {
            //拿到key
            robj *thiskey = margv[keyindex[j]];
            //計(jì)算slot
            int thisslot = keyHashSlot((char*)thiskey->ptr,
                                       sdslen(thiskey->ptr));

            if (firstkey == NULL) {
             
                firstkey = thiskey;
                slot = thisslot;
                //拿著計(jì)算的slot定位到對(duì)應(yīng)的節(jié)點(diǎn)
                n = server.cluster->slots[slot];

                
                //如果定位到的節(jié)點(diǎn)就是當(dāng)前節(jié)點(diǎn)正在做遷出或者遷入,則migrating_slot/importing_slot設(shè)置為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 {
               //......
            }

           
            //如果正在做遷出或者嵌入,且當(dāng)前找不到當(dāng)前db找不到key的位置,則missing_keys++意為某個(gè)key可能正在被遷移中所以沒(méi)有命中
            if ((migrating_slot || importing_slot) &&
                lookupKeyRead(&server.db[0],thiskey) == NULL)
            {
                missing_keys++;
            }
        }
        getKeysFreeResult(keyindex);
    }

   
    //所有key都沒(méi)有對(duì)應(yīng)節(jié)點(diǎn),直接返回當(dāng)前節(jié)點(diǎn)
    if (n == NULL) return myself;

    //......
    //正在遷出且這個(gè)key在當(dāng)前節(jié)點(diǎn)沒(méi)有被命中,則將error_code設(shè)置為ask,并返回遷出的節(jié)點(diǎn)信息,告知客戶端到返回節(jié)點(diǎn)嘗試指令
    if (migrating_slot && missing_keys) {
        if (error_code) *error_code = REDIS_CLUSTER_REDIR_ASK;
        return server.cluster->migrating_slots_to[slot];
    }

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

3. 結(jié)果告知客戶端

上述流程發(fā)現(xiàn)處理的節(jié)點(diǎn)不是自己之后,調(diào)用clusterRedirectClient進(jìn)行重定向,如果是REDIS_CLUSTER_REDIR_MOVED則告知客戶端這些slot后續(xù)直接找重定向節(jié)點(diǎn)處理就好了,后續(xù)無(wú)需找自己。若是REDIS_CLUSTER_REDIR_ASK則說(shuō)明當(dāng)前節(jié)點(diǎn)正處于數(shù)據(jù)遷移到目標(biāo)節(jié)點(diǎn),你可以到遷移的節(jié)點(diǎn)進(jìn)行請(qǐng)求,后續(xù)再次發(fā)起請(qǐng)求是還是找當(dāng)前節(jié)點(diǎn)看看能否出去,如果不能在進(jìn)行重定向:

void clusterRedirectClient(redisClient *c, clusterNode *n, int hashslot, int error_code) {
    //......
    if(......){
    //......
    } else if (error_code == REDIS_CLUSTER_REDIR_MOVED ||
               error_code == REDIS_CLUSTER_REDIR_ASK)
    {
        //返回move命令告知要移動(dòng)到的節(jié)點(diǎn)后續(xù)直接到move的,如果是ask則返回正在遷往的節(jié)點(diǎn)地址,是臨時(shí)措施,下次客戶端還會(huì)找當(dāng)前節(jié)點(diǎn)
        addReplySds(c,sdscatprintf(sdsempty(),
            "-%s %d %s:%d\r\n",
            (error_code == REDIS_CLUSTER_REDIR_ASK) ? "ASK" : "MOVED",
            hashslot,n->ip,n->port));
    } else {
        redisPanic("getNodeByQuery() unknown error.");
    }
}

二、小結(jié)

這篇文章比較精簡(jiǎn),我們通過(guò)源碼的方式簡(jiǎn)單的剖析了去中心化的redis如何在不同節(jié)點(diǎn)處理不同槽的請(qǐng)求,大體過(guò)程比較簡(jiǎn)單:

  • 接收并處理客戶端傳入的key指令操作。
  • 通過(guò)getNodeByQuery獲取key對(duì)應(yīng)的slot所屬節(jié)點(diǎn)。
  • 如果是當(dāng)前節(jié)點(diǎn)的slot直接處理。
  • 如果不是則查看是否正在遷出,如果是則返回ask讓客戶端到別的節(jié)點(diǎn)試試看,反之進(jìn)入步驟5。
  • 如果定位的slot對(duì)應(yīng)的節(jié)點(diǎn)是別的節(jié)點(diǎn)則直接用move指令重定向客戶端,讓客戶端到另一個(gè)節(jié)點(diǎn)詢問(wèn)結(jié)果。
責(zé)任編輯:趙寧寧 來(lái)源: 寫(xiě)代碼的SharkChili
相關(guān)推薦

2024-09-11 20:05:56

2024-04-16 13:32:57

2024-12-25 10:24:31

2023-03-09 12:21:38

2018-11-21 12:27:21

JavaScript 貨幣值區(qū)域

2019-11-08 08:00:00

ASP .NETASP .NET Cocookie

2011-04-11 17:10:16

Oracle

2012-07-30 09:35:10

項(xiàng)目管理

2020-05-18 10:52:10

集群SessionRedis

2019-08-15 10:20:19

云計(jì)算技術(shù)安全

2013-03-20 11:01:37

Redis客戶端連接

2021-03-24 10:40:26

Python垃圾語(yǔ)言

2021-08-18 08:20:14

SQL除數(shù)統(tǒng)計(jì)

2011-01-21 16:27:43

NagiosSendmail

2022-08-08 13:45:12

Redis面試Hash

2019-12-23 10:20:12

Web圖片優(yōu)化前端

2017-10-26 08:43:18

JavaScript內(nèi)存處理

2021-03-01 07:31:53

消息支付高可用

2023-04-06 15:19:51

2014-11-10 10:52:33

Go語(yǔ)言
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 欧美日韩在线成人 | 中文字幕视频在线看5 | 亚洲一区中文字幕 | 天天精品综合 | 中文字幕免费 | 久久久久国产精品一区三寸 | 国产视频线观看永久免费 | 91久久国产综合久久 | 91免费在线看 | 久久精品二区 | 一级美国黄色片 | 91精品国产综合久久久久久 | 国产精品久久久久久妇女6080 | 在线观看视频一区 | 国产精品777一区二区 | 理论片午午伦夜理片影院 | 久久久久香蕉视频 | 国产免费一区二区 | 国产精品久久久久久久久久久久冷 | 国产精品欧美精品日韩精品 | 日本人做爰大片免费观看一老师 | 色又黄又爽网站www久久 | 天天成人综合网 | 精品国产鲁一鲁一区二区张丽 | 在线观看成年视频 | 成人网av | 91久久精品国产91久久性色tv | 日本在线黄色 | 久久久av | 日韩精品一区二区三区视频播放 | 国产成人免费视频网站高清观看视频 | 爱爱爱av| 四虎影视在线 | 精品国产免费一区二区三区五区 | 91欧美精品成人综合在线观看 | 国产成人jvid在线播放 | 亚洲三级在线 | 岛国av一区二区三区 | 欧美一级在线 | av在线一区二区三区 | 看片一区 |