一個分散式釋出-訂閱訊息傳遞系統
特點:
高吞吐量、低延遲
使用場景(舉例):
日誌收集:用kafka收集各種服務產生的log,通過kafka以統一的介面服務的方式開放給各種consumer,如hadoop,hbase等
下載安裝:
1.下載地址 選擇一個版本的kafka進行下載
2.解壓
tar -zxvf kafka_2.11-0.9.0.1.tgz mv kafka_2.11-0.9.0.1 /opt/
3.配置環境變數(可選步驟)
上手使用:
1.config目錄配置檔案(
zookeeper.properties
,service.properties,producer.properties,consumer.properties)
我們暫時先不管這些配置檔案,遵守初始的配置
2.先啟動zookeeper - kafka依賴與zookeeper 實現分散式一致性
我們下載的kafka安裝包,就自帶了zookeeepr,zookeeper.properties就是自帶的zk的配置檔案
nohup bin/zookeeper-server-start.sh config/zookeeepr.properties& nohup &
是實現在後臺啟動
3.再啟動kafka服務
bin/kafka-server-start.sh config/server.properties
4.建立一個Topic
bin/kafka-topics.sh --create --topic test1 --zookeeper localehost:2181 --config max.message.bytes=12800000 --config flush.messages=1 --partitions 5 --replication-factor 1
4.再啟動kafka生產端
bin/kafka-console-producer.sh --broker-list localhost:9092 --topic test1
5.在新視窗再啟動kafka消費端
bin/kafka-console-consumer.sh --zookeeper localhost:2181 --topic test1 --from-beginning
6.在生產視窗輸入任意字元,觀察在消費端是否能夠收到相應字元
如果無法收到正確字元,或者報錯,嘗試從以下方面排查:
1.服務是否都按順序正常啟動
2.命令中開啟的服務埠是否和相應的配置檔案中的配置對應
注:生產端訪問的埠不是 zookeeper的localhost:2181, 而是producer.properties
中配置的broker的埠,預設為9092
注:這個broker的埠是需要在 server中有相應的配置才可以
簡單介紹一下上面提到了config目錄下面的配置,以及kafka叢集的搭建
server.properties:一個server.properties檔案代表了一個kafka服務,也就是一個Broker
所以說,如果我們想搭建一個kafka叢集,需要有不同的 server.properties檔案,來啟動多個broker,多個borker組成kafka cluster
注:每個server.properties配置檔案中的 broker.id(伺服器唯一標識)不能一樣
port(伺服器監聽埠號)不能一樣
zookeeper.connect(zookeeper的連線ip及埠),需和zookeeper.properties保持一致
kafka在Java程式的簡單示例:
生產:
public class JavaKafkaProducer { private Logger logger = Logger.getLogger(JavaKafkaProducer.class); public static final String TOPIC_NAME = "test1"; public static final char[] charts = "qazwsxedcrfvtgbyhnujmikolp1234567890".toCharArray(); public static final int chartsLength = charts.length; public static void main(String[] args) { String brokerList = "127.0.0.1:9092"; Properties props = new Properties(); props.put("metadata.broker.list", brokerList); /** * 0表示不等待結果返回<br/> * 1表示等待至少有一個伺服器返回資料接收標識<br/> * -1表示必須接收到所有的伺服器返回標識,及同步寫入<br/> * */ props.put("request.required.acks", "0"); /** * 內部傳送資料是非同步還是同步 * sync:同步, 預設 * async:非同步 */ props.put("producer.type", "async"); /** * 設定序列化的類 * 可選:kafka.serializer.StringEncoder * 預設:kafka.serializer.DefaultEncoder */ props.put("serializer.class", "kafka.serializer.StringEncoder"); /** * 設定分割槽類 * 根據key進行資料分割槽 * 預設是:kafka.producer.DefaultPartitioner ==> 安裝key的hash進行分割槽 * 可選:kafka.serializer.ByteArrayPartitioner ==> 轉換為位元組陣列後進行hash分割槽 */ props.put("partitioner.class", "com.kafka.JavaKafkaProducerPartitioner"); // 重試次數 props.put("message.send.max.retries", "3"); // 非同步提交的時候(async),併發提交的記錄數 props.put("batch.num.messages", "200"); // 設定緩衝區大小,預設10KB props.put("send.buffer.bytes", "102400"); // 2. 構建Kafka Producer Configuration上下文 ProducerConfig config = new ProducerConfig(props); // 3. 構建Producer物件 final Producer<String, String> producer = new Producer<String, String>(config); // 4. 傳送資料到伺服器,併發執行緒傳送 final AtomicBoolean flag = new AtomicBoolean(true); int numThreads = 50; ExecutorService pool = Executors.newFixedThreadPool(numThreads); for (int i = 0; i < 5; i++) { pool.submit(new Thread(new Runnable() { @Override public void run() { while (flag.get()) { // 傳送資料 KeyedMessage message = generateKeyedMessage(); producer.send(message); System.out.println("傳送資料:" + message); // 休眠一下 try { int least = 10; int bound = 100; Thread.sleep(ThreadLocalRandom.current().nextInt(least, bound)); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(Thread.currentThread().getName() + " shutdown...."); } }, "Thread-" + i)); } // 5. 等待執行完成 long sleepMillis = 600000; try { Thread.sleep(sleepMillis); } catch (InterruptedException e) { e.printStackTrace(); } flag.set(false); // 6. 關閉資源 pool.shutdown(); try { pool.awaitTermination(6, TimeUnit.SECONDS); } catch (InterruptedException e) { } finally { producer.close(); // 最後之後呼叫 } } /** * 產生一個訊息 * * @return */ private static KeyedMessage<String, String> generateKeyedMessage() { String key = "key_" + ThreadLocalRandom.current().nextInt(10, 99); StringBuilder sb = new StringBuilder(); int num = ThreadLocalRandom.current().nextInt(1, 5); for (int i = 0; i < num; i++) { sb.append(generateStringMessage(ThreadLocalRandom.current().nextInt(3, 20))).append(" "); } String message = sb.toString().trim(); return new KeyedMessage(TOPIC_NAME, key, message); } /** * 產生一個給定長度的字串 * * @param numItems * @return */ private static String generateStringMessage(int numItems) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < numItems; i++) { sb.append(charts[ThreadLocalRandom.current().nextInt(chartsLength)]); } return sb.toString(); } }
消費:
public class JavaKafkaConsumerHighAPITest { public static void main(String[] args) { String zookeeper = "127.0.0.1"; String groupId = "test-consumer-group"; String topic = "test1"; int threads = 1; JavaKafkaConsumerHighAPI example = new JavaKafkaConsumerHighAPI(topic, threads, zookeeper, groupId); new Thread(example).start(); // 執行10秒後結束 int sleepMillis = 600000; try { Thread.sleep(sleepMillis); } catch (InterruptedException e) { e.printStackTrace(); } // 關閉 example.shutdown(); } }
1.Broker -- 每個kafka server稱為一個Broker,多個borker組成kafka cluster。
2.Topic -- Topic 就是訊息類別名,一個topic中通常放置一類訊息。每個topic都有一個或者多個訂閱者,也就是訊息的消費者consumer。
Producer將訊息推送到topic,由訂閱該topic的consumer從topic中拉取訊息。
一個Broker上可以建立一個或者多個Topic。同一個topic可以在同一叢集下的多個Broker中分佈。
....
參考博文:http://www.cnblogs.com/liuming1992/tag/Kafka/