Storm1.2.2整合Kafka2.1.1编程

前言

Storm到1版本后发送了很大的变化,很多api都有很多改变。然而网络上的多数教程都是旧版本的api。
导致了这一部分的编程花了我非常非常多的时间阅读官方文档的github上的程序。
而且某些错误是真的难debug。

本文只写一个简单的读取kafka消息的demo
因为编程是简单的,麻烦的是编程之外的细节。
至于编程的问题可以参考官方在github上的example
在storm目录里面也能找到example

环境

Ubuntu18.04
Storm1.2.2
Kafka2.1.1
Zookeeper3.4.13

运行框架

开启zookeeper
开启kafka的broker
开启storm nimbus
开启storm supervisor
开启storm ui

导包

网络环境好可以用maven
但其实所要的jar包基本都放在lib目录下了。
另外需要载下strom-kafka-client.jar和strom-starter.jar
可以去maven官网下

编程

首先声明一个TopologyBuilder

TopologyBuilder tp = new TopologyBuilder();

设置spout和bolt

topologybuilder.setSpout("kafka_spout", new KafkaSpout<>(KafkaSpoutConfig.builder("127.0.0.1:9092", "test").build()), 1);
topologybuilder.setBolt("bolt", new myBolt()).shuffleGrouping("kafka_spout");

如果向更加详细的设置spout
写一个方法生成KafkaSpoutConfig

private static KafkaSpoutConfig newKafkaSpoutConfig(String topic) {
		ByTopicRecordTranslator trans = new ByTopicRecordTranslator<>(
	            (r) -> new Values(r.topic(), r.partition(), r.offset(), r.key(), r.value()),
	            new Fields("topic", "partition", "offset", "key", "value"), "stream1");
		//bootstrapServer 以及topic
        return KafkaSpoutConfig.builder(IPUtil.getUbuntu1()+":9092", topic)
                .setProp(ConsumerConfig.GROUP_ID_CONFIG, "kafkaSpoutTestGroup_" + System.nanoTime())
                .setProp(ConsumerConfig.MAX_PARTITION_FETCH_BYTES_CONFIG, 200)
                .setRecordTranslator(trans)
                .setRetry(getRetryService())
                .setOffsetCommitPeriodMs(10_000)
                .setFirstPollOffsetStrategy(EARLIEST)
                .setMaxUncommittedOffsets(250)
                .build();
    }
    protected static KafkaSpoutRetryService getRetryService() {
        return new KafkaSpoutRetryExponentialBackoff(TimeInterval.microSeconds(500),
            TimeInterval.milliSeconds(2), Integer.MAX_VALUE, TimeInterval.seconds(10));
    }

topologybuilder这样设置

topologybuilder.setSpout("kafka_spout", new KafkaSpout(newKafkaSpoutConfig("test")));

获得storm设置
上面设置的是topology,现在设置的是storm配置

Config stormConf=new Config();
stormConf.setNumWorkers(1);
stormConf.setDebug(true);

其实还有很多设置,topology也是。可以去官网看看,因为太多就不例举了。

上传topology到storm集群
这一步是最最重要的!
首先要告诉集群上传的topology的jar包叫什么名字。

System.setProperty("storm.jar", "storm-test.jar");

然后才上传

StormSubmitter.submitTopology("testtopology", stormConf, topologybuilder.createTopology());

上传有很多方式,你可以StormSubmitter的方法,里面还有很多其他参数的上传方式,你可以通过看源码知道其运行方式。
上传写是写完了,但还不行。还有需要注意的地方。继续看。

本文最重要的地方

如果只是像上文那样写完了是不行的。虽然这以及是最终的代码。
因为你还要做两个操作
1.将整个项目export成jar包,
export->JAR file -> Export all output folders for checked projects -> next -> next -> generate the manifest file->seal the jar -> finsh。

2.将需要的外部文件放到storm目录下的exlib目录里,这一步非常重要。
因为我们用kafka,所以记得把kafka的jar包放到exlib里面。

原因:本地可以读取本地文件系统及java项目中的文件,但是提交集群后就不能读取了,storm只是将topology提交到了集群,所以只能在main方法中将需要读取的配置在提交topology之前读出来,然后再解析,而不是在spout和bolt中读取配置文件;参考-》storm本地可以运行集群出错遇到的问题

打包成jar包后放在项目根目录。
配合System.setProperty(“storm.jar”, “storm-test.jar”);这个语句就可以远程发送topology。
然后就成功了。

整份代码参考

KafkaTopoDemo

package stormtest;

import static org.apache.storm.kafka.spout.KafkaSpoutConfig.FirstPollOffsetStrategy.EARLIEST;

