java调用Kafka的Consumer

原创 2016年06月01日 15:59:57

之前项目中有个需求技术上需要用到Kafka,另一部门的同事通过Kafka的Producer将数据以json的格式发送到服务器上的broker,双方约定一个topic,而我通过Consumer消费服务器上broker的约定topic的数据。Kafka是基于topic的消息生产消费模式,Producer是生产者,生产特定topic的消息,Consumer是消费者,消费特定topic的消息。Kafka的官网文档,比较详细,里面还有一些demo,有兴趣的可以去看看,点此打开

maven依赖:

<dependency>
			<groupId>org.apache.kafka</groupId>
			<artifactId>kafka_2.10</artifactId>
			<version>0.8.2.1</version>
		</dependency>
properties配置文件中定义的属性:

beauty.kafka.zookeeperServer=192.168.2.199:2182
beauty.kafka.topic=0_crawlerSuccTask99
beauty.kafka.groupId=testGroup2
beauty.kafka.sessionTimeOut=6000
beauty.kafka.intervalms=500
xml配置文件中定义的bean:

<bean id="kafkaConsumerHandler" class="com.alan.beauty.taskserver.handler.KafkaConsumerHandler" init-method="init">
		<property name="zookeeper" value="${beauty.kafka.zookeeperServer}" />
		<property name="topic" value="${beauty.kafka.topic}" />
		<property name="groupId" value="${beauty.kafka.groupId}" />
		<property name="sessionTimeOut" value="${beauty.kafka.sessionTimeOut}" />
		<property name="intervalms" value="${beauty.kafka.intervalms}" />
	</bean>
Consumer的调用代码:

import kafka.consumer.Consumer;
import kafka.consumer.ConsumerConfig;
import kafka.consumer.ConsumerIterator;
import kafka.consumer.KafkaStream;
import kafka.javaapi.consumer.ConsumerConnector;

import org.apache.log4j.Logger;

import com.alan.beauty.common.exception.BusinessException;

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 KafkaConsumerHandler {

    private static final Logger logger = Logger.getLogger(KafkaConsumerHandler.class);

//    @Autowired
//    private UserInfoAuditService userInfoAuditService;

    private String zookeeper;
    private String groupId;
    private String topic;
    private String sessionTimeOut;
    private String intervalms;

    private ConsumerConnector consumer;

    private ExecutorService executor;

    private ConsumerConfig createConsumerConfig() {
        Properties props = new Properties();
        props.put("zookeeper.connect", zookeeper);//如果有多个服务器,则配置形式为hostname1:port1,hostname2:port2,hostname3:port3
        props.put("group.id", groupId);
        props.put("zookeeper.session.timeout.ms", sessionTimeOut);
        props.put("zookeeper.sync.time.ms", intervalms);
        //props.put("auto.commit.interval.ms", "40000");//自动提交的间隔时间,自动提交为true时才生效
        props.put("auto.commit.enable", "false");//是否自动提交
        props.put("auto.offset.reset", "smallest");
        return new ConsumerConfig(props);
    }

    void init() {
        try {
            logger.info("zookeeper=" + zookeeper + " groupId=" + groupId + " topic=" + topic);
            ConsumerConfig consumerConfig = this.createConsumerConfig();
            consumer = Consumer.createJavaConsumerConnector(consumerConfig);
            int handleThreadNum = 1;//建议一个分区对应一个线程
            executor = Executors.newFixedThreadPool(handleThreadNum);
            Map<String, Integer> topicCountMap = new HashMap<String, Integer>();
            topicCountMap.put(topic, handleThreadNum);
            Map<String, List<KafkaStream<byte[], byte[]>>> consumerMap = consumer.createMessageStreams(topicCountMap);
            List<KafkaStream<byte[], byte[]>> streams = consumerMap.get(topic);
            for (final KafkaStream<byte[], byte[]> stream : streams) {
            	executor.submit(new KafkaConsumerRunnable(stream));
            }
        } catch (Exception e) {
            logger.error("连接kafka异常", e);
        }
    }

    public void setSessionTimeOut(String sessionTimeOut) {
        this.sessionTimeOut = sessionTimeOut;
    }

    public void setIntervalms(String intervalms) {
        this.intervalms = intervalms;
    }

    public void setZookeeper(String zookeeper) {
        this.zookeeper = zookeeper;
    }

    public void setGroupId(String groupId) {
        this.groupId = groupId;
    }

    public void setTopic(String topic) {
        this.topic = topic;
    }

    class KafkaConsumerRunnable implements Runnable {
    	
    	private KafkaStream<byte[], byte[]> stream;
    	
    	public KafkaConsumerRunnable(KafkaStream<byte[], byte[]> stream){
    		this.stream = stream;
    	}
    	
        @Override
        public void run() {
            ConsumerIterator<byte[], byte[]> it = stream.iterator();
            String result = null;
            while (it.hasNext()) {
                try {
                    result = new String(it.next().message(), "UTF-8");
                    System.out.println("message="+result);
                    //TODO 对获取到的消息进行业务处理
//                    userInfoAuditService.saveOrUpdateUserInfoAudit(result);
                    consumer.commitOffsets();
                } catch (BusinessException e) {
                    logger.error("解析消息格式异常", e);
                    consumer.commitOffsets();
                } catch (Exception e) {
                    logger.error("数据库操作异常,消息内容为:" + result, e);
                }
            }
        }
    }
    
}

