apache kafkac系列lient發展-java

來源:互聯網
上載者:User

標籤:

apache kafka區QQ群:162272557

1.依賴包

        <dependency>
            <groupId>org.apache.kafka</groupId>
            <artifactId>kafka_2.10</artifactId>
            <version>0.8.1</version>
        </dependency>

2.producer程式開發範例2.1 producer參數說明#指定kafka節點列表。用於擷取metadata,不必所有指定
metadata.broker.list=192.168.2.105:9092,192.168.2.106:9092
# 指定分區處理類。預設kafka.producer.DefaultPartitioner,表通過key雜湊到相應分區
#partitioner.class=com.meituan.mafka.client.producer.CustomizePartitioner
 
# 是否壓縮,預設0表示不壓縮,1表示用gzip壓縮,2表示用snappy壓縮。

壓縮後訊息中會有頭來指明訊息壓縮類型,故在消費者端訊息解壓是透明的無需指定。


compression.codec=none
  
# 指定序列化處理類(mafka client API調用說明-->3.序列化約定wiki),默覺得kafka.serializer.DefaultEncoder,即byte[]
serializer.class=com.meituan.mafka.client.codec.MafkaMessageEncoder
# serializer.class=kafka.serializer.DefaultEncoder
# serializer.class=kafka.serializer.StringEncoder
# 假設要壓縮訊息。這裡指定哪些topic要壓縮訊息,預設empty,表示不壓縮。


#compressed.topics=
 
########### request ack ###############
# producer接收訊息ack的時機.默覺得0. 
# 0: producer不會等待broker發送ack 
# 1: 當leader接收到訊息之後發送ack 
# 2: 當全部的follower都同步訊息成功後發送ack. 
request.required.acks=0 
# 在向producer發送ack之前,broker同意等待的最大時間 
# 假設逾時,broker將會向producer發送一個error ACK.意味著上一次訊息由於某種 
# 原因未能成功(比方follower未能同步成功) 
request.timeout.ms=10000
########## end #####################
 
 
# 同步還是非同步發送訊息,預設“sync”表同步,"async"表非同步。非同步能夠提高發送輸送量,
# 也意味著訊息將會在本地buffer中,並適時批量發送,可是也可能導致丟失未發送過去的訊息
producer.type=sync
############## 非同步發送 (下面四個非同步參數可選) ####################
# 在async模式下,當message被緩衝的時間超過此值後,將會批量發送給broker,默覺得5000ms
# 此值和batch.num.messages協同工作.
queue.buffering.max.ms = 5000
# 在async模式下,producer端同意buffer的最大訊息量
# 不管怎樣,producer都無法儘快的將訊息發送給broker,從而導致訊息在producer端大量沉積
# 此時,假設訊息的條數達到閥值,將會導致producer端堵塞或者訊息被拋棄,默覺得10000
queue.buffering.max.messages=20000
# 假設是非同步,指定每次批量發送資料量。默覺得200
batch.num.messages=500
# 當訊息在producer端沉積的條數達到"queue.buffering.max.meesages"後 
# 堵塞一定時間後,隊列仍然沒有enqueue(producer仍然沒有發送出不論什麼訊息) 
# 此時producer能夠繼續堵塞或者將訊息拋棄,此timeout值用於控制"堵塞"的時間 
# -1: 無堵塞逾時限制,訊息不會被拋棄 
# 0:馬上清空隊列,訊息被拋棄 
queue.enqueue.timeout.ms=-1
################ end ###############
 
# 當producer接收到error ACK,或者沒有接收到ACK時,同意訊息重發的次數 
# 由於broker並沒有完整的機制來避免訊息反覆,所以當網路異常時(比方ACK丟失) 
# 有可能導致broker接收到反覆的訊息,預設值為3.
message.send.max.retries=3
 
 
# producer重新整理topic metada的時間間隔,producer須要知道partition leader的位置,以及當前topic的情況 
# 因此producer須要一個機制來擷取最新的metadata,當producer遇到特定錯誤時,將會馬上重新整理 
# (比方topic失效,partition丟失,leader失效等),此外也能夠通過此參數來配置額外的重新整理機制,預設值600000 
topic.metadata.refresh.interval.ms=60000


