kafka自定義partition分發策略實例(含生java生產者實例代碼和消費者實例代碼)

1.基本信息

kafka版本:kafka_2.11-0.9.0.1

kafka jar包版本:0.9.0.1

kafka集羣:192.168.1.101,192.168.1.102,192.168.1.103

2.自定義partition分發策略, 新建MyPartitioner類, 根據key值進行自定義


import kafka.producer.Partitioner;
import kafka.utils.VerifiableProperties;

/**
 * 
 * <p>類描述: 自定義分區分發策略 </p>
 * <p>創建人:wanghonggang  </p>
 * <p>創建時間:2019年9月26日 下午3:30:11  </p>
 */
public class MyPartitioner implements Partitioner {

	/**
	 * 構造函數
	 * 創建一個新的實例 MyPartitioner.
	 *
	 * @param props
	 */
	public MyPartitioner(VerifiableProperties props) {
		
	}

	/**
	 * 根據key和分區數量確定的分區號
	 */
	public int partition(Object key, int numPartitions) {
		try {
			long key_ = Long.parseLong((String) key);
			return (int) Math.abs(key_ % numPartitions);
		} catch (Exception e) {
			return Math.abs(key.hashCode() % numPartitions);
		}
	}
}

3.生產者引用分配策略, 新建MessageProducer類


import java.util.Properties;
import java.util.concurrent.atomic.AtomicInteger;

import kafka.javaapi.producer.Producer;
import kafka.producer.KeyedMessage;
import kafka.producer.ProducerConfig;

/**
 * 
 * <p>類描述: 生產者  </p>
 * <p>創建人:wanghonggang  </p>
 * <p>創建時間:2019年9月26日 下午3:32:58  </p>
 */
public class MessageProducer {
	private Producer<String, String> inner;
	private String topic="topic-test";
	public static AtomicInteger count;

	/**
	 * 構造函數
	 * 創建一個新的實例 MessageProducer.
	 *
	 * @throws Exception
	 */
	public MessageProducer() throws Exception {
		Properties props = new Properties();
		
		//集羣地址
		props.put("metadata.broker.list", "192.168.1.101:9092,192.168.1.102:9092,192.168.1.103:9092");
		props.put("key.serializer.class", "kafka.serializer.StringEncoder");
		props.put("serializer.class", "kafka.serializer.StringEncoder");
		
		//自定義分區分發策略
		props.put("partitioner.class", "demo.producer.MyPartitioner");
		
		ProducerConfig config = new ProducerConfig(props);
		inner = new Producer<String, String>(config);
		count = new AtomicInteger();

	}

	/**
	 * 
	 * <p>方法描述:發送消息 TODO</p>
	 * <p>創建人: wanghonggang  </p>
	 * <p>創建時間: 2019年9月26日 下午3:34:38 </p>
	 * <p>修改記錄:</p>
	 * @param message 
	 * void
	 */
	public void send(String message) {
		if (topic == null || message == null) {
			return;
		}
		
		// 指定key值避免數據傾斜,使消息均勻分佈到各個分區中
		KeyedMessage<String, String> km = new KeyedMessage<String, String>(topic, count.toString(), message);
		inner.send(km);
		count.incrementAndGet();
	}

	/**
	 * 
	 * <p>方法描述:關閉 TODO</p>
	 * <p>創建人: wanghonggang  </p>
	 * <p>創建時間: 2019年9月26日 下午3:34:28 </p>
	 * <p>修改記錄:</p> 
	 * void
	 */
	public void close() {
		try {
			inner.close();
		} catch (Exception ex) {
			ex.printStackTrace();
		}
	}