需要说明的是:

1、Kafka有partition(分区)的概念,最好一个线程对应一个分区。因为我这服务端只设置一个分区,故代码中

int handleThreadNum = 1;
2、Kafka在获取数据时会阻塞主线程,所以必须把Kafka的连接部分和获取数据部分完全区分,获取数据部分必须放在异步线程中执行。

3、我是手动控制偏移量,根据业务场景来决定哪些要提交偏移量,哪些不提交。(比如数据库连接突然增多,导致连接池异常,那么调整参数后重启应用,这部分数据还可以重新读取,因为偏移量没有被提交到服务器。如果是自动提交,那么一段时间后(参数可配,见我代码中的注释)读取出来的这部分数据偏移量会被自动提交,重启后这种场景的数据就读不到了,丢了)

4、我是采用Kafka提供的high level consumer api,这个使用起来比较简单,但是对偏移量的控制比较弱。建议如果有多分区的情况或者对数据丢失的容忍度较低,还是使用Simple Consumer API。



版权声明:本文为博主原创文章,未经博主允许不得转载。

Kafka 学习笔记(三)之Java Consumer客户端

写了producer,这篇我们来看看consumer。

安装部署(六) Kafka集群安装部署以及Producer和Consumer的JAVA代码测试

Kafka集群安装部署以及Producer和Consumer的JAVA代码测试 kafka 0.10.0.0 ubuntu 14.04.04 x64 hadoop 2.7.2 spark 2.0....
  • dst1213
  • dst1213
  • 2016年08月11日 15:42
  • 3300

JAVA_Kafka_producer_consumer

消费者代码: import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Pr...

windows平台下,采用kafka作为消息中间件,consumer和producer采用java api (环境搭建)

1. 先安装zookeeper     a. 下载zookeeper-3.3.6.tar.gz 解压到D:\xxx下,     b. 修改zookeeper主配置文件,conf\zoo.cf...
  • ilytl
  • ilytl
  • 2015年07月02日 14:28
  • 269

Kafka的Producer和Consumer的示例(使用java语言)

我使用的kafka版本是:0.7.2 jdk版本是:1.6.0_20 http://kafka.apache.org/07/quickstart.html官方给的示例并不是很完整,以下代码是经过我...
  • cfeibiao
  • cfeibiao
  • 2013年05月17日 14:35
  • 13320

kafka_hdfs_consumer

  • 2016年07月04日 14:48
  • 4KB
  • 下载

总结kafka的consumer消费能力很低的情况下的处理方案

简介 由于项目中需要使用kafka作为消息队列,并且项目是基于spring-boot来进行构建的,所以项目采用了spring-kafka作为原生kafka的一个扩展库进行使用。先说明一下版本: ...

Kafka系列4-基本概念及消费者组(Consumer Group)的理解

几个基本概念:     Kafka是一个分布式流数据系统,使用Zookeeper进行集群的管理。与其他消息系统类似,整个系统由生产者、Broker Server和消费者三部分组成,生产者和消费者...
  • kuluzs
  • kuluzs
  • 2017年05月04日 16:10
  • 1149

Kafka 0.9 新版本consumer客户端使用介绍

kafka最初的客户端使用scala写的, 但是有很多限制. 在0.8.1版本中, 用Java重写了producer客户端, 0.9版本中用java重写了consumer客户端, 新的客户端提供了更加...

kafka consumer不能消费消息及其处理办法

我这里的Kafka Consumer代码是拷贝网上的,就是开一个线程监听kafka topic,一有消息就处理。开始的代码是这样的: public void kafkaStart() { ...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:java调用Kafka的Consumer
举报原因:
原因补充:

(最多只允许输入30个字)