Flume+kafka+storm整合

ubuntu虚拟机搭建hadoop+spark+zookeeper+hbase+kafka环境 准备工作(软件所需及作用) 1.1- vmware安装包,ubuntu系统 --> 搭建虚拟机环境 1.2- jdk --> 安装java环境 1.3- xshell --> 本机可以连接虚拟机,可选择其他 1.4- scala --> 虚拟机用到的编程环境,可选择其他 1.5- hadoop --> 搭建hadoop环境 1.6- spark --> 搭建spark环境 注- (软件如有需,文章后面会有网盘链接) 流程大致说明:为了简化操作,选用了图形版ubuntu.. 阅读详情

本篇文章转自http://shiyanjun.cn/archives/934.html,谢谢作者的分享

在基于Hadoop平台的很多应用场景中,我们需要对数据进行离线和实时分析,离线分析可以很容易地借助于Hive来实现统计分析,但是对于实时的需求Hive就不合适了。实时应用场景可以使用Storm,它是一个实时处理系统,它为实时处理类应用提供了一个计算模型,可以很容易地进行编程处理。为了统一离线和实时计算,一般情况下,我们都希望将离线和实时计算的数据源的集合统一起来作为输入,然后将数据的流向分别经由实时系统和离线分析系统,分别进行分析处理,这时我们可以考虑将数据源(如使用Flume收集日志)直接连接一个消息中间件,如Kafka,可以整合Flume+Kafka,Flume作为消息的Producer,生产的消息数据(日志数据、业务请求数据等等)发布到Kafka中,然后通过订阅的方式,使用Storm的Topology作为消息的Consumer,在Storm集群中分别进行如下两个需求场景的处理:

  • 直接使用Storm的Topology对数据进行实时分析处理
  • 整合Storm+HDFS,将消息处理后写入HDFS进行离线分析处理

实时处理,只要开发满足业务需要的Topology即可,不做过多说明。这里,我们主要从安装配置Kafka、Storm,以及整合Kafka+Storm、整合Storm+HDFS、整合Kafka+Storm+HDFS这几点来配置实践,满足上面提出的一些需求。配置实践使用的软件包如下所示:

  • zookeeper-3.4.5.tar.gz
  • kafka_2.9.2-0.8.1.1.tgz
  • apache-storm-0.9.2-incubating.tar.gz
  • hadoop-2.2.0.tar.gz

程序配置运行所基于的操作系统为CentOS 5.11。

Kafka安装配置

我们使用3台机器搭建Kafka集群:

192.168.4.142   h1
192.168.4.143   h2
192.168.4.144   h3

在安装Kafka集群之前,这里没有使用Kafka自带的Zookeeper,而是独立安装了一个Zookeeper集群,也是使用这3台机器,保证Zookeeper集群正常运行。 首先,在h1上准备Kafka安装文件,执行如下命令:

cd /usr/local/
wget http://mirror.bit.edu.cn/apache/kafka/0.8.1.1/kafka_2.9.2-0.8.1.1.tgz
tar xvzf kafka_2.9.2-0.8.1.1.tgz
ln -s /usr/local/kafka_2.9.2-0.8.1.1 /usr/local/kafka
chown -R kafka:kafka /usr/local/kafka_2.9.2-0.8.1.1 /usr/local/kafka

修改配置文件/usr/local/kafka/config/server.properties,修改如下内容:

broker.id=0
zookeeper.connect=h1:2181,h2:2181,h3:2181

然后,将配置好的安装文件同步到其他的h2、h3节点上:

scp -r /usr/local/kafka_2.9.2-0.8.1.1/ h2:/usr/local/
scp -r /usr/local/kafka_2.9.2-0.8.1.1/ h3:/usr/local/

最后,在h2、h3节点上配置,执行如下命令:

cd /usr/local/
ln -s /usr/local/kafka_2.9.2-0.8.1.1 /usr/local/kafka
chown -R kafka:kafka /usr/local/kafka_2.9.2-0.8.1.1 /usr/local/kafka

并修改配置文件/usr/local/kafka/config/server.properties内容如下所示:

broker.id=1  # 在h1修改

broker.id=2  # 在h2修改

因为Kafka集群需要保证各个Broker的id在整个集群中必须唯一,需要调整这个配置项的值(如果在单机上,可以通过建立多个Broker进程来模拟分布式的Kafka集群,也需要Broker的id唯一,还需要修改一些配置目录的信息)。 在集群中的h1、h2、h3这三个节点上分别启动Kafka,分别执行如下命令:

bin/kafka-server-start.sh /usr/local/kafka/config/server.properties &

可以通过查看日志,或者检查进程状态,保证Kafka集群启动成功。 我们创建一个名称为my-replicated-topic5的Topic,5个分区,并且复制因子为3,执行如下命令:

bin/kafka-topics.sh --create --zookeeper h1:2181,h2:2181,h3:2181 --replication-factor 3 --partitions 5 --topic my-replicated-topic5

查看创建的Topic,执行如下命令:

bin/kafka-topics.sh --describe --zookeeper h1:2181,h2:2181,h3:2181 --topic my-replicated-topic5

结果信息如下所示:

