相关文章推荐

Apache Kafka版本0.10.1.0起。请注意, KAFKA-7044 可能会导致喷口崩溃,因此,如果您使用的是受影响的版本(1.1.0、1.1.1或2.0.0),则应升级Kafka。

作为拓扑的一部分写入Kafka

您可以创建org.apache.storm.kafka.bolt的实例。KafkaBolt并将其作为组件附加到您的拓扑,或者如果您正在使用trident,则可以使用org.apache.storm.kafka.trident。TridentState,org.apache.storm.kafka.trident。TridentStateFactory和org.apache.storm.kafka.trident。TridentKafkaUpdater。

您需要提供以下2个接口的实现

TupleToKafkaMapper和TridentTupleToKafkaMapper

这些接口定义了2种方法:

K getKeyFromTuple(Tuple/TridentTuple tuple);
V getMessageFromTuple(Tuple/TridentTuple tuple);

顾名思义,调用这些方法可将元组映射到Kafka密钥和Kafka消息。如果只希望将一个字段作为键并将一个字段作为值,则可以使用提供的FieldNameBasedTupleToKafkaMapper.java实现。在KafkaBolt中,如果您出于向后兼容的原因使用默认构造函数构造FieldNameBasedTupleToKafkaMapper,则实现将始终查找具有字段名称“ key”和“ message”的字段。另外,您也可以使用非默认构造函数来指定其他键和消息字段。在TridentKafkaState中,您必须指定密钥和消息的字段名称是什么,因为没有默认的构造函数。在构造FieldNameBasedTupleToKafkaMapper的实例时应指定这些参数。

KafkaTopicSelector和三叉戟KafkaTopicSelector

该接口只有一种方法

