Java Kafka源代码-理解Selector.poll()的语义
我正在研究卡夫卡的网络层代码,我有一些关于选择器的问题 类,特别是poll方法的实现方式。投票方法如下所示:Java Kafka源代码-理解Selector.poll()的语义,java,apache-kafka,polling,Java,Apache Kafka,Polling,我正在研究卡夫卡的网络层代码,我有一些关于选择器的问题 类,特别是poll方法的实现方式。投票方法如下所示: void poll(int timeout){ .... /* check ready keys */ long startSelect = time.nanoseconds(); int readyKeys = select(timeout); long endSelect = time.nanoseconds(); this.sensors.s
void poll(int timeout){
....
/* check ready keys */
long startSelect = time.nanoseconds();
int readyKeys = select(timeout);
long endSelect = time.nanoseconds();
this.sensors.selectTime.record(endSelect - startSelect, time.milliseconds());
if (readyKeys > 0 || !immediatelyConnectedKeys.isEmpty()) {
pollSelectionKeys(this.nioSelector.selectedKeys(), false, endSelect);
pollSelectionKeys(immediatelyConnectedKeys, true, endSelect);
}
...
}
我们首先调用pollSelectionKeys方法的原因是什么
对于select方法返回的键,然后是直接连接的键?是
为了清楚起见,我们单独执行这些操作,还是有一些特定的操作
涉及的要求
其次,在pollSelectionKeys方法中,我们有:
void pollSelectionKeys(Iterable<SelectionKey> selectionKeys,
boolean isImmediatelyConnected,
long currentTimeNanos){
...
/* if channel is ready write to any sockets that have space in their buffer and for which
we have data */
if (channel.ready() && key.isWritable()) {
Send send = channel.write();
if (send != null) {
this.completedSends.add(send);
this.sensors.recordBytesSent(channel.id(), send.size());
}
}
...
}
据我所知,我们只在卡夫卡察尼属于任何一方时才给它写信
我们从前面对select方法的调用中获得的键集,或者如果KafkaChannel
与其中一个立即连接的密钥关联。我的问题是,我们为什么要做这件事
这样写信给卡夫卡察尼家族的事?更具体地说,我们不需要迭代
在所有已连接的卡夫卡通道上,如果他们有发送,请写信给他们
与它们关联的对象?这样我们就可以尽快给卡夫卡察尼写信,
不必等待它属于立即连接的密钥或ReadyKey。在I/O连接完成之前,TCP连接不可用。答案在于下面类相关部分的连接方法
connected = socketChannel.connect(address);
..............................
................................
SelectionKey key = socketChannel.register(nioSelector, SelectionKey.OP_CONNECT);
根据NIO connect的文档说明
如果此通道处于非阻塞模式,则调用
方法启动非阻塞连接操作。如果
立即建立连接,就像本地服务器可能发生的那样
连接,则此方法返回true。否则,这种方法
返回false,连接操作必须稍后由完成
调用finishConnect方法
下面很好地解释了一个典型的交互工作流程
如果以非阻塞模式连接,则应:
注册OP_CONNECT的通道
当它触发时,请调用finishConnect
如果返回true,则取消注册OP_CONNECT并注册OP_READ或OP_WRITE,具体取决于接下来要执行的操作
如果返回false,则不执行任何操作,继续选择
如果connect或finishConnect引发异常,请关闭通道并重试,或者忘记它,或者告诉用户或
只要合适。
如果在通道连接之前不想执行任何操作,请执行以下操作:
在阻塞模式下连接,并在以下情况下进入非阻塞模式:
连接成功
在本地连接的情况下,这种连接方法可能会立即连接,并且可能不会触发为该连接注册的OP_connect事件。在连接调用后,socketChannel会运行几行,因此,当使用典型的java NIO注册代码时,我们可能会错过它。我们最终需要在这些渠道上调用finishConnect,请参阅工作流中的第二个要点。因此,我们将这样的通道密钥添加到另一组立即连接的密钥中,这样它们就可以被处理得太晚,否则我们将完全丢失它们
if (readyKeys > 0 || !immediatelyConnectedKeys.isEmpty()) {
pollSelectionKeys(this.nioSelector.selectedKeys(), false, endSelect);
pollSelectionKeys(immediatelyConnectedKeys, true, endSelect);
}
稍后在pollSelectionKeys方法中,请注意finishConnect的使用,finishConnect是对底层
总之,卡夫卡的代码看起来像是标准的NIO代码,除非卡夫卡团队能够解释更多。关于这个主题的更多好的阅读可以找到。我们可以发现一个有趣的误解,它与这个归档和JDK团队最终的拒绝有关
对于问题的第二部分,您可能会询问以下代码。为什么要两个不同的键
if (readyKeys > 0 || !immediatelyConnectedKeys.isEmpty()) {
pollSelectionKeys(this.nioSelector.selectedKeys(), false, endSelect);
pollSelectionKeys(immediatelyConnectedKeys, true, endSelect);
}
请看,我们现在维护了两组键。虽然有一个整体键视图是由selector.keys提供的,但该键集不可直接修改,因此它是一种只读视图。此密钥集中的密钥只有在被取消且其频道被取消注册后才会被删除。因此,通常使用selector.selectedKeys访问就绪频道。另外,selector.selectedKeys显然不会立即从连接的按键返回按键。对从selector.selectedKeys获得的这些键进行处理的通常模式是在集合上迭代,测试由以下表达式表示的通道可接受、可连接、可读写的事件
密钥已准备就绪,请执行您的操作,然后将其从集合中移除。此删除部分非常必要。选择器不会从所选密钥集本身删除SelectionKey实例。处理完通道后,必须执行此操作。
下一次通道准备就绪时,选择器将再次将其添加到选定的关键点集。因此,这就是处理这两个问题的原因,pollSelectionKeys方法设计用于处理这两个问题。这就更有意义了。你对上面的第二个问题有什么回答吗?我补充了我对第二个问题的看法。
if (readyKeys > 0 || !immediatelyConnectedKeys.isEmpty()) {
pollSelectionKeys(this.nioSelector.selectedKeys(), false, endSelect);
pollSelectionKeys(immediatelyConnectedKeys, true, endSelect);
}