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;
}
}