我们数据都写入了缓冲区,那这里的数据不可能一直放在缓存里的,所以kafka有一个线程,叫做Sender,这个线程,会一直运行,查看缓冲区里的可以发送的消息,就会把他发出去,下面看看有几种场景可以发消息。
内存池不够
上一篇也提供,当申请的内存不足时,就会进入阻塞状态,这个阻塞状态是在waiters的deque里放入一个Condition对象,所以当waiters里有Condition对象的时候,说明此事内存池是不够的,此事就可以发送消息了。
批次写满
我们回忆一下上篇的内容,每个RecordBatch默认为16k,可能会有多个消息往一个RecordBatch写,当写满16k的时候,此时就具备了发送出去的条件。
所以Sender就会从元数据里拿到每一个topic+partition构成的TopicPartition,每一个TopicPartition又有一个Deque,从Deque里拿出已经写满的RecordBatch发出去。
这里有个比较重要的是,每次都只检查deque里的第一个RecordBatch,只要他满了,就可以开始发送。
时间到了
如果RecordBatch一直不到16k,那消息也不能一直存放在缓存里吧,所以lingerMs,默认0ms,通过linger.ms
进行设置。也就是当lingerMs毫秒后,这个RecordBatch如果没有16k,也会发送出去。所以这里我们一般不能用默认值,当默认为0ms的时候,Sender每次都直接把消息发出去,这样就失去了RecordBatch按批次分发的优势了。
由于kafka发送失败的时候会进行重试,所以如果有重试的话,那以重试的时间作为准,通过retry.backoff.ms
进行设置,默认100ms,所以重试的时候,当超过100ms的时候也会自动发出去。
如果过期了,这些RecordBatch就会从队列里移除,并且释放对应的内存资源。
其他
其他两个,分布为缓冲区关闭的时候或者有进程在flush的时候。
连接
当确认到可以发送的deque的时候,就会把对应的Node给记录下来,存放在Node列表中,这个Node是每个partition的leader节点,如果没有对应的leader节点,就需要进行标记,等发送的时候再重新拉取元数据信息。
遍历完每个RecordBatch的队列后,此时还没有达到要发出去的条件,毕竟Node里对应的broker服务器,此时还不知道能不能连接的上,所以还要验证有没有连接,如果没有,看看能不能连接的上,如果都不行,说明这个Node节点是用不了了,此时就要把这个Node从Node列表中,那这个Node对应的消息就不能发送了。
上面的Node对应的是broker服务器,如果Node0和Node1是一个服务器,那发送的时候,就会把同一个服务器的对应的RecordBatch封装成一个个的ClientRequest一起发送。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。