import java.util.*; import kafka.javaapi.producer.Producer;import kafka.producer.KeyedMessage;import kafka.producer.ProducerConfig; public class TestProducer {    public static void main(String[] args) {        long events = Long.parseLong(args[0]);        Random rnd = new Random();         Properties props = new Properties();        props.put("metadata.broker.list", "192.168.2.105:9092");        props.put("serializer.class", "kafka.serializer.StringEncoder"); //預設字串編碼訊息        props.put("partitioner.class", "example.producer.SimplePartitioner");        props.put("request.required.acks", "1");         ProducerConfig config = new ProducerConfig(props);         Producer<String, String> producer = new Producer<String, String>(config);         for (long nEvents = 0; nEvents < events; nEvents++) {                long runtime = new Date().getTime();                 String ip = “192.168.2.” + rnd.nextInt(255);                String msg = runtime + “,www.example.com,” + ip;                KeyedMessage<String, String> data = new KeyedMessage<String, String>("page_visits", ip, msg);               producer.send(data);        }        producer.close();    }}

2.1 指定keywordkey。發送訊息到指定partitions說明:假設須要實現自己定義partitions訊息發送。須要實現Partitioner介面
public class CustomizePartitioner implements Partitioner {    public CustomizePartitioner(VerifiableProperties props) {     }    /**     * 返回分區索引編號     * @param key sendMessage時,輸出的partKey     * @param numPartitions topic中的分區總數     * @return     */    @Override    public int partition(Object key, int numPartitions) {        System.out.println("key:" + key + "  numPartitions:" + numPartitions);        String partKey = (String)key;        if ("part2".equals(partKey))            return 2;//        System.out.println("partKey:" + key);         ........        ........        return 0;    }}

3.consumer程式開發範例3.1 consumer參數說明# zookeeper串連server地址,此處為線下測試環境配置(kafkaMessage Service-->kafka broker叢集線上部署環境wiki)
# 配置範例:"127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002"
zookeeper.connect=192.168.2.225:2181,192.168.2.225:2182,192.168.2.225:2183/config/mobile/mq/mafka
# zookeeper的session到期時間,預設5000ms。用於檢測消費者是否掛掉,當消費者掛掉,其它消費者要等該指定時間才幹檢查到而且觸發又一次負載平衡
zookeeper.session.timeout.ms=5000
zookeeper.connection.timeout.ms=10000
#當consumer reblance時,重試失敗時時間間隔。

zookeeper.sync.time.ms=2000
 
#指定消費組
group.id=xxx
# 當consumer消費一定量的訊息之後,將會自己主動向zookeeper提交offset資訊 
# 注意offset資訊並非每消費一次訊息就向zk提交一次,而是如今本地儲存(記憶體),並定期提交,默覺得true
auto.commit.enable=true
# 自己主動更新時間。預設60 * 1000
auto.commit.interval.ms=1000
 
# 當前consumer的標識,能夠設定,也能夠有系統產生,主要用來跟蹤訊息消費情況,便於觀察
conusmer.id=xxx 
 
# 消費者client編號。用於區分不同client,預設client程式自己主動產生
client.id=xxxx
# 最大取多少塊緩衝到消費者(預設10)
queued.max.message.chunks=50
# 當有新的consumer增加到group時,將會reblance,此後將會有partitions的消費端遷移到新 
# 的consumer上,假設一個consumer獲得了某個partition的消費許可權,那麼它將會向zk注冊 
# "Partition Owner registry"節點資訊,可是有可能此時舊的consumer尚沒有釋放此節點, 
# 此值用於控制,注冊節點的重試次數. 
rebalance.max.retries=5
# 擷取訊息的最大尺寸,broker不會像consumer輸出大於此值的訊息chunk
# 每次feth將得到多條訊息,此值為總大小,提升此值,將會消耗很多其它的consumer端記憶體
fetch.min.bytes=6553600
# 當訊息的尺寸不足時,server堵塞的時間,假設逾時,訊息將馬上發送給consumer
fetch.wait.max.ms=5000
socket.receive.buffer.bytes=655360
 
# 假設zookeeper沒有offset值或offset值超出範圍。

那麼就給個初始的offset。有smallest、largest、
# anything可選,分別表示給當前最小的offset、當前最大的offset、拋異常。預設largest
auto.offset.reset=smallest
# 指定序列化處理類(mafka client API調用說明-->3.序列化約定wiki),默覺得kafka.serializer.DefaultDecoder,即byte[]
derializer.class=com.meituan.mafka.client.codec.MafkaMessageDecoder

3.2 多線程並行消費topicConsumerTest類

import kafka.consumer.ConsumerIterator;import kafka.consumer.KafkaStream; public class ConsumerTest implements Runnable {    private KafkaStream m_stream;    private int m_threadNumber;     public ConsumerTest(KafkaStream a_stream, int a_threadNumber) {        m_threadNumber = a_threadNumber;        m_stream = a_stream;    }     public void run() {        ConsumerIterator<byte[], byte[]> it = m_stream.iterator();        while (it.hasNext())            System.out.println("Thread " + m_threadNumber + ": " + new String(it.next().message()));        System.out.println("Shutting down Thread: " + m_threadNumber);    }}

ConsumerGroupExample類
import kafka.consumer.ConsumerConfig;import kafka.consumer.KafkaStream;import kafka.javaapi.consumer.ConsumerConnector; import java.util.HashMap;import java.util.List;import java.util.Map;import java.util.Properties;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors; public class ConsumerGroupExample {    private final ConsumerConnector consumer;    private final String topic;    private  ExecutorService executor;     public ConsumerGroupExample(String a_zookeeper, String a_groupId, String a_topic) {        consumer = kafka.consumer.Consumer.createJavaConsumerConnector(                createConsumerConfig(a_zookeeper, a_groupId));        this.topic = a_topic;    }     public void shutdown() {        if (consumer != null) consumer.shutdown();        if (executor != null) executor.shutdown();    }     public void run(int a_numThreads) {        Map<String, Integer> topicCountMap = new HashMap<String, Integer>();        topicCountMap.put(topic, new Integer(a_numThreads));        Map<String, List<KafkaStream<byte[], byte[]>>> consumerMap = consumer.createMessageStreams(topicCountMap);        List<KafkaStream<byte[], byte[]>> streams = consumerMap.get(topic);         // 啟動全部線程        executor = Executors.newFixedThreadPool(a_numThreads);         // 開始消費訊息        int threadNumber = 0;        for (final KafkaStream stream : streams) {            executor.submit(new ConsumerTest(stream, threadNumber));            threadNumber++;        }    }     private static ConsumerConfig createConsumerConfig(String a_zookeeper, String a_groupId) {        Properties props = new Properties();        props.put("zookeeper.connect", "192.168.2.225:2183/config/mobile/mq/mafka");        props.put("group.id", "push-token");        props.put("zookeeper.session.timeout.ms", "60000");        props.put("zookeeper.sync.time.ms", "2000");        props.put("auto.commit.interval.ms", "1000");         return new ConsumerConfig(props);    }     public static void main(String[] args) {        String zooKeeper = args[0];        String groupId = args[1];        String topic = args[2];        int threads = Integer.parseInt(args[3]);         ConsumerGroupExample example = new ConsumerGroupExample(zooKeeper, groupId, topic);        example.run(threads);         try {            Thread.sleep(10000);        } catch (InterruptedException ie) {         }        example.shutdown();    }}

總結:

kafka消費者api分為high api和low api,眼下上述demo是都是使用kafka high api,進階api不用關心維護消費狀態資訊和負載平衡。系統會依據配置參數,

定期flush offset到zk上,假設有多個consumer且每一個consumer建立了多個線程,進階api會依據zk上注冊consumer資訊,進行自己主動負載平衡操作。

注意事項:

1.進階api將會內部實現持久化每一個分區最後讀到的訊息的offset,資料儲存在zookeeper中的消費組名中(如/consumers/push-token-group/offsets/push-token/2。

當中push-token-group是消費組,push-token是topic,最後一個2表示第3個分區),每間隔一個(預設1000ms)時間更新一次offset。

那麼可能在重新啟動消費者時拿到反覆的訊息。此外。當分區leader發生變更時也可能拿到反覆的訊息。因此在關閉消費者時最好等待一定時間(10s)然後再shutdown()

2.消費組名是一個全域的資訊,要注意在新的消費者啟動之前舊的消費者要關閉。

假設新的進程啟動而且消費組名同樣。kafka會加入這個進程到可用消費線程組中用來消費

topic和觸發又一次分配負載平衡,那麼同一個分區的訊息就有可能發送到不同的進程中。

3.假設消費者組中全部consumer的匯流排程數量大於分區數,一部分線程或某些consumer可能無法讀取訊息或處於空暇狀態。

4.假設分區數多於線程數(假設消費組中執行者多個消費者,則線程數為消費者組內全部消費者線程總和)。一部分線程會讀取到多個分區的訊息

5.假設一個線程消費多個分區訊息,那麼接收到的訊息是不能保證順序的。

備忘:可用zookeeper web ui工具管理查看zk資料夾樹狀目錄資料: xxx/consumers/push-token-group/owners/push-token/2當中

push-token-group為消費組,push-token為topic,2為分區3.查看裡面的內容如:

push-token-group-mobile-platform03-1405157976163-7ab14bd1-0表示該分區被該標示的線程所運行。


總結:producer效能最佳化:非同步化。訊息批量發送。詳細瀏覽上述參數說明。consumer效能最佳化:假設是高輸送量資料。設定每次拿取訊息(fetch.min.bytes)大些,拿取訊息頻繁(fetch.wait.max.ms)些(或時間間隔短些),假設是低延時要求,則設定時間時間間隔小,每次從kafka broker拿取訊息盡量小些。


請註明轉載自:http://blog.csdn.net/lizhitao/article/details/37811291


apache kafkac系列lient發展-java

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.