clusterCron 处理流程

轮训各个节点看是否节点可用

while((de = dictNext(di)) != NULL) {
clusterNode *node = dictGetVal(de);

    if (node->flags & (REDIS_NODE_MYSELF|REDIS_NODE_NOADDR)) continue;

    /* A Node in HANDSHAKE state has a limited lifespan equal to the
     * configured node timeout. */
    if (nodeInHandshake(node) && now - node->ctime > handshake_timeout) {
        clusterDelNode(node);
        continue;
    }

    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);
        if (fd == -1) {
            /* We got a synchronous error from connect before
             * clusterSendPing() had a chance to be called.
             * If node->ping_sent is zero, failure detection can't work,
             * so we claim we actually sent a ping now (that will
             * be really sent as soon as the link is obtained). */
            if (node->ping_sent == 0) node->ping_sent = mstime();
            redisLog(REDIS_DEBUG, "Unable to connect to "
                "Cluster Node [%s]:%d -> %s", node->ip,
                node->port+REDIS_CLUSTER_PORT_INCR,
                server.neterr);
            continue;
        }
        link = createClusterLink(node);
        link->fd = fd;
        node->link = link;

        printf("yyyyyyyyyy cluster cron create fd  %d   port %d\n", fd, node->port + REDIS_CLUSTER_PORT_INCR);
        aeCreateFileEvent(server.el,link->fd,AE_READABLE,
                clusterReadHandler,link);
        /* Queue a PING in the new connection ASAP: this is crucial
         * to avoid false positives in failure detection.
         *
         * If the node is flagged as MEET, we send a MEET message instead
         * of a PING one, to force the receiver to add us in its node
         * table. */
        old_ping_sent = node->ping_sent;
        clusterSendPing(link, node->flags & REDIS_NODE_MEET ?
                CLUSTERMSG_TYPE_MEET : CLUSTERMSG_TYPE_PING);
        if (old_ping_sent) {
            /* If there was an active ping before the link was
             * disconnected, we want to restore the ping time, otherwise
             * replaced by the clusterSendPing() call. */
            node->ping_sent = old_ping_sent;
        }
        /* We can clear the flag after the first packet is sent.
         * If we'll never receive a PONG, we'll never send new packets
         * to this node. Instead after the PONG is received and we
         * are no longer in meet/handshake status, we want to send
         * normal PING packets. */
        node->flags &= ~REDIS_NODE_MEET;

        redisLog(REDIS_DEBUG,"Connecting with Node %.40s at %s:%d",
                node->name, node->ip, node->port+REDIS_CLUSTER_PORT_INCR);
    }
}
dictReleaseIterator(di);

随机找10个槽点进行测试 判断情况

if (!(iteration % 10)) {
int j;

    /* Check a few random nodes and ping the one with the oldest
     * pong_received time. */
    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;
        if (min_pong_node == NULL || min_pong > this->pong_received) {
            min_pong_node = this;
            min_pong = this->pong_received;
        }
    }
    if (min_pong_node) {
        redisLog(REDIS_DEBUG,"Pinging node %.40s", min_pong_node->name);
        clusterSendPing(min_pong_node->link, CLUSTERMSG_TYPE_PING);
    }
}

3

1 查询是否有孤儿master
2 计算一个master 最大的slaves数量
3 如果是slave计算当前 master最大的slaves
4 同时进行状态检查 ping的发送 ,删除link的操作
orphaned_masters = 0;
max_slaves = 0;
this_slaves = 0;
di = dictGetSafeIterator(server.cluster->nodes);
while((de = dictNext(di)) != NULL) {
clusterNode *node = dictGetVal(de);
now = mstime(); /* Use an updated time at every iteration. */
mstime_t delay;

    if (node->flags &
        (REDIS_NODE_MYSELF|REDIS_NODE_NOADDR|REDIS_NODE_HANDSHAKE))
            continue;

    /* Orphaned master check, useful only if the current instance
     * is a slave that may migrate to another master. */
    if (nodeIsSlave(myself) && nodeIsMaster(node) && !nodeFailed(node)) {
        int okslaves = clusterCountNonFailingSlaves(node);

        /* A master is orphaned if it is serving a non-zero number of
         * slots, have no working slaves, but used to have at least one
         * slave. */
        if (okslaves == 0 && node->numslots > 0 && node->numslaves)
            orphaned_masters++;
        if (okslaves > max_slaves) max_slaves = okslaves;
        if (nodeIsSlave(myself) && myself->slaveof == node)
            this_slaves = okslaves;
    }

    /* If we are waiting for the PONG more than half the cluster
     * timeout, reconnect the link: maybe there is a connection
     * issue even if the node is alive. */
    if (node->link && /* is connected */
        now - node->link->ctime >
        server.cluster_node_timeout && /* was not already reconnected */
        node->ping_sent && /* we already sent a ping */
        node->pong_received < node->ping_sent && /* still waiting pong */
        /* and we are waiting for the pong more than timeout/2 */
        now - node->ping_sent > server.cluster_node_timeout/2)
    {
        /* Disconnect the link, it will be reconnected automatically. */
        freeClusterLink(node->link);
    }

    /* If we have currently no active ping in this instance, and the
     * received PONG is older than half the cluster timeout, send
     * a new ping now, to ensure all the nodes are pinged without
     * a too big delay. */
    if (node->link &&
        node->ping_sent == 0 &&
        (now - node->pong_received) > server.cluster_node_timeout/2)
    {
        clusterSendPing(node->link, CLUSTERMSG_TYPE_PING);
        continue;
    }

    /* If we are a master and one of the slaves requested a manual
     * failover, ping it continuously. */
    if (server.cluster->mf_end &&
        nodeIsMaster(myself) &&
        server.cluster->mf_slave == node &&
        node->link)
    {
        clusterSendPing(node->link, CLUSTERMSG_TYPE_PING);
        continue;
    }

    /* Check only if we have an active ping for this instance. */
    if (node->ping_sent == 0) continue;

    /* Compute the delay of the PONG. Note that if we already received
     * the PONG, then node->ping_sent is zero, so can't reach this
     * code at all. */
    delay = now - node->ping_sent;

    if (delay > server.cluster_node_timeout) {
        /* Timeout reached. Set the node as possibly failing if it is
         * not already in this state. */
        if (!(node->flags & (REDIS_NODE_PFAIL|REDIS_NODE_FAIL))) {
            redisLog(REDIS_DEBUG,"*** NODE %.40s possibly failing",
                node->name);
            node->flags |= REDIS_NODE_PFAIL;
            update_state = 1;
        }
    }
}

4 一个salve 复制中断确保再次连接master

if (nodeIsSlave(myself) &&
server.masterhost == NULL &&
myself->slaveof &&
nodeHasAddr(myself->slaveof))
{
replicationSetMaster(myself->slaveof->ip, myself->slaveof->port);
}

5 孤儿master检查和node状态检查

/* Abourt a manual failover if the timeout is reached. */
manualFailoverCheckTimeout();

if (nodeIsSlave(myself)) {
    clusterHandleManualFailover();
    clusterHandleSlaveFailover();
    /* If there are orphaned slaves, and we are a slave among the masters
     * with the max number of non-failing slaves, consider migrating to
     * the orphaned masters. Note that it does not make sense to try
     * a migration if there is no master with at least *two* working
     * slaves. */
    if (orphaned_masters && max_slaves >= 2 && this_slaves == max_slaves)
        clusterHandleSlaveMigration(max_slaves);
}

if (update_state || server.cluster->state == REDIS_CLUSTER_FAIL)
    clusterUpdateState();
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值