public interface KafkaTopicSelector {
    String getTopics(Tuple/TridentTuple tuple);

该接口的实现应返回需要将元组的键/消息映射发布到的主题。您可以返回null,并且消息将被忽略。如果您有一个静态主题名称,则可以使用DefaultTopicSelector.java并在构造函数中设置主题的名称。 FieldNameTopicSelector和FieldIndexTopicSelector可以用来选择应该向其发布元组的主题。用户只需要在元组本身中为主题名称指定字段名称或字段索引。当找不到主题名称时, Field*TopicSelector将消息写入默认主题。请确保已创建默认主题。

指定Kafka生产者属性

您可以通过调用提供Storm拓扑中的所有生产者属性KafkaBolt.withProducerProperties()和TridentKafkaStateFactory.withProducerProperties() 。有关更多详细信息,请参见http://kafka.apache.org/documentation.html#newproducerconfigs部分“生产者的重要配置属性”。这些也定义在org.apache.kafka.clients.producer.ProducerConfig

使用通配符kafka主题匹配

您可以通过添加以下配置来进行通配符主题匹配

Config config = new Config();
config.put("kafka.topic.wildcard.match",true);

之后,您可以指定一个通配符主题以进行匹配,例如clickstream。* .log。这将匹配所有与clickstream.my.log,clickstream.cart.log等匹配的流

对于螺栓:

TopologyBuilder builder = new TopologyBuilder();
Fields fields = new Fields("key", "message");
FixedBatchSpout spout = new FixedBatchSpout(fields, 4,
            new Values("storm", "1"),
            new Values("trident", "1"),
            new Values("needs", "1"),
            new Values("javadoc", "1")
spout.setCycle(true);
builder.setSpout("spout", spout, 5);
//set producer properties.
Properties props = new Properties();
props.put("bootstrap.servers", "localhost:9092");
props.put("acks", "1");
props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
KafkaBolt bolt = new KafkaBolt()
        .withProducerProperties(props)
        .withTopicSelector(new DefaultTopicSelector("test"))
        .withTupleToKafkaMapper(new FieldNameBasedTupleToKafkaMapper());
builder.setBolt("forwardToKafka", bolt, 8).shuffleGrouping("spout");
Config conf = new Config();
StormSubmitter.submitTopology("kafkaboltTest", conf, builder.createTopology());

对于三叉戟:

Fields fields = new Fields("word", "count");
FixedBatchSpout spout = new FixedBatchSpout(fields, 4,
        new Values("storm", "1"),
        new Values("trident", "1"),
        new Values("needs", "1"),
        new Values("javadoc", "1")
spout.setCycle(true);
TridentTopology topology = new TridentTopology();
Stream stream = topology.newStream("spout1", spout);
//set producer properties.
Properties props = new Properties();
props.put("bootstrap.servers", "localhost:9092");
props.put("acks", "1");
props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
TridentKafkaStateFactory stateFactory = new TridentKafkaStateFactory()
        .withProducerProperties(props)
        .withKafkaTopicSelector(new DefaultTopicSelector("test"))
        .withTridentTupleToKafkaMapper(new FieldNameBasedTupleToKafkaMapper("word", "count"));
stream.partitionPersist(stateFactory, fields, new TridentKafkaStateUpdater(), new Fields());
Config conf = new Config();
StormSubmitter.submitTopology("kafkaTridentTest", conf, topology.build());

从卡夫卡读书(壶嘴)

通过使用以下命令配置喷口实现KafkaSpoutConfig类。此类使用Builder模式,可以通过调用Builders构造函数之一或通过在KafkaSpoutConfig类中调用静态方法builder来启动。

用于创建构建器的构造器或静态方法需要一些键值(以后可以更改),但这是启动喷口所需的最低配置。

bootstrapServers与Kafka消费者属性“ bootstrap.servers”相同。 topics壶嘴将消耗的主题可以是Collection特定主题名称(1个或多个)或正则表达式Pattern ,它指定将使用与该正则表达式匹配的所有主题。

如果您使用的是Builder构造函数,而不是其中一种builder方法,您还需要指定键解串器和值解串器。这是通过使用Java泛型来帮助确保类型安全。可以通过使用以下属性设置的使用者属性来指定反序列化器setProp 。有关详细信息,请参见KafkaConsumer配置文档。

有一些关键配置要注意。

setFirstPollOffsetStrategy允许您设置从何处开始使用数据。在故障恢复和第一次启动喷嘴时都使用此功能。允许的值在FirstPollOffsetStrategy javadocs中列出。

setProcessingGuarantee使您可以配置喷嘴可以提供的处理能力。这会影响消耗的偏移量可以提交的时间以及提交的频率。有关详细信息,请参见ProcessingGuarantee javadoc 。

setRecordTranslator允许您修改喷口将Kafka消费者记录转换为元组的方式,以及该元组将发布到的流中。默认情况下,“主题”,“分区”,“偏移”,“键”和“值”将被发送到“默认”流。如果要根据主题将条目输出到不同的流,storm提供ByTopicRecordTranslator 。有关如何使用它们的更多示例,请参见下文。

setProp和setProps可用于设置KafkaConsumer属性。这些属性的列表可以在Kafka网站上的KafkaConsumer配置文档中找到 。请注意,不支持KafkaConsumer自动提交。如果设置了“ enable.auto.commit”属性,则KafkaSpoutConfig构造函数将引发异常,并且壶嘴使用的使用者将始终将该属性设置为false。您可以配置类似的行为,以通过setProcessingGuarantee KafkaSpoutConfig构建器上的方法。

创建一个简单的不安全喷嘴

下面将使用发布到“主题”的所有事件,并将它们与“主题”,“分区”,“偏移”,“键”,“值”的字段一起发送到MyBolt。

final TopologyBuilder tp = new TopologyBuilder(); tp.setSpout("kafka_spout", new KafkaSpout<>(KafkaSpoutConfig.builder("127.0.0.1:" + port, "topic").build()), 1); tp.setBolt("bolt", new myBolt()).shuffleGrouping("kafka_spout");

通配符主题

通配符主题将从指定代理列表中存在的所有主题中使用,并与模式匹配。因此,在以下示例中,“ topic”,“ topic_foo”和“ topic_bar”将全部与模式“ topic。*”匹配,但“ not_my_topic”将不匹配。

final TopologyBuilder tp = new TopologyBuilder(); tp.setSpout("kafka_spout", new KafkaSpout<>(KafkaSpoutConfig.builder("127.0.0.1:" + port, Pattern.compile("topic.*")).build()), 1); tp.setBolt("bolt", new myBolt()).shuffleGrouping("kafka_spout"); final TopologyBuilder tp = new TopologyBuilder(); //By default all topics not covered by another rule, but consumed by the spout will be emitted to "STREAM_1" as "topic", "key", and "value" ByTopicRecordTranslator<String, String> byTopic = new ByTopicRecordTranslator<>( (r) -> new Values(r.topic(), r.key(), r.value()), new Fields("topic", "key", "value"), "STREAM_1"); //For topic_2 all events will be emitted to "STREAM_2" as just "key" and "value" byTopic.forTopic("topic_2", (r) -> new Values(r.key(), r.value()), new Fields("key", "value"), "STREAM_2"); tp.setSpout("kafka_spout", new KafkaSpout<>(KafkaSpoutConfig.builder("127.0.0.1:" + port, "topic_1", "topic_2", "topic_3").build()), 1); tp.setBolt("bolt", new myBolt()).shuffleGrouping("kafka_spout", "STREAM_1"); tp.setBolt("another", new myOtherBolt()).shuffleGrouping("kafka_spout", "STREAM_2");
final TridentTopology tridentTopology = new TridentTopology();
final Stream spoutStream = tridentTopology.newStream("kafkaSpout",
    new KafkaTridentSpoutOpaque<>(KafkaSpoutConfig.builder("127.0.0.1:" + port, Pattern.compile("topic.*")).build()))
      .parallelismHint(1)

Trident不支持多个流,并且将忽略为输出设置的任何流。但是,如果每个输出主题的字段都不相同,它将抛出异常,并且不会继续。

使用storm-kafka-client的示例拓扑可以在Storm源或二进制发行版中包含的examples / storm-kafka-client-examples目录中找到。

自定义RecordTranslators(高级)

在大多数情况下,内置的SimpleRecordTranslator和ByTopicRecordTranslator应该可以解决您的用例。如果确实遇到需要定制的情况,那么本文档将描述如何正确执行此操作,以及涉及的一些不太明显的类。

要点apply是采取一个ConsumerRecord并将其变成一个List可以发出。不明显的是如何告诉喷口将其发射到特定流。为此,您需要返回一个实例org.apache.storm.kafka.spout.KafkaTuple 。这提供了一种方法routedTo那将说明元组应该去哪个特定流。

return new KafkaTuple(1, 2, 3, 4).routedTo("bar");

将导致元组在“ bar”流上发出。

编写自定义记录翻译器时要小心,因为就像在风暴喷口中一样,它也必须自洽。的streams方法应该返回该转换器将尝试发射的完整的流集。另外getFieldsFor应该为每个流返回一个有效的Fields对象。如果您要对三叉戟执行此操作,则值必须在由返回的列表中apply对于该流的Fields对象中的每个字段,否则三叉戟可能会引发异常。

手动分区分配(高级)

默认情况下,将使用循环策略为KafkaSpout实例分配分区。如果您需要自定义分区分配,则必须实施ManualPartitioner接口。您可以将实现传递给KafkaSpoutConfig.Builder构造函数。提供自定义实现时请多加注意,因为不正确ManualPartitioner实现可能会使某些分区无法读取,或被多个spout实例同时读取。见RoundRobinManualPartitioner有关如何实现此功能的示例。

手动分区发现

您可以通过实施以下操作来自定义喷口发现现有分区的方式TopicFilter接口。Storm-kafka-client附带了一些实现。喜欢ManualPartitioner ,您可以将实现传递给KafkaSpoutConfig.Builder构造函数。请注意TopicFilter仅负责发现分区,确定要订阅哪个发现分区是ManualPartitioner 。

将storm-kafka-client与不同版本的kafka一起使用

Storm-kafka-client的Kafka依赖项定义为provided Maven中的作用域,这意味着它不会作为传递依赖项引入。这使您可以使用与您的kafka集群兼容的Kafka依赖版本。

当使用storm-kafka-client构建项目时,必须显式添加Kafka客户端依赖项。例如,要使用Kafka-clients 0.10.0.0,请在您的计算机上使用以下依赖项pom.xml :

        <dependency>
            <groupId>org.apache.kafka</groupId>
            <artifactId>kafka-clients</artifactId>
            <version>0.10.0.0</version>
        </dependency>

您还可以使用参数从Maven构建时覆盖kafka客户端版本storm.kafka.client.version例如mvn clean install -Dstorm.kafka.client.version=0.10.0.0

选择kafka客户端版本时,应确保-1。Kafka api必须兼容。storm-kafka-client模块仅支持Kafka 0.10或更高版本 。对于较旧的版本,您可以使用storm-kafka模块( https://github.com/apache/storm/tree/1.x-branch/external/storm-kafka )。
2。您选择的Kafka客户端版本应与代理完全兼容。请参阅Kafka兼容性矩阵 。

Kafka Spout性能调优

Kafka喷嘴提供两个内部参数来控制其性能。可以使用setOffsetCommitPeriodMs和setMaxUncommittedOffsets方法设置参数。

  • “ offset.commit.period.ms”控制喷口提交给Kafka的频率
  • “ max.uncommitted.offsets”控制在进行另一个轮询之前可以挂起多少个偏移量的提交
  • Kafka使用者配置参数也可能会影响出水嘴的性能。以下Kafka参数可能是对壶嘴性能影响最大的参数:

  • “ fetch.min.bytes”
  • “ fetch.max.wait.ms”
  • Kafka Consumer实例轮询超时,它使用setPollTimeoutMs方法为每个Kafka出口指定。

    根据您的Kafka群集的结构,数据的分布以及要轮询的数据的可用性,必须适当配置这些参数。请参阅有关Kafka参数调整的Kafka文档。

    目前,Kafka喷口具有以下默认值,如本博文所述,这些默认值已证明在测试环境中具有良好的性能。

  • poll.timeout.ms = 200
  • offset.commit.period.ms = 30000(30s)
  • 最大未提交偏移量= 10000000
  • 默认情况下,当处理保证为AT_LEAST_ONCE时,喷嘴仅跟踪发出的元组。可能有必要使用其他处理保证来跟踪发出的元组,以便从Storm功能中受益,例如在UI中显示完整的延迟,或者使用Config启用背压。TOPOLOGY_MAX_SPOUT_PENDING。

    KafkaSpoutConfig<String, String> kafkaConf = KafkaSpoutConfig
      .builder(String bootstrapServers, String ... topics)
      .setProcessingGuarantee(ProcessingGuarantee.AT_MOST_ONCE)
      .setTupleTrackingEnforced(true)
    

    注意:此设置对AT_LEAST_ONCE处理保证无效,因为需要进行元组跟踪并因此始终启用该跟踪。

    从映射storm-kafka至storm-kafka-client喷口特性

    这可能不是详尽的清单,因为storm-kafka配置来自Storm 0.9.6 SpoutConfig和KafkaConfig 。 storm-kafka-client喷口配置来自Storm 1.0.6 KafkaSpoutConfig和Kafka 0.10.1.0 ConsumerConfig 。

    SpoutConfig KafkaSpoutConfig / ConsumerConfig KafkaSpoutConfig的用法 设置: startOffsetTime

    默认: EarliestTime
    ________________________________________________
    设置: forceFromStart

    默认: false

    startOffsetTime和forceFromStart一起确定起始偏移量。 forceFromStart确定是否忽略Zookeeper偏移量。 startOffsetTime设置确定起始偏移量的时间戳,以防Zookeeper中没有偏移量,或者忽略Zookeeper偏移量 设置: FirstPollOffsetStrategy

    默认: UNCOMMITTED_EARLIEST

    请参考助手表进行选择FirstPollOffsetStrategy根据您的startOffsetTime和forceFromStart设定 .setFirstPollOffsetStrategy() 设置: scheme

    该接口指定如何ByteBuffer从Kafka主题转换为Storm tuple
    默认: RawMultiScheme 设置: Deserializers .setProp(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, )

    .setProp(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, ) 设置: fetchSizeBytes

    消息提取大小-尝试在一个请求中提取到Kafka服务器的字节数
    默认: 1MB 设置: max.partition.fetch.bytes .setProp(ConsumerConfig.MAX_PARTITION_FETCH_BYTES_CONFIG, ) 设置: bufferSizeBytes

    网络请求的缓冲区大小(以字节为单位)。消费者用于从生产者提取数据的缓冲区大小
    默认: 1MB 设置: receive.buffer.bytes .setProp(ConsumerConfig.RECEIVE_BUFFER_CONFIG, ) 设置: socketTimeoutMs

    默认: 10000 设置: useStartOffsetTimeIfOffsetOutOfRange

    默认: true 设置: auto.offset.reset

    默认值:请注意auto.offset.reset是earliest如果你有ProcessingGuarantee调成AT_LEAST_ONCE ,但默认值为latest除此以外。 .setProp(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, ) 设置: fetchMaxWait

    等待响应的最长时间(以毫秒为单位)
    默认: 10000 设置: fetch.max.wait.ms .setProp(ConsumerConfig.FETCH_MAX_WAIT_MS_CONFIG, ) 设置: maxOffsetBehind

    指定喷口尝试重试失败的元组的时间。一种情况是失败的元组的偏移量大于maxOffsetBehind在缩进的偏移量之后,喷嘴将停止重试元组。
    默认: LONG.MAX_VALUE 设置: clientId 设置: client.id .setProp(ConsumerConfig.CLIENT_ID_CONFIG, )

    如果使用此表升级拓扑以使用storm-kafka-client代替storm-kafka ,那么您还需要将消费者补偿从ZooKeeper迁移到Kafka经纪人。使用storm-kafka-migration工具来迁移Kafka消费者补偿。

    设置助手表FirstPollOffsetStrategy

    挑选并设置FirstPollOffsetStrategy基于startOffsetTime和forceFromStart设置:

    startOffsetTime forceFromStart FirstPollOffsetStrategy EarliestTime EARLIEST EarliestTime false UNCOMMITTED_EARLIEST LatestTime LATEST LatestTime false UNCOMMITTED_LATEST
    Apache Storm,Apache,Apache Feather徽标和Apache Storm项目徽标是The Apache Software Foundation的商标。
    提及的所有其他商标可能是其各自所有者的商标或注册商标。

     
    推荐文章