Topic:my-replicated-topic5	PartitionCount:5	ReplicationFactor:3	Configs:
  Topic: my-replicated-topic5	Partition: 0	Leader: 0	Replicas: 0,2,1	Isr: 0,2,1
  Topic: my-replicated-topic5	Partition: 1	Leader: 0	Replicas: 1,0,2	Isr: 0,2,1
  Topic: my-replicated-topic5	Partition: 2	Leader: 2	Replicas: 2,1,0	Isr: 2,0,1
  Topic: my-replicated-topic5	Partition: 3	Leader: 0	Replicas: 0,1,2	Isr: 0,2,1
  Topic: my-replicated-topic5	Partition: 4	Leader: 2	Replicas: 1,2,0	Isr: 2,0,1

上面Leader、Replicas、Isr的含义如下:

Partition: 分区
Leader   : 负责读写指定分区的节点
Replicas : 复制该分区log的节点列表
Isr      : "in-sync" replicas,当前活跃的副本列表(是一个子集),并且可能成为Leader

我们可以通过Kafka自带的bin/kafka-console-producer.sh和bin/kafka-console-consumer.sh脚本,来验证演示如果发布消息、消费消息。 在一个终端,启动Producer,并向我们上面创建的名称为my-replicated-topic5的Topic中生产消息,执行如下脚本:

bin/kafka-console-producer.sh --broker-list h1:9092,h2:9092,h3:9092 --topic my-replicated-topic5

在另一个终端,启动Consumer,并订阅我们上面创建的名称为my-replicated-topic5的Topic中生产的消息,执行如下脚本:

bin/kafka-console-consumer.sh --zookeeper h1:2181,h2:2181,h3:2181 --from-beginning --topic my-replicated-topic5

可以在Producer终端上输入字符串消息行,然后回车,就可以在Consumer终端上看到消费者消费的消息内容。 也可以参考Kafka的Producer和Consumer的Java API,通过API编码的方式来实现消息生产和消费的处理逻辑。

Storm安装配置

Storm集群也依赖Zookeeper集群,要保证Zookeeper集群正常运行。Storm的安装配置比较简单,我们仍然使用下面3台机器搭建:

192.168.4.142   h1
192.168.4.143   h2
192.168.4.144   h3

首先,在h1节点上,执行如下命令安装:

cd /usr/local/
wget http://mirror.bit.edu.cn/apache/incubator/storm/apache-storm-0.9.2-incubating/apache-storm-0.9.2-incubating.tar.gz
tar xvzf apache-storm-0.9.2-incubating.tar.gz
ln -s /usr/local/apache-storm-0.9.2-incubating /usr/local/storm
chown -R storm:storm /usr/local/apache-storm-0.9.2-incubating /usr/local/storm

然后,修改配置文件conf/storm.yaml,内容如下所示:

storm.zookeeper.servers:
  - "h1"
  - "h2"
  - "h3"
storm.zookeeper.port: 2181
#
nimbus.host: "h1"

supervisor.slots.ports:
    - 6700
    - 6701
    - 6702
    - 6703

storm.local.dir: "/tmp/storm"

将配置好的安装文件,分发到其他节点上:

scp -r /usr/local/apache-storm-0.9.2-incubating/ h2:/usr/local/
scp -r /usr/local/apache-storm-0.9.2-incubating/ h3:/usr/local/

最后,在h2、h3节点上配置,执行如下命令:

cd /usr/local/
ln -s /usr/local/apache-storm-0.9.2-incubating /usr/local/storm
chown -R storm:storm /usr/local/apache-storm-0.9.2-incubating /usr/local/storm

Storm集群的主节点为Nimbus,从节点为Supervisor,我们需要在h1上启动Nimbus服务,在从节点h2、h3上启动Supervisor服务:

bin/storm nimbus &
bin/storm supervisor &

为了方便监控,可以启动Storm UI,可以从Web页面上监控Storm Topology的运行状态,例如在h2上启动:

bin/storm ui &

这样可以通过访问 http://h2:8080/ 来查看Topology的运行状况。

整合Kafka+Storm

消息通过各种方式进入到Kafka消息中间件,比如可以通过使用Flume来收集日志数据,然后在Kafka中路由暂存,然后再由实时计算程序Storm做实时分析,这时我们就需要将在Storm的Spout中读取Kafka中的消息,然后交由具体的Spot组件去分析处理。实际上,apache-storm-0.9.2-incubating这个版本的Storm已经自带了一个集成Kafka的外部插件程序storm-kafka,可以直接使用,例如我使用的Maven依赖配置,如下所示:

<dependency>
      <groupId>org.apache.storm</groupId>
      <artifactId>storm-core</artifactId>
      <version>0.9.2-incubating</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>org.apache.storm</groupId>
      <artifactId>storm-kafka</artifactId>
      <version>0.9.2-incubating</version>
    </dependency>
    <dependency>
      <groupId>org.apache.kafka</groupId>
      <artifactId>kafka_2.9.2</artifactId>
      <version>0.8.1.1</version>
      <exclusions>
        <exclusion>
          <groupId>org.apache.zookeeper</groupId>
          <artifactId>zookeeper</artifactId>
        </exclusion>
        <exclusion>
          <groupId>log4j</groupId>
          <artifactId>log4j</artifactId>
        </exclusion>
      </exclusions>
    </dependency>

下面,我们开发了一个简单WordCount示例程序,从Kafka读取订阅的消息行,通过空格拆分出单个单词,然后再做词频统计计算,实现的Topology的代码,如下所示:

package org.shirdrn.storm.examples;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.atomic.AtomicInteger;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import storm.kafka.BrokerHosts;
import storm.kafka.KafkaSpout;
import storm.kafka.SpoutConfig;
import storm.kafka.StringScheme;
import storm.kafka.ZkHosts;
import backtype.storm.Config;
import backtype.storm.LocalCluster;
import backtype.storm.StormSubmitter;
import backtype.storm.generated.AlreadyAliveException;
import backtype.storm.generated.InvalidTopologyException;
import backtype.storm.spout.SchemeAsMultiScheme;
import backtype.storm.task.OutputCollector;
import backtype.storm.task.TopologyContext;
import backtype.storm.topology.OutputFieldsDeclarer;
import backtype.storm.topology.TopologyBuilder;
import backtype.storm.topology.base.BaseRichBolt;
import backtype.storm.tuple.Fields;
import backtype.storm.tuple.Tuple;
import backtype.storm.tuple.Values;

public class MyKafkaTopology {

  public static class KafkaWordSplitter extends BaseRichBolt {

    private static final Log LOG = LogFactory.getLog(KafkaWordSplitter.class);
    private static final long serialVersionUID = 886149197481637894L;
    private OutputCollector collector;
      
    @Override
    public void prepare(Map stormConf, TopologyContext context,
        OutputCollector collector) {
      this.collector = collector;		    
    }

    @Override
    public void execute(Tuple input) {
      String line = input.getString(0);
      LOG.info("RECV[kafka -> splitter] " + line);
      String[] words = line.split("\\s+");
      for(String word : words) {
        LOG.info("EMIT[splitter -> counter] " + word);
        collector.emit(input, new Values(word, 1));
      }
      collector.ack(input);
    }

    @Override
    public void declareOutputFields(OutputFieldsDeclarer declarer) {
      declarer.declare(new Fields("word", "count"));	    
    }
      
  }
    
  public static class WordCounter extends BaseRichBolt {

    private static final Log LOG = LogFactory.getLog(WordCounter.class);
    private static final long serialVersionUID = 886149197481637894L;
    private OutputCollector collector;
    private Map<String, AtomicInteger> counterMap;
      
    @Override
    public void prepare(Map stormConf, TopologyContext context,
        OutputCollector collector) {
      this.collector = collector;    
      this.counterMap = new HashMap<String, AtomicInteger>();
    }

    @Override
    public void execute(Tuple input) {
      String word = input.getString(0);
      int count = input.getInteger(1);
      LOG.info("RECV[splitter -> counter] " + word + " : " + count);
      AtomicInteger ai = this.counterMap.get(word);
      if(ai == null) {
        ai = new AtomicInteger();
        this.counterMap.put(word, ai);
      }
      ai.addAndGet(count);
      collector.ack(input);
      LOG.info("CHECK statistics map: " + this.counterMap);
    }

    @Override
    public void cleanup() {
      LOG.info("The final result:");
      Iterator<Entry<String, AtomicInteger>> iter = this.counterMap.entrySet().iterator();
      while(iter.hasNext()) {
        Entry<String, AtomicInteger> entry = iter.next();
        LOG.info(entry.getKey() + "\t:\t" + entry.getValue().get());
      }
        
    }

    @Override
    public void declareOutputFields(OutputFieldsDeclarer declarer) {
      declarer.declare(new Fields("word", "count"));	    
    }
  }
    
  public static void main(String[] args) throws AlreadyAliveException, InvalidTopologyException, InterruptedException {
    String zks = "h1:2181,h2:2181,h3:2181";
    String topic = "my-replicated-topic5";
    String zkRoot = "/storm"; // default zookeeper root configuration for storm
    String id = "word";
      
    BrokerHosts brokerHosts = new ZkHosts(zks);
    SpoutConfig spoutConf = new SpoutConfig(brokerHosts, topic, zkRoot, id);
    spoutConf.scheme = new SchemeAsMultiScheme(new StringScheme());
    spoutConf.forceFromStart = true;
    spoutConf.zkServers = Arrays.asList(new String[] {"h1", "h2", "h3"});
    spoutConf.zkPort = 2181;
      
    TopologyBuilder builder = new TopologyBuilder();
    builder.setSpout("kafka-reader", new KafkaSpout(spoutConf), 5); // Kafka我们创建了一个5分区的Topic,这里并行度设置为5
    builder.setBolt("word-splitter", new KafkaWordSplitter(), 2).shuffleGrouping("kafka-reader");
    builder.setBolt("word-counter", new WordCounter()).fieldsGrouping("word-splitter", new Fields("word"));
      
    Config conf = new Config();
      
    String name = MyKafkaTopology.class.getSimpleName();
    if (args != null && args.length > 0) {
      // Nimbus host name passed from command line
      conf.put(Config.NIMBUS_HOST, args[0]);
      conf.setNumWorkers(3);
      StormSubmitter.submitTopologyWithProgressBar(name, conf, builder.createTopology());
    } else {
      conf.setMaxTaskParallelism(3);
      LocalCluster cluster = new LocalCluster();
      cluster.submitTopology(name, conf, builder.createTopology());
      Thread.sleep(60000);
      cluster.shutdown();
    }
  }
}

