现有消息队列(MessageQueue)比较:
网站系统 <-- Flume集群 --> Kafka集群 --> strom集群 --> redis集群
Flume用于获取数据,Kafka用于缓存数据,strom用于处理,redis用于存储。
Kafka类似于JMS中间件,但是设计完全不一样,此外Kafka并不是JMS规范的实现。
Kafka对消息保存时根据Topic进行归类,发送者为Producer,接受者为Consumer。一个Kafka集群由多个Kafka实例(Server)组成,每个Server称为broker。
Kafka集群、Producer和Consumer都依赖于zookeeper保存元数据信息(meta信息),以保证系统可用性。
Kafka特性:
1. 同时为发布和订阅提供高吞吐量(每秒生产25万条数据(50M),每秒处理55万条数据(110M))。
2. 可持久化数据。可持久化到磁盘,所以可用于批量消费,如ETL、实时应用程序,防止数据丢失。
3. 易于向外拓展。所有的Producer、consumer和broker都是分布式的,无需停机即可拓展机器。
4. 消息被处理状态在consumer中维护,而不是Server。
5. Kafka会将topic中的消息进行分区(partition),不同的consumer可以同时消费不同分区的数据(但是若consumer数大于partition数,就会有consumer获取不到数据),提高数据传输速度。一个 topic 可以分为多个 partition,每个 partition 是一个有序的队列。partition 中的每条消息都会被分配一个有序的 id(offset)。
6. Consumer Group 消费者组,可以并行消费Topic中partition的消息
message是通信的基本单位,包含三个属性:
offset 对应类型:long
messageSize 对应类型:int32
data message的具体内容
Producer
public class Producer extends Thread {
private String topic;
private kafka.javaapi.producer.Producer<Integer, String> producer;
private Properties props = new Properties();
public Producer(String topic) {
this.topic = topic;
props.put("serializer.class", "kafka.serializer.StringEncoder");
props.put("metadata.broker.list", "localhost:9092");
producer = new kafka.javaapi.producer.Producer<Integer, String>(new ProducerConfig(props));
}
@Override
public void run() {
int messageNo = 1;
String messageStr = new String ("Message_" + messageNo);
System.out.println("Send:"+messageStr);
producer.send(new KeyedMessage<Integer, String>(topic, messageStr));
messageNo ++;
try {
sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Consumer
public class Consumer extends Thread {
private ConsumerConnector consumer; //通过properties设置Consumer参数,并且创建了连接器,连接到Kafka
private String topic;
public Consumer(String topic) {
consumer = kafka.consumer.Consumer.createJavaConsumerConnector(createConsumerConfig());
this.topic = topic;
}
private ConsumerConfig createConsumerConfig() {
Properties props = new Properties();
props.put("zookeeper.connect", KafkaProperties.zkConnect);
props.put("group.id", KafkaProperties.groupId);
props.put("zookeeper.session.timeout.ms", "40000");
props.put("zookeeper.sync.time.ms", "200");
props.put("auto.commit.interval.ms", "1000");
return new ConsumerConfig(props);
}
@Override
public void run() {
//Map用于存topic及具体的partition
Map<String, Integer> topicCountMap = new HashMap<String, Integer>();
topicCountMap.put(topic, 1);
//consumerMap为broker发出来的消息,KafkaSteam为partition中的数据
Map<String, List<KafkaStream<byte[], byte[]>>> consumerMap = consumer.createMessageStreams(topicCountMap);
KafkaStream<byte[], byte[]> stream = consumerMap.get(topic).get(0);
ConsumerIterator<byte[], byte[]> it = stream.iterator();
while (it.hasNext()) {
System.out.println("receive:" + new String(it.next().message()));
try {
sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}