1. 程式人生 > >Storm和Kafka的整合安裝和測試

Storm和Kafka的整合安裝和測試

1、先保證Storm叢集已經安裝

Storm叢集的安裝可以參考文章:Storm叢集的安裝,Kafka的安裝和測試也可以參考apache kafka官網上的Quick Start

2、安裝Kafka叢集:

2.1 下載Kafka包,我們這裡選擇kafka_2.9.2-0.8.1.tgz版本進行安裝,解壓到安裝目錄:tar -xzf kafka_2.9.2-0.8.1.tgz

2.2 建立一個軟連結kafka:ln -s kafka_2.9.2-0.8.1 kafka,方便以後升級

2.3 修改~/.profile,匯出KAFKA_HOME和PATH

export KAFKA_HOME=/home/storm/software/kafka

export PATH=.:$KAFKA_HOME/bin:$PATH

2.4 執行:source ~/.profile,使得修改對於當前會話生效

2.5 修改kafka配置檔案kafka/config/server.properties

log.dirs=/home/storm/software/kafka/kafka-logs

zookeeper.connect=linux-21:2181,linux-7:2181

2.6 啟動kafka:nohup kafka-server-start.sh ./config/server.properties &

檢視日誌cat nohup.out,有可能會報如下錯誤:

Unrecognized VM option '+UseCompressedOops'

Could not create the Java virtual machine.

這是由於機器上安裝的JDK版本不支援VM選項導致的,Kafka0.8.1版本需要的JDK是JDK 1.7 u51。可以通過如下方法暫時規避,但是是否還有其他相容性問題,還不確定:修改kafka/bin目錄下的KAFKA_JVM_PERFORMANCE_OPTS取值,把-XX:+UseCompressedOops刪除

2.7 建立topic:

kafka-topics.sh --create --zookeeper linux-7:2181 --partitions 2 --replication-factor 1 --topic test

其中--zookeeper指定一個zookeeper的位置,

--partition指定partition的個數,建立完後,我們能在log.dirs指定的目錄下看到兩個以主題名稱建立的資料夾:test-0,test-1,裡面有一個索引檔案.index,一個數據檔案.log

--relication-factor指定副本的個數(這個值不能大於broker的個數)

--topic指定主題的名字

2.8 檢視topic:

kafka-topics.sh --list --zookeeper linux-21:2181

2.9 produce訊息:

kafka-console-producer.sh --broker-list localhost:9092 --topic test

--broker-list指定broker的列表

2.10 consume訊息:

kafka-console-consumer.sh --zookeeper localhost:2181 --topic test --from-beginning

--zookeeper指定zookeeper的位置

我們從produce命令和consume命令可以看出,produce是直接和broker通訊的;而consume不需要和broker直接通訊,它是從zookeeper通訊而獲得broker的資訊的。

2.11 將整個kafka目錄拷貝到其他kafka叢集機器上,注意~/.profile的修改和生效,以及修改server.properties檔案中的broker.id屬性,使得所有叢集的機器取值不同。

2,12 將其他機器上的kafka啟動,並測試producer和consumer指令。

3、編寫kafka Producer JAVA程式

這裡有個例子,這裡有具體API的文件

3.1 先構造一個ProducerConfig物件,用來配置kafka broker的資訊

3.2 構造Producer,呼叫send命令傳送KeyedMessage訊息。

3.3 這裡要注意兩個問題:

  • 程式碼中的API已經過時,已經有新的API替換
  • 如果你寫的Producer程式是在本機(非kafka伺服器) 上執行,那麼一定要配置好server.properties配置檔案的advertised.host.name引數,配置檔案中關於這個引數有如下說明:

# Hostname the broker will advertise to producers and consumers. If not set, it uses the

# value for "host.name" if configured.  Otherwise, it will use the value returned from

# java.net.InetAddress.getCanonicalHostName().

意思就是說廣播給producer和consumer用的。如果沒有設定,就去讀host.name中的設定,如果也沒設定,就通過getCanonicalHostName()來取。所以如果你的本機沒有配置hosts檔案的話,就無法解析發過來的broker主機名。如果不想修改本機的hosts檔案,直接把這個引數配置成broker的IP地址就可以了。

