Sender发送条件

发送条件:
1)full: 如果一个批次写满了(无论时间有没有到)
2)expired:时间到了(批次没写满也得发送)
3)exhausted:内存不够(消息发送出去以后,就会释放内存)
4)closed : kafka producer 关闭前先将缓存的数据发送

this.accumulator.ready

    public ReadyCheckResult ready(Cluster cluster, long nowMs) {
    
    
        Set<Node> readyNodes = new HashSet<>();
        long nextReadyCheckDelayMs = Long.MAX_VALUE;
        Set<String> unknownLeaderTopics = new HashSet<>();

        //waiters里面有数据,说明我们的这个内存池里面内存不够了。
        //如果exhausted的值等于true,说明内存池里面的内存不够用了。
        boolean exhausted = this.free.queued() > 0;

        //遍历所有的分区
        for (Map.Entry<TopicPartition, Deque<RecordBatch>> entry : this.batches.entrySet()) {
    
    
            //获取到分区
            TopicPartition part = entry.getKey();
            //获取到分区对应的队列
            Deque<RecordBatch> deque = entry.getValue();
            //根据分区 可以获取到这个分区的leader partition在哪一台kafka的主机上面。
            Node leader = cluster.leaderFor(part);
            synchronized (deque) {
    
    
                //如果没有找到对应主机。 unknownLeaderTopics
                if (leader == null && !deque.isEmpty()) {
    
    
                    // This is a partition for which leader is not known, but messages are available to send.
                    // Note that entries are currently not removed from batches when deque is empty.
                    unknownLeaderTopics.add(part.topic());
                } else if (!readyNodes.contains(leader) && !muted.contains(part)) {
    
    
                    //首先从队列的队头获取到批次
                    RecordBatch batch = deque.peekFirst();
                    //如果这个batch不null,我们判断一下是否可以发送这个批次。
                    if (batch != null) {
    
    
                        /**
                         * 解析来就判断这个批次是否符合发送出去的条件
                         */
                        /**
                         * batch.attempts:重试的次数
                         * batch.lastAttemptMs:上一次重试的时间
                         * retryBackoffMs:重试的时间间隔
                         *
                         * backingOff:重新发送数据的时间到了
                         *
                         * 但是,如果我们用的是场景驱动的方式,那很明显我们是第一次发送消息
                         * 肯定还没有到重试到地步。
                         */
                        boolean backingOff = batch.attempts > 0 && batch.lastAttemptMs + retryBackoffMs > nowMs;
                        /**
                         * nowMs: 当前时间
                         * batch.lastAttemptMs: 上一次重试的时间。
                         * waitedTimeMs=这个批次已经等了多久了。
                         */
                        long waitedTimeMs = nowMs - batch.lastAttemptMs;
                        /**
                         * 但是我们用场景驱动的方式去分析,因为我们第一次发送数据。
                         * 所以之前也没有消息发送出去过,也就没有重试这一说。
                         *
                         * timeToWaitMs =lingerMs
                         * lingerMs
                         * 这个值默认是0,如果这个值默认是0 的话,那代表着来一条消息
                         * 就发送一条消息,那很明显是不合适的。
                         * 所以我们发送数据的时候,大家一定要记得去配置这个参数。
                         * 假设我们配置的是100ms
                         * timeToWaitMs = linerMs = 100ms
                         * 消息最多存多久就必须要发送出去了。
                         */
                        long timeToWaitMs = backingOff ? retryBackoffMs : lingerMs;
                        /**
                         * timeToWaitMs: 最多能等待多久
                         * waitedTimeMs: 已经等待了多久
                         * timeLeftMs: 还要在等待多久
                         */
                        long timeLeftMs = Math.max(timeToWaitMs - waitedTimeMs, 0);
                        /**
                         *如果队列大于一,说明这个队列里面至少有一个批次肯定是写满了
                         * 如果批次写满了肯定是可以发送数据了。
                         *当然也有可能就是这个队列里面只有一个批次,然后刚好这个批次
                         * 写满了,也可以发送数据。
                         *
                         * full:是否有写满的批次
                         */
                        boolean full = deque.size() > 1 || batch.records.isFull();
                        /**
                         * waitedTimeMs:已经等待了多久
                         * timeToWaitMs:最多需要等待多久
                         * expired: 时间到了,到了发送消息的时候了
                         * 如果expired=true 代表就是时间到了,到了发送消息的时候了
                         */
                        boolean expired = waitedTimeMs >= timeToWaitMs;
                        /**
                         * 1)full: 如果一个批次写满了(无论时间有没有到)
                         * 2)expired:时间到了(批次没写满也得发送)
                         * 3)exhausted:内存不够(消息发送出去以后,就会释放内存)
                         */
                        boolean sendable = full || expired || exhausted || closed || flushInProgress();
                        //可以发送消息
                        if (sendable && !backingOff) {
    
    
                            //把可以发送【批次】的Partition的leader partition所在的主机加入到
                            //readyNodes
                            readyNodes.add(leader);
                        } else {
    
    
                            // Note that this results in a conservative estimate since an un-sendable partition may have
                            // a leader that will later be found to have sendable data. However, this is good enough
                            // since we'll just wake up and then sleep again for the remaining time.
                            nextReadyCheckDelayMs = Math.min(timeLeftMs, nextReadyCheckDelayMs);
                        }
                    }
                }
            }
        }

        return new ReadyCheckResult(readyNodes, nextReadyCheckDelayMs, unknownLeaderTopics);
    }

猜你喜欢

转载自blog.csdn.net/m0_46449152/article/details/114907708