	/**
	 * 
	 * <p>方法描述:測試 TODO</p>
	 * <p>創建人: wanghonggang  </p>
	 * <p>創建時間: 2019年9月26日 下午3:30:01 </p>
	 * <p>修改記錄:</p>
	 * @param args 
	 * void
	 */
	public static void main(String[] args) {
		MessageProducer p;
		try {
			p = new MessageProducer();
			for(int i=1;i<100;i++){
				p.send(i+"");
			}
			p.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

4, 運行測試方法, 可見kafka已產生數據, 並根據測試分配partition

5.新建消費者類MessageConsumer, 多線程消費


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;

import kafka.consumer.ConsumerConfig;
import kafka.consumer.ConsumerIterator;
import kafka.consumer.KafkaStream;
import kafka.javaapi.consumer.ConsumerConnector;
import kafka.message.MessageAndMetadata;

/**
 * 
 * <p>類描述: 消費者 </p>
 * <p>創建人:wanghonggang  </p>
 * <p>創建時間:2019年9月26日 下午3:37:23  </p>
 */
public class MessageConsumer {
	private ConsumerConfig config;  
    private ConsumerConnector connector;  
    private String topicName;
    private ExecutorService threadPool;
    
    /**
     * 構造函數
     * 創建一個新的實例 MessageConsumer.
     *
     * @throws Exception
     */
	public MessageConsumer() throws Exception{ 
        
    }  
	
	/**
	 * 
	 * <p>方法描述:消息消費 TODO</p>
	 * <p>創建人: wanghonggang  </p>
	 * <p>創建時間: 2019年9月26日 下午3:51:22 </p>
	 * <p>修改記錄:</p>
	 * @throws Exception 
	 * void
	 */
    public void consumer() throws Exception{
    	
    	Properties props = new Properties();
    	
    	//group名稱
    	props.put("group.id", "group-test");
		props.put("auto.commit.interval.ms", "1000");
		props.put("zookeeper.connect", "192.168.1.101:2181,192.168.1.102:2181,192.168.1.103:2181");
		props.put("rebalance.max.retries", "10");
		props.put("rebalance.backoff.ms", "60000");
		config = new ConsumerConfig(props);
    	
		//topic名稱
		topicName = "topic-test";
		connector = kafka.consumer.Consumer.createJavaConsumerConnector(config);
		Map<String, Integer> topics = new HashMap<String, Integer>();
		
		//分區數
		topics.put(topicName, 3);
		Map<String, List<KafkaStream<byte[], byte[]>>> streams = connector.createMessageStreams(topics);
		List<KafkaStream<byte[], byte[]>> partitions = streams.get(topicName);
		
		//線程數
		threadPool = Executors.newFixedThreadPool(3);
		
		//根據分區開啓線程
		for (KafkaStream<byte[], byte[]> partition : partitions) {
			threadPool.execute(new ConsumerRunner(partition));
		}
    }
    
    /**
     * 
     * <p>類描述:線程實現  </p>
     * <p>創建人:wanghonggang  </p>
     * <p>創建時間:2019年9月26日 下午3:51:00  </p>
     */
    class ConsumerRunner implements Runnable {
		private KafkaStream<byte[], byte[]> partition;

		ConsumerRunner(KafkaStream<byte[], byte[]> partition) {
			this.partition = partition;
		}

		@SuppressWarnings("static-access")
		public void run() {
			ConsumerIterator<byte[], byte[]> it = partition.iterator();
			while (it.hasNext()) {
				try {
					MessageAndMetadata<byte[], byte[]> item = it.next();
					String message = new String(item.message());
					
					//輸出
					System.out.println("message:"+message);
					
				} catch (Exception e) {
					e.printStackTrace();;
				}
			}
		}
	}
    
    /**
     * 
     * <p>方法描述:關閉 TODO</p>
     * <p>創建人: wanghonggang  </p>
     * <p>創建時間: 2019年9月26日 下午3:50:23 </p>
     * <p>修改記錄:</p> 
     * void
     */
	public void close() {
		try {
			connector.shutdown();
			threadPool.shutdownNow();
		} catch (Exception ex) {
			ex.printStackTrace();
		}
	}
	
	/**
	 * 
	 * <p>方法描述: 測試 TODO</p>
	 * <p>創建人: wanghonggang  </p>
	 * <p>創建時間: 2019年9月26日 下午3:42:28 </p>
	 * <p>修改記錄:</p>
	 * @param args 
	 * void
	 */
	public static void main(String[] args) {
		MessageConsumer m;
		try {
			m = new MessageConsumer();
			m.consumer();
//			m.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

運行測試方法, 可以看到消費的數據結果.

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