众所周知,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构建的话,请加上:

  1. <dependency>
  2. <groupId>org.apache.kafka</groupId>
  3. <artifactId>kafka-clients</artifactId>
  4. <version>0.10.2.0</version>
  5. </dependency>

如果是gradle,请加上:

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

底层框架

  1. /**
  2. * 发送请求主方法
  3. * @param host 目标broker的主机名
  4. * @param port 目标broker的端口
  5. * @param request 请求对象
  6. * @param apiKey 请求类型
  7. * @return 序列化后的response
  8. * @throws IOException
  9. */
  10. public ByteBuffer send(String host, int port, AbstractRequest request, ApiKeys apiKey) throws IOException {
  11. Socket socket = connect(host, port);
  12. try {
  13. return send(request, apiKey, socket);
  14. } finally {
  15. socket.close();
  16. }
  17. }
  18.  
  19. /**
  20. * 发送序列化请求并等待response返回
  21. * @param socket 连向目标broker的socket
  22. * @param request 序列化后的请求
  23. * @return 序列化后的response
  24. * @throws IOException
  25. */
  26. private byte[] issueRequestAndWaitForResponse(Socket socket, byte[] request) throws IOException {
  27. sendRequest(socket, request);
  28. return getResponse(socket);
  29. }
  30.  
  31. /**
  32. * 发送序列化请求给socket
  33. * @param socket 连向目标broker的socket
  34. * @param request 序列化后的请求
  35. * @throws IOException
  36. */
  37. private void sendRequest(Socket socket, byte[] request) throws IOException {
  38. DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
  39. dos.writeInt(request.length);
  40. dos.write(request);
  41. dos.flush();
  42. }
  43.  
  44. /**
  45. * 从给定socket处获取response
  46. * @param socket 连向目标broker的socket
  47. * @return 获取到的序列化后的response
  48. * @throws IOException
  49. */
  50. private byte[] getResponse(Socket socket) throws IOException {
  51. DataInputStream dis = null;
  52. try {
  53. dis = new DataInputStream(socket.getInputStream());
  54. byte[] response = new byte[dis.readInt()];
  55. dis.readFully(response);
  56. return response;
  57. } finally {
  58. if (dis != null) {
  59. dis.close();
  60. }
  61. }
  62. }
  63.  
  64. /**
  65. * 创建Socket连接
  66. * @param hostName 目标broker主机名
  67. * @param port 目标broker服务端口, 比如9092
  68. * @return 创建的Socket连接
  69. * @throws IOException
  70. */
  71. private Socket connect(String hostName, int port) throws IOException {
  72. return new Socket(hostName, port);
  73. }
  74.  
  75. /**
  76. * 向给定socket发送请求
  77. * @param request 请求对象
  78. * @param apiKey 请求类型, 即属于哪种请求
  79. * @param socket 连向目标broker的socket
  80. * @return 序列化后的response
  81. * @throws IOException
  82. */
  83. private ByteBuffer send(AbstractRequest request, ApiKeys apiKey, Socket socket) throws IOException {
  84. RequestHeader header = new RequestHeader(apiKey.id, request.version(), "client-id", 0);
  85. ByteBuffer buffer = ByteBuffer.allocate(header.sizeOf() + request.sizeOf());
  86. header.writeTo(buffer);
  87. request.writeTo(buffer);
  88. byte[] serializedRequest = buffer.array();
  89. byte[] response = issueRequestAndWaitForResponse(socket, serializedRequest);
  90. ByteBuffer responseBuffer = ByteBuffer.wrap(response);
  91. ResponseHeader.parse(responseBuffer);
  92. return responseBuffer;
  93. }

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

创建topic

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

查看位移

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

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. 路由策略和策略路由 & route-map

    今天,这个专题应用下route-map,在这个之前,有很多内容需要掌握,不是简单的制定一个路由图就可以了. -------- 本次专题理论的东西居多,但是不是复制黏贴,是加上自己的理解思想. 第一个要 ...

  2. Mxnet学习资源

    MxNet 学习笔记(1):MxNet中的NDArray http://mxnet.incubator.apache.org/api/python/symbol/symbol.html api文档 M ...

  3. SpagoBI 教程 Lesson 1:Introduction and Installation

    SapgoBI Lesson 1: Introduction and Installation Downloading and installing SpagoBI. Download SpagoBI ...

  4. HTML5实现摇一摇的功能(实测后)--转

    eviceMotionEvent(设备运动事件)返回设备有关于加速度和旋转的相关信息.加速度的数据将包含三个轴:x,y和z(示意如下图所 示,x轴横向贯穿手机屏幕或者笔记本键盘,y轴纵向贯穿手机屏幕或 ...

  5. Java如何合并两个数组?

    Java中,如何合并两个数组? 示例 本例展示了如何使用List类的List.Addall(array1.asList(array2))方法和Array类的Arrays.toString()方法将两个 ...

  6. Swing用于开发Java应用程序用户界面

    Swing是一个用于开发Java应用程序用户界面的开发工具包. 以抽象窗口工具包(AWT)为基础使跨平台应用程序可以使用任何可插拔的外观风格. Swing开发人员只用很少的代码就可以利用Swing丰富 ...

  7. js 操作json对象增删改

    //将表单序列化成字符串 $.fn.serializeObject = function () { var obj = {}; var count = 0; $.each(this.serialize ...

  8. win10专业版激活方法

    slmgr.vbs /upk 此时弹出窗口显未“已成功卸载了产品密钥”. slmgr /ipk W269N-WFGWX-YVC9B-4J6C9-T83GX 弹出窗口提示:“成功的安装了产品密钥”. s ...

  9. js 事件调度

    var EventTarget = function () { this._listener = {}; }; EventTarget.prototype = { constructor: this, ...

  10. nginx隐藏server信息和版本信息

    1.隐藏版本信息 在nginx.conf里面添加 server_tokens off; 2.隐藏server信息 需要重新编译ngnix进入解压出来的nginx 源码目录 vi src/http/ng ...