创建一个topic

  1. ./kafka-topics.sh --create --zookeeper 192.168.1.244:2181,192.168.1.245:2181,192.168.1.246:2181 --replication-factor 1
    --partitions 1 --topic topic_test_zk_minOffset_zkGroup

查看topic列表

  1. ./kafka-topics.sh --list --zookeeper 192.168.1.244:2181,192.168.1.245:2181,192.168.1.246:2181

producer 代码如下

  1. package com.kafka.test;
  2.  
  3. import java.util.Properties;
  4.  
  5. import org.apache.kafka.clients.producer.KafkaProducer;
  6. import org.apache.kafka.clients.producer.ProducerRecord;
  7.  
  8. /**
  9. * @author:FengZhen
  10. * @create:2018年8月9日
  11. */
  12. public class Producer_zk {
  13.  
  14. public static void main(String[] args) {
  15. Properties props = new Properties();
  16. props.put("bootstrap.servers", "192.168.1.244:6667,192.168.1.247:6667");
  17. //props.put("zookeeper.connect", "192.168.1.244:2181,192.168.1.245:2181,192.168.1.246:2181");
  18. props.put("acks", "all");
  19. props.put("retries", 0);
  20. props.put("batch.size", 16384);
  21. props.put("linger.ms", 1);
  22. props.put("buffer.memory", 33554432);
  23. props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
  24. props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
  25.  
  26. KafkaProducer<String, String> producer = new KafkaProducer<String, String>(props);
  27. for (int i = 30; i < 40; i++)
  28. producer.send(new ProducerRecord<String, String>("topic_test_zk_minOffset_zkGroup", Integer.toString(i), "中文测试-"+Integer.toString(i)));
  29.  
  30. producer.close();
  31. }
  32.  
  33. }