import org.apache.kafka.clients.consumer.ConsumerConfig;
import org.apache.storm.Config;
import org.apache.storm.StormSubmitter;
import org.apache.storm.generated.AlreadyAliveException;
import org.apache.storm.generated.AuthorizationException;
import org.apache.storm.generated.InvalidTopologyException;
import org.apache.storm.generated.StormTopology;
import org.apache.storm.kafka.spout.ByTopicRecordTranslator;
import org.apache.storm.kafka.spout.KafkaSpout;
import org.apache.storm.kafka.spout.KafkaSpoutConfig;
import org.apache.storm.kafka.spout.KafkaSpoutRetryExponentialBackoff;
import org.apache.storm.kafka.spout.KafkaSpoutRetryService;
import org.apache.storm.kafka.spout.KafkaSpoutRetryExponentialBackoff.TimeInterval;
import org.apache.storm.topology.TopologyBuilder;
import org.apache.storm.tuple.Fields;
import org.apache.storm.tuple.Values;

import datacool.hadoop.common.IPUtil;

public class KafkaTopoDemo {
	public static void main(String[] args) {
		final TopologyBuilder topologybuilder = new TopologyBuilder();
		topologybuilder.setSpout("kafka_spout", new KafkaSpout(newKafkaSpoutConfig("test")));
		topologybuilder.setBolt("bolt", new myBolt()).shuffleGrouping("kafka_spout");
		
		Config stormConf=new Config();
		stormConf.setNumWorkers(1);
		stormConf.setDebug(true);
		try {
			System.setProperty("storm.jar", "storm-test.jar");
			StormSubmitter.submitTopologyAs("testtopology", stormConf, topologybuilder.createTopology(), null, null, "czq");
			StormSubmitter.
			System.out.println("提交完成");
		} catch (AlreadyAliveException e) {
			// TODO Auto-generated catch block
			System.out.println("出现AlreadyAliveException");
			e.printStackTrace();
		} catch (InvalidTopologyException e) {
			// TODO Auto-generated catch block
			System.out.println("出现InvalidTopologyException");
			e.printStackTrace();
		} catch (AuthorizationException e) {
			// TODO Auto-generated catch block
			System.out.println("出现AuthorizationException");
			e.printStackTrace();
		}
    }
	
	private static KafkaSpoutConfig newKafkaSpoutConfig(String topic) {
		ByTopicRecordTranslator trans = new ByTopicRecordTranslator<>(
	            (r) -> new Values(r.topic(), r.partition(), r.offset(), r.key(), r.value()),
	            new Fields("topic", "partition", "offset", "key", "value"), "stream1");
		//bootstrapServer 以及topic
        return KafkaSpoutConfig.builder(IPUtil.getUbuntu1()+":9092", topic)
                .setProp(ConsumerConfig.GROUP_ID_CONFIG, "kafkaSpoutTestGroup_" + System.nanoTime())
                .setProp(ConsumerConfig.MAX_PARTITION_FETCH_BYTES_CONFIG, 200)
                .setRecordTranslator(trans)
                .setRetry(getRetryService())
                .setOffsetCommitPeriodMs(10_000)
                .setFirstPollOffsetStrategy(EARLIEST)
                .setMaxUncommittedOffsets(250)
                .build();
    }
	
	protected static KafkaSpoutRetryService getRetryService() {
        return new KafkaSpoutRetryExponentialBackoff(TimeInterval.microSeconds(500),
            TimeInterval.milliSeconds(2), Integer.MAX_VALUE, TimeInterval.seconds(10));
    }
}

Bolt

package stormtest;

import java.io.FileWriter;
import java.io.IOException;
import java.util.Map;

import org.apache.storm.task.OutputCollector;
import org.apache.storm.task.TopologyContext;
import org.apache.storm.topology.IRichBolt;
import org.apache.storm.topology.OutputFieldsDeclarer;
import org.apache.storm.tuple.Tuple;

public class myBolt implements IRichBolt {
	private FileWriter fileWriter;
	@Override
	public void prepare(Map stormConf, TopologyContext context, OutputCollector collector) {
		// TODO Auto-generated method stub
		try {
			System.out.println("准备filewriter");
			fileWriter = new FileWriter("/home/czq/tmp/please.txt");
			System.out.println("filewriter准备成功");
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	@Override
	public void execute(Tuple input) {
		// TODO Auto-generated method stub
		System.out.println(input);
		try {
			System.out.println("准备输出");
			fileWriter.write(input.getStringByField("value")+"\n");
			fileWriter.flush();
			System.out.println("输出成功");
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}

	@Override
	public void cleanup() {
		// TODO Auto-generated method stub

	}

	@Override
	public void declareOutputFields(OutputFieldsDeclarer declarer) {
		// TODO Auto-generated method stub

	}

	@Override
	public Map getComponentConfiguration() {
		// TODO Auto-generated method stub
		return null;
	}

}

你可能感兴趣的:(Hadoop,Storm,Kafka)