Storm集群的安装可以参考文章:Storm集群的安装,Kafka的安装和测试也可以参考apache kafka官网上的Quick Start
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指令。
这里有个例子,这里有具体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来检查是否已经收到这段程序发过来的数据。
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(); } }