上面程序,在本地调试(使用LocalCluster)不需要输入任何参数,提交到实际集群中运行时,需要传递一个参数,该参数为Nimbus的主机名称。 通过Maven构建,生成一个包含依赖的single jar文件(不要把Storm的依赖包添加进去),例如storm-examples-0.0.1-SNAPSHOT.jar,在提交Topology程序到Storm集群之前,因为用到了Kafka,需要拷贝一下依赖jar文件到Storm集群中的lib目录下面:

cp /usr/local/kafka/libs/kafka_2.9.2-0.8.1.1.jar /usr/local/storm/lib/
cp /usr/local/kafka/libs/scala-library-2.9.2.jar /usr/local/storm/lib/
cp /usr/local/kafka/libs/metrics-core-2.2.0.jar /usr/local/storm/lib/
cp /usr/local/kafka/libs/snappy-java-1.0.5.jar /usr/local/storm/lib/
cp /usr/local/kafka/libs/zkclient-0.3.jar /usr/local/storm/lib/
cp /usr/local/kafka/libs/log4j-1.2.15.jar /usr/local/storm/lib/
cp /usr/local/kafka/libs/slf4j-api-1.7.2.jar /usr/local/storm/lib/
cp /usr/local/kafka/libs/jopt-simple-3.2.jar /usr/local/storm/lib/

然后,就可以提交我们开发的Topology程序了:

bin/storm jar /home/storm/storm-examples-0.0.1-SNAPSHOT.jar org.shirdrn.storm.examples.MyKafkaTopology h1

可以通过查看日志文件(logs/目录下)或者Storm UI来监控Topology的运行状况。如果程序没有错误,可以使用前面我们使用的Kafka Producer来生成消息,就能看到我们开发的Storm Topology能够实时接收到并进行处理。

整合Storm+HDFS

Storm实时计算集群从Kafka消息中间件中消费消息,有实时处理需求的可以走实时处理程序,还有需要进行离线分析的需求,如写入到HDFS进行分析。下面实现了一个Topology,代码如下所示:

package org.shirdrn.storm.examples;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import java.util.Random;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.storm.hdfs.bolt.HdfsBolt;
import org.apache.storm.hdfs.bolt.format.DefaultFileNameFormat;
import org.apache.storm.hdfs.bolt.format.DelimitedRecordFormat;
import org.apache.storm.hdfs.bolt.format.FileNameFormat;
import org.apache.storm.hdfs.bolt.format.RecordFormat;
import org.apache.storm.hdfs.bolt.rotation.FileRotationPolicy;
import org.apache.storm.hdfs.bolt.rotation.TimedRotationPolicy;
import org.apache.storm.hdfs.bolt.rotation.TimedRotationPolicy.TimeUnit;
import org.apache.storm.hdfs.bolt.sync.CountSyncPolicy;
import org.apache.storm.hdfs.bolt.sync.SyncPolicy;

import backtype.storm.Config;
import backtype.storm.LocalCluster;
import backtype.storm.StormSubmitter;
import backtype.storm.generated.AlreadyAliveException;
import backtype.storm.generated.InvalidTopologyException;
import backtype.storm.spout.SpoutOutputCollector;
import backtype.storm.task.TopologyContext;
import backtype.storm.topology.OutputFieldsDeclarer;
import backtype.storm.topology.TopologyBuilder;
import backtype.storm.topology.base.BaseRichSpout;
import backtype.storm.tuple.Fields;
import backtype.storm.tuple.Values;
import backtype.storm.utils.Utils;

public class StormToHDFSTopology {

     public static class EventSpout extends BaseRichSpout {

  private static final Log LOG = LogFactory.getLog(EventSpout.class);
  private static final long serialVersionUID = 886149197481637894L;
  private SpoutOutputCollector collector;
  private Random rand;
  private String[] records;
         
  @Override
  public void open(Map conf, TopologyContext context,
    SpoutOutputCollector collector) {
       this.collector = collector;    
       rand = new Random();
       records = new String[] {
         "10001     ef2da82d4c8b49c44199655dc14f39f6     4.2.1     HUAWEI G610-U00     HUAWEI     2     70:72:3c:73:8b:22     2014-10-13 12:36:35",
         "10001     ffb52739a29348a67952e47c12da54ef     4.3     GT-I9300     samsung     2     50:CC:F8:E4:22:E2     2014-10-13 12:36:02",
         "10001     ef2da82d4c8b49c44199655dc14f39f6     4.2.1     HUAWEI G610-U00     HUAWEI     2     70:72:3c:73:8b:22     2014-10-13 12:36:35"
       };
  }


  @Override
  public void nextTuple() {
       Utils.sleep(1000);
       DateFormat df = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss");
       Date d = new Date(System.currentTimeMillis());
       String minute = df.format(d);
       String record = records[rand.nextInt(records.length)];
       LOG.info("EMIT[spout -> hdfs] " + minute + " : " + record);
       collector.emit(new Values(minute, record));
  }

  @Override
  public void declareOutputFields(OutputFieldsDeclarer declarer) {
       declarer.declare(new Fields("minute", "record"));         
  }


     }
    