Streaming代码如下

  1. package streaming
  2.  
  3. import kafka.api.{OffsetRequest, PartitionOffsetRequestInfo, TopicMetadataRequest}
  4. import kafka.common.TopicAndPartition
  5. import kafka.consumer.SimpleConsumer
  6. import kafka.message.MessageAndMetadata
  7. import kafka.serializer.StringDecoder
  8. import kafka.utils.{ZKGroupTopicDirs, ZkUtils}
  9. import org.I0Itec.zkclient.ZkClient
  10. import org.apache.spark.streaming.dstream.InputDStream
  11. import org.apache.spark.streaming.kafka.{HasOffsetRanges, KafkaUtils, OffsetRange}
  12. import org.apache.spark.streaming.{Seconds, StreamingContext}
  13. import org.apache.spark.{SparkConf, SparkContext}
  14.  
  15. object KafkaLog_local_zk_minOffset_zkGroup {
  16.  
  17. def main(args: Array[String]): Unit = {
  18. val conf = new SparkConf().setAppName("KafkaLog_local_zk_minOffset_zkGroup").setMaster("local[2]")
  19. val sc = new SparkContext(conf)
  20. sc.setLogLevel("WARN")
  21. val ssc = new StreamingContext(sc, Seconds(5))
  22.  
  23. val broker_servers = "192.168.1.244:6667,192.168.1.247:6667"
  24. val zk_host = "192.168.1.244:2181,192.168.1.245:2181,192.168.1.246:2181"
  25. //消费的 topic 名字
  26. val topic : String = "topic_test_zk_minOffset_zkGroup"
  27. //创建 stream 时使用的 topic 名字集合
  28. val topics : Set[String] = Set(topic)
  29.  
  30. var kafkaParam:Map[String,String] = Map()
  31. kafkaParam += ("bootstrap.servers" -> broker_servers)
  32. kafkaParam += ("group.id" -> "test")
  33. kafkaParam += ("enable.auto.commit" -> "true")
  34. kafkaParam += ("auto.commit.interval.ms" -> "100")
  35.  
  36. //创建一个 ZKGroupTopicDirs 对象,对保存
  37. val topicDirs = new ZKGroupTopicDirs("topic_test_zk_minOffset_zkGroup_group", topic)
  38.  
  39. //获取 zookeeper 中的路径,这里会变成 /consumers/test_spark_streaming_group/offsets/topic_name
  40. // /consumers/topic_test_zk_minOffset_zkGroup_group/offsets/topic_test_zk_minOffset_zkGroup/0
  41. val zkTopicPath = s"${topicDirs.consumerOffsetDir}"
  42.  
  43. //zookeeper 的host 和 ip,创建一个 client
  44. val zkClient = new ZkClient(zk_host)
  45. //查询该路径下是否字节点(默认有字节点为我们自己保存不同 partition 时生成的)
  46. val children = zkClient.countChildren(zkTopicPath)
  47.  
  48. var kafkaStream : InputDStream[(String, String)] = null
  49.  
  50. //如果 zookeeper 中有保存 offset,我们会利用这个 offset 作为 kafkaStream 的起始位置
  51. var fromOffsets: Map[TopicAndPartition, Long] = Map()
  52.  
  53. //如果保存过 offset,这里更好的做法,还应该和 kafka 上最小的 offset 做对比,不然会报 OutOfRange 的错误
  54. if (children > 0) {
  55. for (i <- 0 until children) {
  56. val topic2 = List(topic)
  57. val req = new TopicMetadataRequest(topic2, 0)
  58. // 第一个参数是 kafka broker 的host,第二个是 port
  59. val getLeaderConsumer = new SimpleConsumer("192.168.1.244", 6667, 10000, 10000, "OffsetLookup")
  60. val res = getLeaderConsumer.send(req)
  61. val topicMetaOption = res.topicsMetadata.headOption
  62. val partitions = topicMetaOption match {
  63. // 将结果转化为 partition -> leader 的映射关系
  64. case Some(tm) =>
  65. tm.partitionsMetadata.map(pm => (pm.partitionId, pm.leader.get.host)).toMap[Int, String]
  66. case None =>
  67. Map[Int, String]()
  68. }
  69. //去出分片对应的leader host
  70. val brokerLeaderHost = partitions.get(i).toString.replace("Some(", "").replace(")","")
  71.  
  72. val partitionOffset = zkClient.readData[String](s"${zkTopicPath}/${i}")
  73. val tp = TopicAndPartition(topic, i)
  74.  
  75. val requestMin = OffsetRequest(Map(tp -> PartitionOffsetRequestInfo(OffsetRequest.EarliestTime, 1)))
  76. val consumerMin = new SimpleConsumer(brokerLeaderHost, 6667, 10000, 10000, "getMinOffset")
  77. val curOffsets = consumerMin.getOffsetsBefore(requestMin).partitionErrorAndOffsets(tp).offsets
  78. var nextOffset = partitionOffset.toLong
  79. // 通过比较从 kafka 上该 partition 的最小 offset 和 zk 上保存的 offset,进行选择
  80. if (curOffsets.length > 0 && nextOffset < curOffsets.head) {
  81. nextOffset = curOffsets.head
  82. }
  83. //设置正确的 offset,这里将 nextOffset 设置为 0(0 只是一个特殊值),可以观察到 offset 过期的想想
  84. fromOffsets += (tp -> nextOffset)
  85. println("@@@@@@ topic[" + topic + "] partition[" + i + "] offset[" + partitionOffset + "] @@@@@@")
  86. }
  87.  
  88. //这个会将 kafka 的消息进行 transform,最终 kafak 的数据都会变成 (topic_name, message) 这样的 tuple
  89. val messageHandler = (mmd : MessageAndMetadata[String, String]) => (mmd.topic, mmd.message())
  90. kafkaStream = KafkaUtils.createDirectStream[String, String, StringDecoder, StringDecoder, (String, String)](ssc, kafkaParam, fromOffsets, messageHandler)
  91. }
  92. else {
  93. //如果未保存,根据 kafkaParam 的配置使用最新或者最旧的 offset
  94. kafkaStream = KafkaUtils.createDirectStream[String, String, StringDecoder, StringDecoder](ssc, kafkaParam, topics)
  95. }
  96.  
  97. var offsetRanges = Array[OffsetRange]()
  98. //得到该 rdd 对应 kafka 的消息的 offset
  99. kafkaStream.transform{ rdd =>
  100. offsetRanges = rdd.asInstanceOf[HasOffsetRanges].offsetRanges
  101. rdd
  102. }.foreachRDD { rdd => //.map(msg => Utils.msgDecode(msg))
  103. for (o <- offsetRanges) {
  104. val zkPath = s"${zkTopicPath}/${o.partition}"
  105. //将该 partition 的 offset 保存到 zookeeper
  106. ZkUtils.updatePersistentPath(zkClient, zkPath, o.fromOffset.toString)
  107. println(s"@@@@@@ topic ${o.topic} partition ${o.partition} fromoffset ${o.fromOffset} untiloffset ${o.untilOffset} #######")
  108. }
  109. rdd.foreachPartition(
  110. message => {
  111. while(message.hasNext) {
  112. println(s"@^_^@ [" + message.next() + "] @^_^@")
  113. }
  114. }
  115. )
  116. }
  117. //开启流式计算
  118. ssc.start()
  119. //一直会阻塞,等待退出
  120. ssc.awaitTermination()
  121. }
  122. }

出现的问题

使用simpleConsumer时报错

  1. Exception in thread "main" java.nio.channels.ClosedChannelException
  2. at kafka.network.BlockingChannel.send(BlockingChannel.scala:100)
  3. at kafka.consumer.SimpleConsumer.liftedTree1$1(SimpleConsumer.scala:78)
  4. at kafka.consumer.SimpleConsumer.kafka$consumer$SimpleConsumer$$sendRequest(SimpleConsumer.scala:68)
  5. at kafka.consumer.SimpleConsumer.getOffsetsBefore(SimpleConsumer.scala:127)
  6. at streaming.KafkaLog_local_zk_minOffset$$anonfun$main$1.apply$mcVI$sp(KafkaLog_local_zk_minOffset.scala:64)
  7. at scala.collection.immutable.Range.foreach$mVc$sp(Range.scala:160)
  8. at streaming.KafkaLog_local_zk_minOffset$.main(KafkaLog_local_zk_minOffset.scala:44)
  9. at streaming.KafkaLog_local_zk_minOffset.main(KafkaLog_local_zk_minOffset.scala)
  1. 解决将Kafka config下的server.properties的参数修改下
  1. num.network.threads=3
  2. zookeeper.connection.timeout.ms=6000

 再次尝试即可.

