分佈式發佈訂閱消息系統 Kafka

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


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章