     public static void main(String[] args) throws AlreadyAliveException, InvalidTopologyException, InterruptedException {
  // use "|" instead of "," for field delimiter
  RecordFormat format = new DelimitedRecordFormat()
          .withFieldDelimiter(" : ");

  // sync the filesystem after every 1k tuples
  SyncPolicy syncPolicy = new CountSyncPolicy(1000);

  // rotate files 
  FileRotationPolicy rotationPolicy = new TimedRotationPolicy(1.0f, TimeUnit.MINUTES);

  FileNameFormat fileNameFormat = new DefaultFileNameFormat()
          .withPath("/storm/").withPrefix("app_").withExtension(".log");

  HdfsBolt hdfsBolt = new HdfsBolt()
          .withFsUrl("hdfs://h1:8020")
          .withFileNameFormat(fileNameFormat)
          .withRecordFormat(format)
          .withRotationPolicy(rotationPolicy)
          .withSyncPolicy(syncPolicy);
         
  TopologyBuilder builder = new TopologyBuilder();
  builder.setSpout("event-spout", new EventSpout(), 3);
  builder.setBolt("hdfs-bolt", hdfsBolt, 2).fieldsGrouping("event-spout", new Fields("minute"));
         
  Config conf = new Config();
         
  String name = StormToHDFSTopology.class.getSimpleName();
  if (args != null && args.length > 0) {
       conf.put(Config.NIMBUS_HOST, args[0]);
       conf.setNumWorkers(3);
       StormSubmitter.submitTopologyWithProgressBar(name, conf, builder.createTopology());
  } else {
       conf.setMaxTaskParallelism(3);
       LocalCluster cluster = new LocalCluster();
       cluster.submitTopology(name, conf, builder.createTopology());
       Thread.sleep(60000);
       cluster.shutdown();
  }
     }

}

上面的处理逻辑,可以对HdfsBolt进行更加详细的配置,如FileNameFormat、SyncPolicy、FileRotationPolicy(可以设置在满足什么条件下,切出一个新的日志,如可以指定多长时间切出一个新的日志文件,可以指定一个日志文件大小达到设置值后,再写一个新日志文件),更多设置可以参考storm-hdfs,。 上面代码在打包的时候,需要注意,使用storm-starter自带的Maven打包配置,可能在将Topology部署运行的时候,会报错,可以使用maven-shade-plugin这个插件,如下配置所示:

<plugin>
           <groupId>org.apache.maven.plugins</groupId>
           <artifactId>maven-shade-plugin</artifactId>
           <version>1.4</version>
           <configuration>
             <createDependencyReducedPom>true</createDependencyReducedPom>
           </configuration>
           <executions>
             <execution>
               <phase>package</phase>
               <goals>
                 <goal>shade</goal>
               </goals>
               <configuration>
                 <transformers>
                   <transformer
                       implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
                   <transformer
                       implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                     <mainClass></mainClass>
                   </transformer>
                 </transformers>
               </configuration>
             </execution>
           </executions>
         </plugin>

整合Kafka+Storm+HDFS

上面分别对整合Kafka+Storm和Storm+HDFS做了实践,可以将后者的Spout改成前者的Spout,从Kafka中消费消息,在Storm中可以做简单处理,然后将数据写入HDFS,最后可以在Hadoop平台上对数据进行离线分析处理。下面,写了一个简单的例子,从Kafka消费消息,然后经由Storm处理,写入到HDFS存储,代码如下所示:

package org.shirdrn.storm.examples;

import java.util.Arrays;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.storm.hdfs.bolt.HdfsBolt;
import org.apache.storm.hdfs.bolt.format.DefaultFileNameFormat;
import org.apache.storm.hdfs.bolt.format.DelimitedRecordFormat;
import org.apache.storm.hdfs.bolt.format.FileNameFormat;
import org.apache.storm.hdfs.bolt.format.RecordFormat;
import org.apache.storm.hdfs.bolt.rotation.FileRotationPolicy;
import org.apache.storm.hdfs.bolt.rotation.TimedRotationPolicy;
import org.apache.storm.hdfs.bolt.rotation.TimedRotationPolicy.TimeUnit;
import org.apache.storm.hdfs.bolt.sync.CountSyncPolicy;
import org.apache.storm.hdfs.bolt.sync.SyncPolicy;

import storm.kafka.BrokerHosts;
import storm.kafka.KafkaSpout;
import storm.kafka.SpoutConfig;
import storm.kafka.StringScheme;
import storm.kafka.ZkHosts;
import backtype.storm.Config;
import backtype.storm.LocalCluster;
import backtype.storm.StormSubmitter;
import backtype.storm.generated.AlreadyAliveException;
import backtype.storm.generated.InvalidTopologyException;
import backtype.storm.spout.SchemeAsMultiScheme;
import backtype.storm.task.OutputCollector;
import backtype.storm.task.TopologyContext;
import backtype.storm.topology.OutputFieldsDeclarer;
import backtype.storm.topology.TopologyBuilder;
import backtype.storm.topology.base.BaseRichBolt;
import backtype.storm.tuple.Fields;
import backtype.storm.tuple.Tuple;
import backtype.storm.tuple.Values;

public class DistributeWordTopology {
    
     public static class KafkaWordToUpperCase extends BaseRichBolt {

  private static final Log LOG = LogFactory.getLog(KafkaWordToUpperCase.class);
  private static final long serialVersionUID = -5207232012035109026L;
  private OutputCollector collector;
         
  @Override
  public void prepare(Map stormConf, TopologyContext context,
    OutputCollector collector) {
       this.collector = collector;	    
  }

