具有相同消费者群组ID

时间:2018-05-27 11:27:32

标签: apache-spark apache-kafka spark-streaming

我正在尝试对消费者群体进行实验

这是我的代码段

public final class App {

private static final int INTERVAL = 5000;

public static void main(String[] args) throws Exception {

    Map<String, Object> kafkaParams = new HashMap<>();
    kafkaParams.put("bootstrap.servers", "xxx:9092");
    kafkaParams.put("key.deserializer", StringDeserializer.class);
    kafkaParams.put("value.deserializer", StringDeserializer.class);
    kafkaParams.put("auto.offset.reset", "earliest");
    kafkaParams.put("enable.auto.commit", true);
    kafkaParams.put("auto.commit.interval.ms","1000");
    kafkaParams.put("security.protocol","SASL_PLAINTEXT");
    kafkaParams.put("sasl.kerberos.service.name","kafka");
    kafkaParams.put("retries","3");
    kafkaParams.put(GROUP_ID_CONFIG,"mygroup");
    kafkaParams.put("request.timeout.ms","210000");
    kafkaParams.put("session.timeout.ms","180000");
    kafkaParams.put("heartbeat.interval.ms","3000");
    Collection<String> topics = Arrays.asList("venkat4");

    SparkConf conf = new SparkConf();
    JavaStreamingContext ssc = new JavaStreamingContext(conf, new Duration(INTERVAL));


    final JavaInputDStream<ConsumerRecord<String, String>> stream =
            KafkaUtils.createDirectStream(
                    ssc,
                    LocationStrategies.PreferConsistent(),
                    ConsumerStrategies.<String, String>Subscribe(topics, kafkaParams)
            );

    stream.mapToPair(
            new PairFunction<ConsumerRecord<String, String>, String, String>() {
                @Override
                public Tuple2<String, String> call(ConsumerRecord<String, String> record) {
                    return new Tuple2<>(record.key(), record.value());
                }
            }).print();


    ssc.start();
    ssc.awaitTermination();


}

}

当我同时运行两个这个火花流工作时,它失败并出现错误

  

线程“main”中的异常java.lang.IllegalStateException:没有分区venkat4-1的当前赋值       at org.apache.kafka.clients.consumer.internals.SubscriptionState.assignedState(SubscriptionState.java:251)       at org.apache.kafka.clients.consumer.internals.SubscriptionState.needOffsetReset(SubscriptionState.java:315)       在org.apache.kafka.clients.consumer.KafkaConsumer.seekToEnd(KafkaConsumer.java:1170)       在org.apache.spark.streaming.kafka010.DirectKafkaInputDStream.latestOffsets(DirectKafkaInputDStream.scala:197)       at org.apache.spark.streaming.kafka010.DirectKafkaInputDStream.compute(DirectKafkaInputDStream.scala:214)       在org.apache.spark.streaming.dstream.DStream $$ anonfun $ getOrCompute $ 1 $$ anonfun $ 1 $$ anonfun $ apply $ 7.apply(DStream.scala:341)       在org.apache.spark.streaming.dstream.DStream $$ anonfun $ getOrCompute $ 1 $$ anonfun $ 1 $$ anonfun $ apply $ 7.apply(DStream.scala:341)       在scala.util.DynamicVariable.withValue(DynamicVariable.scala:58)       在org.apache.spark.streaming.dstream.DStream $$ anonfun $ getOrCompute $ 1 $$ anonfun $ 1.apply(DStream.scala:340)       在org.apache.spark.streaming.dstream.DStream $$ anonfun $ getOrCompute $ 1 $$ anonfun $ 1.apply(DStream.scala:340)       在org.apache.spark.streaming.dstream.DStream.createRDDWithLocalProperties(DStream.scala:415)       在org.apache.spark.streaming.dstream.DStream $$ anonfun $ getOrCompute $ 1.apply(DStream.scala:335)       在org.apache.spark.streaming.dstream.DStream $$ anonfun $ getOrCompute $ 1.apply(DStream.scala:333)       在scala.Option.orElse(Option.scala:289)

根据此https://www.wisdomjobs.com/e-university/apache-kafka-tutorial-1342/apache-kafka-consumer-group-example-19004.html创建具有相同组的kafka使用者的单独实例将创建分区的重新平衡。我相信消费者不会容忍再平衡。我应该如何解决这个问题

以下是使用的命令

SPARK_KAFKA_VERSION = 0.10 spark2-submit --num-executors 2 --master yarn --deploy-mode client --files jaas.conf#jaas.conf,hive.keytab #hive.keytab --driver-java-options “-Djava.security.auth.login.config =。/ jaas.conf”--class Streaming.App --conf“spark.executor.extraJavaOptions = -Djava.security.auth.login.config =。/ jaas.conf “--conf spark.streaming.kafka.consumer.cache.enabled = false 1-1.0-SNAPSHOT.jar

2 个答案:

答案 0 :(得分:2)

  