Kafka+SparkStreaming+Zookeeper(ZK存储Offset,解决checkpoint问题)的更多相关文章

  1. Kafka在zookeeper中存储结构和查看方式

    Zookeeper 主要用来跟踪Kafka 集群中的节点状态, 以及Kafka Topic, message 等等其他信息. 同时, Kafka 依赖于Zookeeper, 没有Zookeeper 是 ...

  2. kafka在zookeeper中存储结构

    1.topic注册信息 /brokers/topics/[topic] : 存储某个topic的partitions所有分配信息 Schema:   {    "version": ...

  3. filebeat+kafka+SparkStreaming程序报错及解决办法

    // :: WARN RandomBlockReplicationPolicy: Expecting replicas with only peer/s. // :: WARN BlockManage ...

  4. Kafka学习之路 (五)Kafka在zookeeper中的存储

    一.Kafka在zookeeper中存储结构图 二.分析 2.1 topic注册信息 /brokers/topics/[topic] : 存储某个topic的partitions所有分配信息 [zk: ...

  5. Kafka(四)Kafka在zookeeper中的存储

    一 Kafka在zookeeper中存储结构图 二 分析 2.1 topic注册信息 /brokers/topics/[topic] : 存储某个topic的partitions所有分配信息 [zk: ...

  6. 深入浅出理解基于 Kafka 和 ZooKeeper 的分布式消息队列

    消息队列中间件是分布式系统中重要的组件,主要解决应用耦合,异步消息,流量削锋等问题.实现高性能,高可用,可伸缩和最终一致性架构,是大型分布式系统不可缺少的中间件. 本场 Chat 主要内容: Kafk ...

  7. Kafka 和 ZooKeeper 的分布式消息队列分析

    1. Kafka 总体架构 基于 Kafka-ZooKeeper 的分布式消息队列系统总体架构如下: 如上图所示,一个典型的 Kafka 体系架构包括若干 Producer(消息生产者),若干 bro ...

  8. sparkStreaming消费kafka-1.0.1方式:direct方式(存储offset到zookeeper)

    版本声明: kafka:1.0.1 spark:2.1.0 注意:在使用过程中可能会出现servlet版本不兼容的问题,因此在导入maven的pom文件的时候,需要做适当的排除操作 <?xml ...

  9. sparkStreaming消费kafka-1.0.1方式:direct方式(存储offset到zookeeper)-- 2

    参考上篇博文:https://www.cnblogs.com/niutao/p/10547718.html 同样的逻辑,不同的封装 package offsetInZookeeper /** * Cr ...

随机推荐

  1. 【BZOJ1997】[Hnoi2010]Planar 2-SAT

    [BZOJ1997][Hnoi2010]Planar Description Input Output Sample Input 2 6 9 1 4 1 5 1 6 2 4 2 5 2 6 3 4 3 ...

  2. Fraction

    Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission ...

  3. TestClass必须是public的

    运行一个测试类遇到一下问题: namespace TestSample.Sample {     [TestClass]     class CynthiaTest     {         [Te ...

  4. api文档的书写

    写文档写要与写代码一样,增加复用. 比如 model 说明就只需要一个,api中含有哪些字段,就在api说明中增加到那些 models 的链接. 使用 sophinx 如何生成目录 .. toctre ...

  5. 【python】-- Django Form

    Django  Form Django的Form主要具有一下几大功能: 生成HTML标签 验证用户数据(显示错误信息) HTML Form提交保留上次提交数据 初始化页面显示内容(自定义样式) 一.F ...

  6. Oracle中的in参数的个数限制

    遇到了这个问题 “oracle中in参数个数限制”,这里记录下, in后括号中的参数个数有限制,Oracle 9i 中个数不能超过256,Oracle 10g个数不能超过1000. 当in的个数大于1 ...

  7. js验证表单大全1

    附加:js验证radio是否选择 <script language="javascript"> function checkform(obj) { for(i=0;i& ...

  8. kubernetes 搭建教程

    http://blog.csdn.net/u011563903/article/details/71037093

  9. Unity3D游戏开发从零单排(六) - 人物运动及攻击连击

    提要 今天要实现的是一个简单人物控制器. 包括用w,a,s,d来控制人物上下左右跑动,鼠标左击发出连招,都是基于老的lagacy的动画.尽管unity3d自带有charactorcontroller, ...

  10. 024-Spring Boot 应用的打包和部署

    一.概述 二.手工打包[不推荐] 打包命令:maven clean package 打包并导出依赖:maven clean package dependency:copy-dependencies 1 ...