  @Override
  public void execute(Tuple input) {
       String line = input.getString(0).trim();
       LOG.info("RECV[kafka -> splitter] " + line);
       if(!line.isEmpty()) {
    String upperLine = line.toUpperCase();
    LOG.info("EMIT[splitter -> counter] " + upperLine);
    collector.emit(input, new Values(upperLine, upperLine.length()));
       }
       collector.ack(input);
  }

  @Override
  public void declareOutputFields(OutputFieldsDeclarer declarer) {
       declarer.declare(new Fields("line", "len"));         
  }
         
     }
    
     public static class RealtimeBolt extends BaseRichBolt {

  private static final Log LOG = LogFactory.getLog(KafkaWordToUpperCase.class);
  private static final long serialVersionUID = -4115132557403913367L;
  private OutputCollector collector;
         
  @Override
  public void prepare(Map stormConf, TopologyContext context,
    OutputCollector collector) {
       this.collector = collector;	    
  }

  @Override
  public void execute(Tuple input) {
       String line = input.getString(0).trim();
       LOG.info("REALTIME: " + line);
       collector.ack(input);
  }

  @Override
  public void declareOutputFields(OutputFieldsDeclarer declarer) {
      
  }

     }

     public static void main(String[] args) throws AlreadyAliveException, InvalidTopologyException, InterruptedException {

  // Configure Kafka
  String zks = "h1:2181,h2:2181,h3:2181";
  String topic = "my-replicated-topic5";
  String zkRoot = "/storm"; // default zookeeper root configuration for storm
  String id = "word";
  BrokerHosts brokerHosts = new ZkHosts(zks);
  SpoutConfig spoutConf = new SpoutConfig(brokerHosts, topic, zkRoot, id);
  spoutConf.scheme = new SchemeAsMultiScheme(new StringScheme());
  spoutConf.forceFromStart = true;
  spoutConf.zkServers = Arrays.asList(new String[] {"h1", "h2", "h3"});
  spoutConf.zkPort = 2181;
         
  // Configure HDFS bolt
  RecordFormat format = new DelimitedRecordFormat()
          .withFieldDelimiter("\t"); // use "\t" instead of "," for field delimiter
  SyncPolicy syncPolicy = new CountSyncPolicy(1000); // sync the filesystem after every 1k tuples
  FileRotationPolicy rotationPolicy = new TimedRotationPolicy(1.0f, TimeUnit.MINUTES); // rotate files
  FileNameFormat fileNameFormat = new DefaultFileNameFormat()
          .withPath("/storm/").withPrefix("app_").withExtension(".log"); // set file name format
  HdfsBolt hdfsBolt = new HdfsBolt()
          .withFsUrl("hdfs://h1:8020")
          .withFileNameFormat(fileNameFormat)
          .withRecordFormat(format)
          .withRotationPolicy(rotationPolicy)
          .withSyncPolicy(syncPolicy);
         
  // configure & build topology
  TopologyBuilder builder = new TopologyBuilder();
  builder.setSpout("kafka-reader", new KafkaSpout(spoutConf), 5);
  builder.setBolt("to-upper", new KafkaWordToUpperCase(), 3).shuffleGrouping("kafka-reader");
  builder.setBolt("hdfs-bolt", hdfsBolt, 2).shuffleGrouping("to-upper");
  builder.setBolt("realtime", new RealtimeBolt(), 2).shuffleGrouping("to-upper");
         
  // submit topology
  Config conf = new Config();
  String name = DistributeWordTopology.class.getSimpleName();
  if (args != null && args.length > 0) {
       String nimbus = args[0];
       conf.put(Config.NIMBUS_HOST, nimbus);
       conf.setNumWorkers(3);
       StormSubmitter.submitTopologyWithProgressBar(name, conf, builder.createTopology());
  } else {
       conf.setMaxTaskParallelism(3);
       LocalCluster cluster = new LocalCluster();
       cluster.submitTopology(name, conf, builder.createTopology());
       Thread.sleep(60000);
       cluster.shutdown();
  }
     }

}

上面代码中,名称为to-upper的Bolt将接收到的字符串行转换成大写以后,会将处理过的数据向后面的hdfs-bolt、realtime这两个Bolt各发一份拷贝,然后由这两个Bolt分别根据实际需要(实时/离线)单独处理。 打包后,在Storm集群上部署并运行这个Topology:

bin/storm jar ~/storm-examples-0.0.1-SNAPSHOT.jar org.shirdrn.storm.examples.DistributeWordTopology h1

可以通过Storm UI查看Topology运行情况,可以查看HDFS上生成的数据。

一百零八、Kettle采集Kafka数据到HDFS(踩坑,亲测有效) Kettle采集Kafka数据到HDFS 阅读详情

相关推荐

大数据NiFi(二十二):Kafka中数据实时导入到HDFS中

连接后,并设置“PutHDFS”处理器“failure”和“success”路由关系为自动终止。此案例使用到“ConsumerKafka_1_0”和“PutHDFS”处理器。“ConsumerKafka_1_0”处理器可以将消费Kafka中的数据。案例:向Kafka某个topic中写入数据,实时导入到HDFS文件中。逗号分割的Kafka集群Broker列表。格式:host:port。Kafka topic名称,多个可以使用逗号分隔。设置读取Kafka topic数据的位置。

Lansonli(蓝深李)的博客 1454

使用Flume消费Kafka数据到HDFS (亲测好用)

