众所周知,Kafka自己实现了一套二进制协议(binary protocol)用于各种功能的实现,比如发送消息,获取消息,提交位移以及创建topic等。具体协议规范参见:Kafka协议  这套协议的具体使用流程为:

  1. 客户端创建对应协议的请求
  2. 客户端发送请求给对应的broker
  3. broker处理请求,并发送response给客户端

  虽然Kafka提供的大量的脚本工具用于各种功能的实现,但很多时候我们还是希望可以把某些功能以编程的方式嵌入到另一个系统中。这时使用Java API的方式就显得异常地灵活了。本文我将尝试给出Java API底层框架的一个范例,同时也会针对“创建topic”和“查看位移”这两个主要功能给出对应的例子。 需要提前说明的是,本文给出的范例并没有考虑Kafka集群开启安全的情况。另外Kafka的KIP4应该一直在优化命令行工具以及各种管理操作,有兴趣的读者可以关注这个KIP。

  本文中用到的API依赖于kafka-clients,所以如果你使用Maven构建的话,请加上:

<dependency>
<groupId>org.apache.kafka</groupId>
<artifactId>kafka-clients</artifactId>
<version>0.10.2.0</version>
</dependency>

如果是gradle,请加上:

compile group: 'org.apache.kafka', name: 'kafka-clients', version: '0.10.2.0'

底层框架

 /**
* 发送请求主方法
* @param host 目标broker的主机名
* @param port 目标broker的端口
* @param request 请求对象
* @param apiKey 请求类型
* @return 序列化后的response
* @throws IOException
*/
public ByteBuffer send(String host, int port, AbstractRequest request, ApiKeys apiKey) throws IOException {
Socket socket = connect(host, port);
try {
return send(request, apiKey, socket);
} finally {
socket.close();
}
} /**
* 发送序列化请求并等待response返回
* @param socket 连向目标broker的socket
* @param request 序列化后的请求
* @return 序列化后的response
* @throws IOException
*/
private byte[] issueRequestAndWaitForResponse(Socket socket, byte[] request) throws IOException {
sendRequest(socket, request);
return getResponse(socket);
} /**
* 发送序列化请求给socket
* @param socket 连向目标broker的socket
* @param request 序列化后的请求
* @throws IOException
*/
private void sendRequest(Socket socket, byte[] request) throws IOException {
DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
dos.writeInt(request.length);
dos.write(request);
dos.flush();
} /**
* 从给定socket处获取response
* @param socket 连向目标broker的socket
* @return 获取到的序列化后的response
* @throws IOException
*/
private byte[] getResponse(Socket socket) throws IOException {
DataInputStream dis = null;
try {
dis = new DataInputStream(socket.getInputStream());
byte[] response = new byte[dis.readInt()];
dis.readFully(response);
return response;
} finally {
if (dis != null) {
dis.close();
}
}
} /**
* 创建Socket连接
* @param hostName 目标broker主机名
* @param port 目标broker服务端口, 比如9092
* @return 创建的Socket连接
* @throws IOException
*/
private Socket connect(String hostName, int port) throws IOException {
return new Socket(hostName, port);
} /**
* 向给定socket发送请求
* @param request 请求对象
* @param apiKey 请求类型, 即属于哪种请求
* @param socket 连向目标broker的socket
* @return 序列化后的response
* @throws IOException
*/
private ByteBuffer send(AbstractRequest request, ApiKeys apiKey, Socket socket) throws IOException {
RequestHeader header = new RequestHeader(apiKey.id, request.version(), "client-id", 0);
ByteBuffer buffer = ByteBuffer.allocate(header.sizeOf() + request.sizeOf());
header.writeTo(buffer);
request.writeTo(buffer);
byte[] serializedRequest = buffer.array();
byte[] response = issueRequestAndWaitForResponse(socket, serializedRequest);
ByteBuffer responseBuffer = ByteBuffer.wrap(response);
ResponseHeader.parse(responseBuffer);
return responseBuffer;
}

  有了这些方法的铺垫,我们就可以创建具体的请求了。

创建topic

 /**
* 创建topic
* 由于只是样例代码,有些东西就硬编码写到程序里面了(比如主机名和端口),各位看官自行修改即可
* @param topicName topic名
* @param partitions 分区数
* @param replicationFactor 副本数
* @throws IOException
*/
public void createTopics(String topicName, int partitions, short replicationFactor) throws IOException {
Map<String, CreateTopicsRequest.TopicDetails> topics = new HashMap<>();
// 插入多个元素便可同时创建多个topic
topics.put(topicName, new CreateTopicsRequest.TopicDetails(partitions, replicationFactor));
int creationTimeoutMs = 60000;
CreateTopicsRequest request = new CreateTopicsRequest.Builder(topics, creationTimeoutMs).build();
ByteBuffer response = send("localhost", 9092, request, ApiKeys.CREATE_TOPICS);
CreateTopicsResponse.parse(response, request.version());
}

查看位移

 /**
* 获取某个consumer group下的某个topic分区的位移
* @param groupID group id
* @param topic topic名
* @param parititon 分区号
* @throws IOException
*/
public void getOffsetForPartition(String groupID, String topic, int parititon) throws IOException {
TopicPartition tp = new TopicPartition(topic, parititon);
OffsetFetchRequest request = new OffsetFetchRequest.Builder(groupID, singletonList(tp))
.setVersion((short)2).build();
ByteBuffer response = send("localhost", 9092, request, ApiKeys.OFFSET_FETCH);
OffsetFetchResponse resp = OffsetFetchResponse.parse(response, request.version());
OffsetFetchResponse.PartitionData partitionData = resp.responseData().get(tp);
System.out.println(partitionData.offset);
}
 /**
* 获取某个consumer group下所有topic分区的位移信息
* @param groupID group id
* @return (topic分区 --> 分区信息)的map
* @throws IOException
*/
public Map<TopicPartition, OffsetFetchResponse.PartitionData> getAllOffsetsForGroup(String groupID) throws IOException {
OffsetFetchRequest request = new OffsetFetchRequest.Builder(groupID, null).setVersion((short)2).build();
ByteBuffer response = send("localhost", 9092, request, ApiKeys.OFFSET_FETCH);
OffsetFetchResponse resp = OffsetFetchResponse.parse(response, request.version());
return resp.responseData();
}

