Java API方式调用Kafka各种协议
众所周知,Kafka自己实现了一套二进制协议(binary protocol)用于各种功能的实现,比如发送消息,获取消息,提交位移以及创建topic等。具体协议规范参见:Kafka协议 这套协议的具体使用流程为:
- 客户端创建对应协议的请求
- 客户端发送请求给对应的broker
- 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各种协议的更多相关文章
- java api如何获取kafka所有Topic列表,并放置为一个list
kafka内部所有的实现都是通过TopicCommand的main方法,通过java代码调用API,TopicCommand.main(options)的方式只能打印到控制台,不能转换到一个list. ...
- 使用Java API方式的MapReduce练习
众所周知,hadoop生态圈的多数组件都是使用java开发的. 那么使用Java API方式实现起来,显得要比其它语言效率更高,更原生态. 前面有一个Hadoop学习笔记02_MapReduce练习 ...
- VBA通过C#以API方式调用JS脚本函数
http://www.cnblogs.com/Charltsing/p/JSDotNetAPI.html 在网页采集中,很多时候需要运行网站下载的某个js文件中的函数,以计算Request参数.VBA ...
- 使用Java API方式连接HDFS Client测试
IDEA中新建Maven工程,添加POM依赖, 在IDE的提示中, 点击 Import Changes 等待自动下载完成相关的依赖包. <?xml version="1.0" ...
- 以API方式调用C# dll,使用OneNote2013 sp1实现OCR识别本地图片
http://www.cnblogs.com/Charltsing/p/OneNoteOCRAPI.html OneNote2013 OCR API调用使用说明2019.4.17 使用说明:1.安装干 ...
- java命令行调用本地文件协议hikvideoclient://
最近在做一个视频项目,项目中需要通过调用海康本地协议打开视频播放器,起初尝试通过Process/ProcessBuilder无解,因为这个是调用本地应用程序的. 我要调用的是本地伪协议,最终通过一些研 ...
- 使用Java API创建(create),查看(describe),列举(list),删除(delete)Kafka主题(Topic)
使用Kafka的同学都知道,我们每次创建Kafka主题(Topic)的时候可以指定分区数和副本数等信息,如果将这些属性配置到server.properties文件中,以后调用Java API生成的主题 ...
- kafka2.9.2的伪分布式集群安装和demo(java api)测试
目录: 一.什么是kafka? 二.kafka的官方网站在哪里? 三.在哪里下载?需要哪些组件的支持? 四.如何安装? 五.FAQ 六.扩展阅读 一.什么是kafka? kafka是LinkedI ...
- ubuntu12.04+kafka2.9.2+zookeeper3.4.5的伪分布式集群安装和demo(java api)测试
博文作者:迦壹 博客地址:http://idoall.org/home.php?mod=space&uid=1&do=blog&id=547 转载声明:可以转载, 但必须以超链 ...
随机推荐
- Numpy 的数组转置和轴对换
数组转置 转置(transpose)是重塑的一种特殊形式, 它返回的是源数据的视图(不会进行任何操作.)数组不仅有transpose,还要特殊的T属性 计算矩阵内积 高维数组transpose 详细讲 ...
- (笔记)Linux线程编译undefined reference to 'pthread_create'
在使用线程时,使用gcc或arm-linux-gcc编译时,会出现错误:undefined reference to 'pthread_create' 主要是以下两种原因: 1.#include &l ...
- 第三百八十二节,Django+Xadmin打造上线标准的在线教育平台—xadmin管理员详情页面布局,导航图标设置
第三百八十二节,Django+Xadmin打造上线标准的在线教育平台—xadmin进阶 1.后台管理员详情页面布局 后台管理员详情页面,区块是可以拖动的,而且分为了很多个区块 这个页面的布局在xadm ...
- HttpWebRequest.ReadWriteTimeout 属性
获取或设置写入或读取流时的超时. 属性值在写入超时或读取超时之前的毫秒数.默认值为 300,000 毫秒(5 分钟). 备注 在写入由 GetRequestStream 方法返回的流时,或在读取由 G ...
- 对SingleTask和TaskAffinity的理解(转至 http://www.2cto.com/kf/201311/254450.html)
最近研究微信调起自己客户端的事情,对于SingleTask和TaskAffinity的理解又多了一些理解. 以前对于Android的四种LaunchMode有一些了解,其中比较有意思的就是Sing ...
- SpringMVC文件上传基础
maven依赖 <!--文件上传所需--> <dependency> <groupId>commons-fileupload</groupId> < ...
- Business vs Technology
Business 只是 Technology的子集. Business只是体现在Code中. 比如说是HTML页面中内容的一部分. 或者说业务是对HTML组成的内容的分类. 比如说Smallbusin ...
- textarea标签内容为(英文或数字不自动换行)的解决方法
textarea 显示一串英文时不会发生换行. 以下是两种解决方法:1.限制textarea的大小 width 设置为 00px (不要设置为00%)cols 设置为 30+ (也有类似效果) 2. ...
- Linux系统下wetty安装和使用说明
1. Wetty简介 Wetty是使用Node.js和websockets开发的一个开源Web-based SSH.关于Web-based SSH的更多资料请参考https://en.wikipedi ...
- [转]WPF入口Application
1.WPF和 传统的WinForm 类似, WPF 同样需要一个 Application 来统领一些全局的行为和操作,并且每个 Domain (应用程序域)中只能有一个 Application 实例存 ...