1.概述 对于数据的转发,Kafka是一个不错的选择。Kafka能够装载数据到消息队列,然后等待其他业务场景去消费这些数据,Kafka的应用接口API非常的丰富,支持各种存储介质,例如HDFS、HBase等。如果不想使用Kafka API编写代码去消费Kafka Topic,也是有组件可以去集成消费的。下面笔者将为大家介绍如何使用Flume快速消费Kafka Topic数据,然后将消费后的数据转发到HDFS上。 2.内容 在实现这套方案之间,可以先来看看整个数据的流向,如下图所示: 业务数据

song_quan_的博客 7683

Hadoop实时数据处理:Flume+Kafka+Storm整合方案

在当今数字化时代,数据量呈现爆炸式增长,很多场景都需要对数据进行实时处理,比如电商平台的实时销售数据监控、金融市场的实时交易分析等。我们这篇文章的目的就是介绍一种基于Hadoop生态系统的实时数据处理方案,也就是把Flume、Kafka和Storm这三个组件整合起来使用。范围涵盖了这三个组件的基本概念、它们之间的协作原理、具体的代码实现以及实际应用场景等方面。本文首先会解释Flume、Kafka和Storm这三个核心组件的概念,以及它们之间的关系。

软件工程实践的博客 982

Kafka到Hdfs的数据Pipeline整理

作者:Syn良子 出处:http://www.cnblogs.com/cssdongl 转载请注明出处 找时间总结整理了下数据从Kafka到Hdfs的一些pipeline,如下 1> Kafka -> Flume –> Hadoop Hdfs 常用方案,基于配置,需要注意hdfs小文件性能等问题. GitHub地址:  https://github.com/apache/f

易水寒 3326

基于python+mediapipe的手势拖动识别(无gpu)

手势点方块拖动

weixin_38029956的博客 5981

芯片设计流程中的def文件

在实际的DEF文件中,每个部分都包含了与实际设计相关的详细信息,这个模板只展示了每个部分的基本结构。在实际应用中,DEF文件通常由EDA(电子设计自动化)工具在完成布局(Placement)和布线(Routing)步骤后自动生成,在集成电路设计中,DEF(Design Exchange Format)文件的模板具体内容会依设计的复杂性和特定需求而变化。简而言之,LEF文件提供了单元的物理特性和规则,而DEF文件使用这些规则来确定单元。)文件描述了特定设计中所有物理元素的精确放置和连线信息。

qq_36045093的博客 4858

Flume,Kafka与Storm整合

本文参考文章:http://www.cnblogs.com/lion.net/p/3922960.html#top 以及各种官方文档。 1、Kafka与Storm的整合            Kafka与storm的整合就是用Kafka的消费者实现为为storm的数据源spout,用Kafka的stream数据作为storm中spout的数据源。      PS:编写代码的

Jz Shen的专栏 1689

90nm CMOS工艺下6μW超低功耗LDO设计实战:从原理图到版图全解析

本文详细解析了在90nm CMOS工艺下设计一款静态功耗仅为6μW的超低功耗LDO(低压差线性稳压器)的全过程。文章深入探讨了如何通过改进型翻转电压跟随器(FVF)架构实现无输出电容设计,在满足极低功耗和芯片面积高效(chip-area-efficient)要求的同时,确保环路稳定性与快速瞬态响应,为物联网、可穿戴设备等应用提供关键电源管理解决方案。

weixin_29196613的博客 272

flume+kafka+storm集群整合

1.在集群上先启动kafka以及zookeeper 2.进行kafka与flume整合 博主经过好几个小时的研究,最终才整合成功,主要原因在于flume 和kafka有的存在版本冲突,如果你按照我下面的两个版本进行整合,将不会出错,其他版本不保证!安装教程,查看博主的kafka和flume安装步骤即可。 kafka版本为kafka_2.11-0.8.2.2.tgz, 链接...

逆流而上Mr李 826

java对接海康实现页面实时播放和回放

前言:之前已经写过一篇关于视频的文章,因为觉得有很多优化的地方,也谢谢同行们加我微信跟我提了一些需求和意见,所以在过年的假期重新写了一个比较能扩张的版本。 上一个版本的连接:https://blog.youkuaiyun.com/weixin_45848110/article/details/119363602 与之前的版本不同之处: 1.不需要安装ffmpeg 2.不需要安装nginx 3.直接运行jar即可 4.之前是完全脱离海康sdk,回放的录像是保存到本地服务,现在是直接在海康硬盘录像机获取录像回放 5.实时播

weixin_45848110的博客 1万+

Python爬虫实战:如何爬取汽车之家报价信息

本文通过实战介绍了如何使用Python编写爬虫,抓取汽车之家网站的车型、价格、配置等信息。在爬虫实现过程中,我们使用了requests库来发送HTTP请求,使用解析HTML页面,提取嵌入的JSON数据,并将数据存储到CSV文件中。同时,我们还介绍了如何使用反爬虫策略(如随机User-Agent、请求延时、代理池等)来规避反爬虫机制,确保爬虫的稳定性。

2201_76125261的博客 1594

flume+kafka+storm整合文件

flume和kafka整合 1.下载flume-kafka-plus:https://github.com/beyondj2ee/flumeng-kafka-plugin 2.提取插件中的flume-conf.properties文件 修改该文件:#source section producer.sources.s.type = exec producer.sources.s.comma

woainie804904772的博客 460

