用Storm处理实时日志
- 之前写过一篇用MapReduce清洗数据,比起MR,在工作中更早使用了Storm进行实时的日志清理
- Storm的输入和输出相当灵活,我处理的主要输入流都是Kafka,输出流有Kafka和Scribe
主类配置Topology
Storm的Topology,代表整个处理流程的逻辑拓扑,在构建TopologyBuilder
实例时,可以设置Spout和Bolt
TopologyBuilder builder = new TopologyBuilder();
builder.setSpout("KAFKA_SPOUT", new KafkaSpout(), kafkaSpoutNum);
builder.setBolt("PARSER_BOLT", new ParserBolt(), parserBoltNum).shuffleGrouping("KAFKA_SPOUT");
- setSpout和setBolt的时候需要指定该Spout和Bolt的ID
- setSpout和setBolt的时候可以指定Spout和Bolt的数量
- setBolt的时候需要说明该Bolt如何消费流入它的数据,本例中流入的数据来自
KafkaSpout
,通过shuffleGrouping
的方式消费
配置完成后提交该topology:
Config conf = new Config();
/* Submit topology */
StormSubmitter.submitTopology(group, conf, builder.createTopology());
Topology就像一个任务框架,业务人员按着这个框架来编程就可以了
Spout负责从数据源处读取数据,吐到拓扑里,因为从Kafka消费数据是很常见的应用,所以直接复用KafkaSpout就好,不用自己另外实现
解析和清洗日志的具体逻辑在Bolt中实现,这里实现了一个ParserBolt
Bolt负责具体计算
- Storm中流淌的数据单元是Tuple,可以由用户自定义
- Bolt可以有多级,最后一级Bolt会定期把结果写到目标存储
- 自己实现的Bolt继承自
BaseBasicBolt
,具体处理逻辑在函数execute()
中实现
public class ParserBolt extends BaseBasicBolt {
public void prepare(Map stormConf, TopologyContext context) {
}
public void execute(Tuple tuple, BasicOutputCollector collector) {
String input = String.valueOf(tuple.getValue(0));
String[] lines = input.split("\n");
for (int i = 0; i < lines.length; i++) {
// process
// writeTo
}
}
public Map<String, Object> getComponentConfiguration() {
Map<String, Object> conf = super.getComponentConfiguration();
if (conf == null) {
conf = new Config();
}
conf.put(Config.TOPOLOGY_TICK_TUPLE_FREQ_SECS, 60); //设置tick的时间为60秒,实现一些定时操作。
return conf;
}
}