众所周知,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. 如何通过使用窗体身份验证和 Visual C#.NET 对 Active Directory 验证身份

    本分步指南演示如何在 ASP.NET 应用程序如何使用窗体身份验证允许用户使用轻型目录访问协议 (LDAP),对 Active Directory 进行验证.经过身份验证的用户重定向之后,可以使用Ap ...

  2. JAVA NIO 简单介绍

    Version:0.9 StartHTML:-1 EndHTML:-1 StartFragment:00000099 EndFragment:00918492 一:为什么要使用NIO技术        ...

  3. (笔记)arm-linux-gcc/ld/objcopy/objdump参数总结

    说明:gcc是编译器,负责对c代码的编译, ld是连接器 负责将多个*.o的目标文件链接成elf可执行文件.elf可执行文件是unix常用的可执行文件类型,就像windows的exe文件.elf文件中 ...

  4. CSS之float vs position:absolute

    补充:ul 应该设置下 list-style: none; 题外话:看了张鑫旭的视频,这家伙把简单的css玩出了新花样,绝对大神级的存在.膜拜下先~ float的作用前面一章已经说过了,但没考虑过的是 ...

  5. application/json 与 application/x-www-form-urlencoded的简单比较

    application/x-www-form-urlencoded 提交请求示例 curl -X POST 'http://localhost:8080/formPost' -d 'id=1& ...

  6. bioerl 获取gi号

    代码示例: use Bio::DB::EUtilities; my @ids = qw(CAB02640 EAS10332 YP_250808 NP_623143 P41007); my $facto ...

  7. Linux服务器 java生成的图片验证码乱码问题

    问题:如图所示项目中生成的图形验证码不能正常显示出需要的字体 原因:  linux下没有对应的字体 查找项目中使用到系统字体的地方,如下: 解决: 1. 在本地 路径 C:\Windows\Fonts ...

  8. apache用户认证 域名跳转 Apache访问日志

  9. window.frames[]在Firefox下无法兼容的解决方式

    html代码段: <iframe id="fr" src="ProjectTree.aspx?IsFree=true&f=yes&IsCheckPr ...

  10. swig和angular双花括号的冲突

    swig和angular都用{{name}}来作为模板中变量的取值, 那么要共用的话怎么办: {% raw %}{{ foobar }}{% endraw %} 或者 config(['$interp ...