程式碼如下:

package com.mykafka.producer;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.Properties;

import kafka.javaapi.producer.Producer;
import kafka.producer.KeyedMessage;
import kafka.producer.ProducerConfig;

public class MyLogProducer {

	public static void main(String[] args) throws IOException {
		Properties props = new Properties();
		props.put("metadata.broker.list", "10.118.15.7:9092");
		
        props.put("serializer.class", "kafka.serializer.StringEncoder");
        //props.put("partitioner.class", "example.producer.SimplePartitioner");
        props.put("request.required.acks", "1");
        props.put("producer.type", "async");
        
        props.put("compression.codec", "1");
        
        //props.put("zookeeper.connect", "linux-7:2181,linux-21:2181");
        
		
        ProducerConfig config = new ProducerConfig(props);
        Producer<String, String> producer = new Producer<String, String>(config);
        
        BufferedReader reader = new BufferedReader(new FileReader("c:/access.log"), 2048);
        String aline;
        while((aline = reader.readLine()) != null){
        	System.out.println(aline);
        	KeyedMessage<String, String> data = new KeyedMessage<String, String>("logs", aline);
        	producer.send(data);
        }
        
        producer.close();
        reader.close();
        System.out.println("send over....");
	}

}

可以在broker端開一個consumer來檢查是否已經收到這段程式發過來的資料。

4、Storm consume Kafka

Storm從Kafka讀取資料,我們可以利用一個開源的jar包來實現。

主要分兩步來使用:

第一步,構造一個SpoutConfig物件,它需要zookeeper的資訊,以及topic資訊等。

第二步,用SpoutConfig來構造KafkaSpout物件

import com.storm.stormkafka08.bolt.LogParserBolt;

import backtype.storm.Config;
import backtype.storm.LocalCluster;
import backtype.storm.spout.SchemeAsMultiScheme;
import backtype.storm.topology.TopologyBuilder;
import storm.kafka.KafkaSpout;
import storm.kafka.SpoutConfig;
import storm.kafka.StringScheme;
import storm.kafka.ZkHosts;

public class LogTopology {

    public static void main(String[] args) {
        // zookeeper hosts for the Kafka cluster 
        ZkHosts zkHosts = new ZkHosts("10.118.15.21:2181"); 
        // Create the KafkaSpout configuration 
        // Second argument is the topic name 
        // Third argument is the ZooKeeper root for Kafka 
        // Fourth argument is consumer group id 
        SpoutConfig kafkaConfig = new SpoutConfig(zkHosts,  "logs", "", "id7"); 
        // Specify that the kafka messages are String 
        kafkaConfig.scheme = new SchemeAsMultiScheme(new  StringScheme()); 
        // We want to consume all the first messages in 
        // the topic every time we run the topology to 
        // help in debugging. In production, this 
        // property should be false 
        kafkaConfig.forceFromStart = true; 
        // Now we create the topology 
        TopologyBuilder builder = new TopologyBuilder(); 
        // set the kafka spout class 
        builder.setSpout("KafkaSpout", new KafkaSpout(kafkaConfig), 1); 
        // configure the bolts 
        builder.setBolt("ParseLog", new LogParserBolt(), 3).shuffleGrouping("KafkaSpout"); 
        
        // create an instance of LocalCluster class 
        // for executing topology in local mode. 
        LocalCluster cluster = new LocalCluster(); 
        Config conf = new Config(); 
        // Submit topology for execution 
        cluster.submitTopology("KafkaToplogy", conf, builder.createTopology()); 
        try { 
          // Wait for some time before exiting 
          System.out.println("Waiting to consume from kafka"); 
          Thread.sleep(10000); 
        } catch (Exception exception) { 
          System.out.println("Thread interrupted exception : " 
          + exception); 
        } 
        // kill the KafkaTopology 
        cluster.killTopology("KafkaToplogy"); 
        // shut down the storm test cluster 
        cluster.shutdown(); 

    }

}