MATLAB算法实战应用案例精讲-【数模应用】梯度提升决策树(GDBT)(附python代码)

GBDT(Gradient Boosting Decision Tree) 又叫 MART(Multiple Additive Regression Tree),是一种迭代的决策树算法,该算法由多棵决策树组成,它在被提出之初就和SVM一起被认为是泛化能力(generalization)较强的算法。近些年更因为被用于搜索排序的机器学习模型而引起大家关注。.........

qq_36130719的博客 2075

flume+kafka+storm整合

整合 1.  flume+kafka整合 1.1.  记录log 1.1.1.  创建java项目 创建一个java项目 1.1.2.  将log4j配置文件添加到项目中 log4j将日志输出到文件 1.1.3.  在项目中记录log 在代码中通过log.info(“日志”);记录日志 1.1.4.  将项目打成jar包 将项目打成jar包,运行在linux上 1.2.  f

senvil的专栏 618

GameFramework框架详解之 Network网络框架

NetworkManager只负责维护NetworkChannel,实际的有种我们简历网络连接的也是NetworkChannel作为一个网路频道,这样管理起来比较方便,比如:一个游戏可能有多个网络连接,那么我们建立多个网络频道即可,或者当我们一个网络频道断线后,我们可以直接再新建一个,防止数据混乱。/// /// 网络管理器。/// /// 网络频道。/// 用户自定义网络错误事件。/// 检查是否存在网络频道。/// 获取网络频道。/// 获取所有网络频道。

TxNet 3366

Python高阶爬虫:逆向工程模拟Wind/同花顺等金融终端数据抓取

本文详细阐述了模拟金融数据终端进行数据抓取的全套技术方案。我们从法律合规性讲起,选择了Playwright作为核心自动化工具,通过两个实战案例(同花顺网页版和Wind桌面版)演示了从分析、模拟到数据解析的完整流程,并进一步介绍了构建健壮爬虫系统所需的高级技巧。我们的策略是:启动一个由Playwright控制的浏览器,模拟真人登录,然后监听所有网络请求,从中过滤出我们需要的那个数据API。if key in ['f43', 'f169', 'f170', 'f46', 'f60']: # 价格类字段。

2201_76125261的博客 546

zookeeper+flume+kafka+storm整合笔记1

2019独角兽企业重金招聘Python工程师标准>>> ...

weixin_33744141的博客 273

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

Flume+Kafka+storm的连接整合

Flume-ng Flume是一个分布式、可靠、和高可用的海量日志采集、聚合和传输的系统。 Flume的文档可以看http://flume.apache.org/FlumeUserGuide.html官方的英文文档 介绍的比较全面。 不过这里写写自己的见解 这个是flume的架构图 从上图可以看到几个名词: Agent: 一个Agent包含S...

weixin_30561425的博客 124

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

flume+kafka+storm+hdfs整合

转载:http://blog.youkuaiyun.com/zlfing/article/details/77161440基础环境: Redhat 5.5 64位(我这里是三台虚拟机h40,h41,h42) myeclipse 8.5 jdk1.7.0_25 Python-2.7.12 zookeeper-3.4.5集群 Hadoop-2.6.0集群 apache-storm-0.9.5集群 k

u014033218的专栏 600

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

Flume+Kafka+Storm整合

Flume+Kafka+Storm整合 1. 需求: 有一个客户端Client可以产生日志信息,我们需要通过Flume获取日志信息,再把该日志信息放入到Kafka的一个Topic:flume-to-kafka 再由Storm读取该topic:flume-to-kafka,进行日志分析处理(这里我们做的逻辑处理为filter,即过滤日志信息),处理完日志信息后,再由Storm把处理好...

abxlep7702的博客 359

Flume+Kafka+Storm实战:二、Flume与Kafka整合

文章目录 0x00 文章内容 0x01 Flume准备 1. 编写Flume配置文件 0x02 Kafka准备 1. 创建topic(如已操作过可跳过) 0x03 校验结果 1. 启动Flume 2. 启动Kafka消费者 3. 测试结果 0xFF 总结

邵奈一的博客 1291

Flume+Kafka+Storm实战:一、Kakfa与Storm整合

文章目录 0x00 文章内容 0x01 Kafka准备 1. 启动Kafka 2. 创建Topic 3. 启动消费者与消费者 0x02 Storm准备 1. 构建Maven项目 2. 编写代码 0x03 校验结果 1. 打包Storm代码 2. 执行ZK与Storm 3. 执行Storm作业 4. 校验过程 0xFF 总结

邵奈一的博客 2211

Flume-Kafka-Storm 整合实例

启动Topology作为Kafka的comsumer bin/storm jar storm-kafka-App-0.1.0-SNAPSHOT-jar-with-dependencies.jar com.exec.storm.kafka.KafKaSpoutTopologyTest 192.168.137.10:2181 启动flume-kafka的producer bin/flume

luyee2010的专栏 1万+

flume+kafka+storm整合01

具体实现1、实现Spout, 因为Storm源数据是从kafka中获取, 所以使用storm提供的KafkaSpout //由于Spout是从kafka中获取数据, Storm提供了KafkaSpout //配置kafkaSpout //kafka的topic, 是为了方便从哪儿拿数据 String topic = "testFlum

chbxw 1258
上一篇: JS闭包测试
下一篇: kafka安装
小niuniu
博客等级 码龄15年 5粉丝 16原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值