okay, 上面就是“创建topic”和“查看位移”的样例代码,各位看官可以参考着这两个例子构建其他类型的请求。

Java API方式调用Kafka各种协议的更多相关文章

  1. java api如何获取kafka所有Topic列表,并放置为一个list

    kafka内部所有的实现都是通过TopicCommand的main方法,通过java代码调用API,TopicCommand.main(options)的方式只能打印到控制台,不能转换到一个list. ...

  2. 使用Java API方式的MapReduce练习

    众所周知,hadoop生态圈的多数组件都是使用java开发的. 那么使用Java API方式实现起来,显得要比其它语言效率更高,更原生态. 前面有一个Hadoop学习笔记02_MapReduce练习 ...

  3. VBA通过C#以API方式调用JS脚本函数

    http://www.cnblogs.com/Charltsing/p/JSDotNetAPI.html 在网页采集中,很多时候需要运行网站下载的某个js文件中的函数,以计算Request参数.VBA ...

  4. 使用Java API方式连接HDFS Client测试

    IDEA中新建Maven工程,添加POM依赖, 在IDE的提示中, 点击 Import Changes 等待自动下载完成相关的依赖包. <?xml version="1.0" ...

  5. 以API方式调用C# dll,使用OneNote2013 sp1实现OCR识别本地图片

    http://www.cnblogs.com/Charltsing/p/OneNoteOCRAPI.html OneNote2013 OCR API调用使用说明2019.4.17 使用说明:1.安装干 ...

  6. java命令行调用本地文件协议hikvideoclient://

    最近在做一个视频项目,项目中需要通过调用海康本地协议打开视频播放器,起初尝试通过Process/ProcessBuilder无解,因为这个是调用本地应用程序的. 我要调用的是本地伪协议,最终通过一些研 ...

  7. 使用Java API创建(create),查看(describe),列举(list),删除(delete)Kafka主题(Topic)

    使用Kafka的同学都知道,我们每次创建Kafka主题(Topic)的时候可以指定分区数和副本数等信息,如果将这些属性配置到server.properties文件中,以后调用Java API生成的主题 ...

  8. kafka2.9.2的伪分布式集群安装和demo(java api)测试

    目录: 一.什么是kafka? 二.kafka的官方网站在哪里? 三.在哪里下载?需要哪些组件的支持? 四.如何安装? 五.FAQ 六.扩展阅读   一.什么是kafka? kafka是LinkedI ...

  9. ubuntu12.04+kafka2.9.2+zookeeper3.4.5的伪分布式集群安装和demo(java api)测试

    博文作者:迦壹 博客地址:http://idoall.org/home.php?mod=space&uid=1&do=blog&id=547 转载声明:可以转载, 但必须以超链 ...

随机推荐

  1. ACTIVE NEURAL LOCALIZATION

    用贝叶斯滤波器定义状态,用rl帮助定位. 这个方法需要对地图和角度进行离散化,当地图很大,角度较精细时,输出会很大,所以不太可能用到大地图,高精度角度的任务上.

  2. applicationContext.xml报错org.springframework.orm.hibernate3.LocalSessionFactoryBean not found

    applicationContext.xml报错org.springframework.orm.hibernate3.LocalSessionFactoryBean not found 解决办法: 1 ...

  3. android设置主mic/副mic录音

    //添加MIC设置参数 /hal/audio_extn/audio_extn.c @@ -75,6 +75,7 @@ struct audio_extn_module { bool ras_enabl ...

  4. c++11 std::move() 的使用

    std::move函数可以以非常简单的方式将左值引用转换为右值引用.(左值.左值引用.右值.右值引用 参见:http://www.cnblogs.com/SZxiaochun/p/8017475.ht ...

  5. Wireshark 抓包小例子

    捕捉过滤器(CaptureFilters): 用于决定将什么样的信息记录在捕捉结果中. 语法详见:http://www.cnblogs.com/SZxiaochun/p/7920962.html 显示 ...

  6. e768. 创建单选按钮

    // Create an action for each radio button Action action1 = new AbstractAction("RadioButton Labe ...

  7. Linux中的软链接与硬链接

    软链接相当于windows的快捷方式,当源文件不存在时,软链接失效. 链接是指向文件名,当指向的文件名字删除的时候,就找不到源文件了.硬链接是指向文件本身,删除一个文件名字,还是可以找到源文件的.ls ...

  8. MYSQL类型与JAVA类型对应表

    MYSQL类型与JAVA类型对应表: 类型名称 显示长度 数据库类型 JAVA类型 JDBC类型索引(int) VARCHAR L+N VARCHAR java.lang.String 12 CHAR ...

  9. js requestAnimationFrame

    requestAnimationFrame,Web中写动画的另一种选择  原文:https://www.cnblogs.com/Wayou/p/requestAnimationFrame.html H ...

  10. linux cfs调度器_理论模型

    参考资料:<调度器笔记>Kevin.Liu <Linux kernel development> <深入Linux内核架构> version: 2.6.32.9 下 ...