根据此https://www.wisdomjobs.com/e-university/apache-kafka-tutorial-1342/apache-kafka-consumer-group-example-19004.html创建具有相同组的kafka使用者的单独实例将创建分区的重新平衡。我相信消费者不会容忍再平衡。我应该如何解决这个问题

enter image description here

现在所有分区仅由一个消费者使用。如果数据摄取率很高,消费者可能会以摄取的速度消耗数据。

enter image description here

向同一个使用者组添加更多使用者以使用主题中的数据并提高使用率。使用这种方法使用Kafka分区和Spark分区之间的1:1并行性进行Spark流式处理。 Spark会在内部处理它。

如果您拥有的消费者数量多于主题分区,则它将处于空闲状态,资源利用率不高。始终建议消费者应小于或等于分区数。

  

如果添加更多进程/线程,Kafka将重新平衡。如果任何消费者或代理无法向ZooKeeper发送心跳,则可以通过Kafka集群重新配置ZooKeeper。

只要任何代理发生故障或向现有主题添加新分区,Kafka就会重新平衡分区存储。这是kafka特定的如何在代理中的分区之间平衡数据。

Spark流在Kafka分区和Spark分区之间提供简单的1:1并行性。如果您未使用ConsumerStragies.Assign提供任何分区详细信息,请使用给定主题的所有分区。

  

Kafka将主题的分区分配给组中的消费者,所以   每个分区仅由组中的一个消费者使用。   Kafka保证消息只能由单个消费者阅读   在小组中。

当您启动第二个spark spark流作业时,另一个使用者尝试使用同一个使用者groupid中的相同分区。所以它引发了错误。

val alertTopics = Array("testtopic")

val kafkaParams = Map[String, Object](
  "bootstrap.servers" -> sparkJobConfig.kafkaBrokers,
  "key.deserializer" -> classOf[StringDeserializer],
  "value.deserializer" -> classOf[StringDeserializer],
  "group.id" -> sparkJobConfig.kafkaConsumerGroup,
  "auto.offset.reset" -> "latest"
)

val streamContext = new StreamingContext(sparkContext, Seconds(sparkJobConfig.streamBatchInterval.toLong))

val streamData = KafkaUtils.createDirectStream(streamContext, PreferConsistent, Subscribe[String, String](alertTopics, kafkaParams))

如果要使用特定于分区的spark作业,请使用以下代码。

val topicPartitionsList =  List(new TopicPartition("topic",1))

val alertReqStream1 = KafkaUtils.createDirectStream(streamContext, PreferConsistent, ConsumerStrategies.Assign(topicPartitionsList, kafkaParams))

https://spark.apache.org/docs/2.2.0/streaming-kafka-0-10-integration.html#consumerstrategies

  

消费者可以使用samegroup.id加入群组。

val topicPartitionsList =  List(new TopicPartition("topic",3), new TopicPartition("topic",4))

    val alertReqStream2 = KafkaUtils.createDirectStream(streamContext, PreferConsistent, ConsumerStrategies.Assign(topicPartitionsList, kafkaParams))

添加两个以上的消费者正在添加到同一个groupid中。

请阅读Spark-Kafka集成指南。 https://spark.apache.org/docs/2.2.0/streaming-kafka-0-10-integration.html

希望这有帮助。

答案 1 :(得分:1)

@Ravikumar对延迟道歉。

我的测试是这样完成的

一个。我的主题有3个分区 湾火花流媒体工作是由两个执行者启动的 - 运行良好。 C。后来我决定用另一个实例扩展它,通过运行另一个带有1个执行器的spark-streaming工作来匹配我的第3个失败的分区。

关于你的陈述: 当您启动第二个spark spark流程作业时,另一个使用者尝试使用同一个使用者groupid中的相同分区。所以它抛出错误 是的,这是完全正确的。但是为什么它不能容忍这里的问题。

引用您突出显示的文档:

  

Kafka将主题的分区分配给组中的消费者,所以   每个分区仅由组中的一个消费者使用。   Kafka保证消息只能由单个消费者阅读   在小组中。无论何时,Kafka都会重新平衡分区存储   代理失败或向现有主题添加新分区。这是   kafka具体如何平衡分区中的数据   经纪人。如果添加更多进程/线程,Kafka将重新平衡。   如果有任何消费者或者,Kafka集群可以重新配置ZooKeeper   经纪人无法向ZooKeeper发送心跳。

这也是我期待的火花流媒体工作。我尝试了普通的kafka客户端,它们能够容忍重新平衡。

您的观点来自文档“缓存由topicpartition和group.id键入,因此对每次调用createDirectStream使用单独的group.id”澄清了我的问题。

另外来自PR https://github.com/apache/spark/pull/21038 - 以下是

  

“当新的消费者加入时,Kafka分区可以被撤销   消费者组重新平衡分区。但目前Spark Kafka   连接器代码确保没有分区撤销方案,所以   试图从撤销的分区获取最新的偏移将抛出   提及JIRA的例外情况。“

很高兴关闭这个帖子。非常感谢您的回复