現有消息隊列(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();
}
}
}
}
}