kafka网络客户端中的异步NIO原理

开始认为kafka生产端的future应用是线程中的异步操作, 直到后来看到消费端主要到只有一个线程的情况下収future的使用

 NIO.2,主要包括新的:

  • 异步 I/O(简称 AIO);
  • Multicase 多播;
  • Stream Control Transport Protocol(SCTP);
  • 文件系统 API;
  • 以及一些 I/O API 的更新,例如:java.io.File.toPath,NetworkChannel 的完整抽象,等等。

AIO 的 I/O 操作,有两种方式的 API 可以进行:

  • Future 方式;
  • Callback 方式。

下面我们分别对这两种方式的 API 进行举例说明。

Future 方式

Future 方式:即提交一个 I/O 操作请求,返回一个 Future。然后您可以对 Future 进行检查,确定它是否完成,或者阻塞 IO 操作直到操作正常完成或者超时异常。使用 Future 方式很简单,比较典型的代码通常像清单 1 所示。

清单 1. 使用 Future 方式的代码示例

AsynchronousSocketChannel ch = AsynchronousSocketChannel.open();



// 连接远程服务器,等待连接完成或者失败

Future<Void> result = ch.connect(remote);

// 进行其他工作,例如,连接后的准备环境,f.e.

//prepareForConnection();

//Future 返回 null 表示连接成功

if(result.get()!=null){

   // 连接失败,清理刚才准备好的环境,f.e.

   //clearPreparation();

   return;

}



// 网络连接正常建立

...



ByteBuffer buffer = ByteBuffer.allocateDirect(8192);



// 进行读操作

Future<Integer> result = ch.read(buffer);



// 此时可以进行其他工作,f.e.

//prepareLocalFile();

// 然后等待读操作完成

try {

   int bytesRead = result.get();

   if(bytesRead==-1){

   // 返回 -1 表示没有数据了而且通道已经结束,即远程服务器正常关闭连接。

       //clear();

       return;

   }

    

   // 处理读到的内容,例如,写入本地文件,f.e.

   //writeToLocolFile(buffer);

} catch (ExecutionExecption x) {

   //failed

}

需要注意的是,因为 Future.get()是同步的,所以如果不仔细考虑使用场合,使用 Future 方式可能很容易进入完全同步的编程模式,从而使得异步操作成为一个摆设。如果这样,那么原来旧版本的 Socket API 便可以完全胜任,大可不必使用异步 I/O。

Callback 方式

Callback 方式:即提交一个 I/O 操作请求,并且指定一个 CompletionHandler。当异步 I/O 操作完成时,便发送一个通知,此时这个 CompletionHandler 对象的 completed 或者 failed 方法将会被调用,样例代码如清单 2 所示。

清单 2. 完成处理接口

public interface CompletionHandler<V,A> {

   // 当操作完成后被调用,result 参数表示操作结果,

   //attachment 参数表示提交操作请求时的参数。

   void completed(V result, A attachment);


   // 当操作失败是调用,exc 参数表示失败原因。attachment 参数同上。

   void failed(Throwable exc, A attachment);

}

关于 Attachment 参数

Attachment 参数是不是看着十分眼熟呢?是的,NIO 中也使用类似的方法。当然 I/O 操作是不会对这个参数进行任何操作的,可以用于在不同的 CompletionHandler 对象之间进行通信。

  • V表示结果值的类型。对于异步网络通道的读写操作而言,这个结果值 V 都是整数类型,表示已经操作的卦数,如果是 -1,NIO.2 内核实现保证传递的 ByteBuffer参数不会有变化。
  • A表示关联到 I/O 操作的对象的类型。用于传递操作环境。通常会封装一个连接环境。
  • 如果成功则 completed 方法被调用。如果失败则 failed 方法被调用。

准备好 CompletionHandler 之后,如何使用 CompletionHandler 呢? AIO 提供四种类型的异步通道以及不同的 I/O 操作接受一个 CompletionHandler 对象,它们分别是:

  • AsynchronousSocketChannel:connect,read,write代码段 小部件
  • AsynchronousFileChannel:lock,read,write
  • AsynchronousServerSocketChannel:accept
  • AsynchronousDatagramChannel:read,write,send,receive

本文重点关注 AsynchronousSocketChannel 的使用,首先简单浏览一下该类型的 API。

AsynchronousSocketChannel

public abstract class AsynchronousSocketChannel

   implements AsynchronousByteChannel, NetworkChannel

创建一个异步网络通道,并且绑定到一个默认组。

public static AsynchronousSocketChannel open() throws IOException

将异步网络通道连接到远程服务器,使用指定的 CompletionHandler 听候完成通知。

public abstract <A> void connect(SocketAddress remote, A attachment,

   CompletionHandler<Void,? super A> handler)

从异步网络通道读取数据到指定的缓冲区,使用指定的 CompletionHandler 听候完成通知。

public final <A> void read(ByteBuffer dst, A attachment,

   CompletionHandler<Integer,? super A> handler)

向异步网络通道写缓冲区中的数据,使用指定的 CompletionHandler 听候完成通知。

public final <A> void write(ByteBuffer src,A attachment,

   CompletionHandler<Integer,? super A> handler)

参考: https://www.ibm.com/developerworks/cn/java/j-lo-nio2/index.html 

posted @ 2021-06-20 23:35  車輪の唄  阅读(29)  评论(0编辑  收藏  举报  来源