kafka初识—随笔(windows版)

一、初衷

因为之前学习消息队列,朋友推荐了kafka(卡夫卡),然后就入坑了一段时间,总算对kafka有一个初步的认识。现记录一下坑,和简单的使用方式。这个版本是window的操作,比较简单。希望对初学者有一定的帮助。

二、安装kafka

windows版本,卡夫卡的版本是kafka_2.11-1.1.0;依赖zookeeper,版本使用的是zookeeper-3.4.10。直接到官网下载window的压缩包解压即可。解压后的目录结构如下:

 然后zookeeper如下:

 因为kafka依赖zookeeper,所以先配置好zookeeper,首先是配置zookeeper的日志保存路径,打开conf,修改如下:

更改dataDir的日志路径,其他默认即可 。启动Zookeeper,进入 bin 目录,执行 zkServer.cmd。可以注册为windows服务,这里就不说了。启动成功如下:

接下来是配置kafka,打开kafka目录下的config,里面有几个重要的配置文件,producer、consumer、server配置文件,server的配置文件启动的时候会去该文件。下图是zookeeper.propertis:

下图是生产者的配置文件说明:

kafka的server.properties配置文件改下几个重要的属性:

 这里说明一下:topic创建的时候指定的分区数量应该根据每个group的消费者的数量而定制,一般是partition>=goup下的消费者数量才合理。

 zk的端口如果都是默认的话,,一般不需要更改,,默认就好。

接下来启动卡夫卡服务,,进入bin目录下的windows目录,,因为是windows版本,,所以需要依赖bat文件执行相应的kafka命令,启动命令:kafka-server-start.bat ..\..\config\server.properties     启动成功后,,接下来创建一个topic订阅主题和topic对应的分区数量,命令:

kafka-topics.bat --create --zookeeper localhost:2181 --replication-factor 1 --partitions 1 --topic test.topic

 如果后期需要修改topic的分区数量可执行该命令:kafka-topics.bat –zookeeper localhost:2181 -alter –partitions 5 –topic test.topic

创建成功后,Java这边代码,主要是以API来实现。

三、Java集成简单的kafka-client

 

 对应的版本为  <kafka-clients.version>1.1.0</kafka-clients.version>

编写消费者的代码如下:

package com.lmx.springbootdemo.common.entity;

import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.apache.kafka.clients.consumer.ConsumerRecords;
import org.apache.kafka.clients.consumer.KafkaConsumer;

import java.util.Arrays;
import java.util.Properties;

public class MyKafkaConsumer implements Runnable{
	private final KafkaConsumer<String, String> consumer;
	private String topic;
	private String groupId;

	public MyKafkaConsumer(String topic, String groupId){
		this.topic=topic;
		this.groupId=groupId;
		Properties props = new Properties();
		/* 定义kakfa 服务的地址,不需要将所有broker指定上 */
		props.put("bootstrap.servers", "localhost:9092");
		/* 制定consumer group */
		props.put("group.id", this.groupId);
		/* 是否自动确认offset */
		props.put("enable.auto.commit", "true");
		/* 自动确认offset的时间间隔 */
		props.put("auto.commit.interval.ms", "1000");
		props.put("session.timeout.ms", "30000");
		/* key的序列化类 */
		props.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
		/* value的序列化类 */
		props.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
		/* 定义consumer */
		this.consumer=new KafkaConsumer<>(props);
		/* 消费者订阅的topic, 可同时订阅多个 */
		this.consumer.subscribe(Arrays.asList(this.topic));
	}

	@Override
	public void run() {
		try {
			while (true){
				System.out.println("消费者test-consumer-group"+this+"接收消息中>>>>>>>>>>>>>>>>>>>>>>>>>");
				ConsumerRecords<String, String> records = this.consumer.poll(1000);
				for (ConsumerRecord<String, String> record : records) {
					System.out.printf("消费者test-consumer-group"+this+">>>>>>>> "+"offset = %d, key = %s, value = %s\n", record.offset(), record.key(), record.value());
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

kafka生产者的与发送消息的工具类,因为我这只想实例化一个生产者,,所以单例了。这里注释掉了Partitioner接口,这个接口目的是自定义topic分区消息分发策略,如果只有一个topic切一个分区,多个相同的group.id订阅相同的topic,,那么成了广播模式,,所有消费者会接收到相同的消息;如果topic下多个分区,消费者group下有多个消费者,,那么kafka将采用随机或者取模的方式把消息分配到topic的分区,group的消费者就会各自分配到一个对应的分区消费各自不同的消息,每个分区都存在一个log。

package com.lmx.springbootdemo.common.utils;

import com.baomidou.mybatisplus.toolkit.IdWorker;
import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.ProducerRecord;

import java.util.Properties;

/**
 * @auther Lin_J
 * @className: (卡夫卡工具类)
 * @date 2018/04/11 20:07:47
 */
public class KafkaUtil /*implements Partitioner*/{

    private static KafkaProducer<String, String> producer;
    //  private static KafkaConsumer<String, String> consumer = null;

    public final static String TOPIC="xinggege";
	private static Properties producerProps = null;

	private static Properties initProducerProPer(){
		if(null==producerProps){
			producerProps = new Properties();
			producerProps.put("bootstrap.servers", "localhost:9092");
			producerProps.put("client.id", "DemoProducer");
			producerProps.put("acks", "all");
			// producerProps.put("partitioner.class", "com.lmx.springbootdemo.common.utils.KafkaUtil");
			producerProps.put("retries", 0);
			producerProps.put("batch.size", 16384);
			producerProps.put("linger.ms", 10);
			producerProps.put("request.timeout.ms", "6000");
			producerProps.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
			producerProps.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
		}
		return producerProps;
	}


	/**
	 * 单例一个生产者
	 * @return
	 */
	private static KafkaProducer<String, String> initKafkaProducer(){
		if(null==producer){
			producer=new KafkaProducer<>(initProducerProPer());
			producer.partitionsFor(TOPIC);
		}
		return producer;
	}


	/**
	 * 调用生产者发送消息
	 * @param msg
	 */
	public static void prodMessage(String msg){
		initKafkaProducer();
		if(null != producer){
			System.out.println("发送的数据>>>>>>>>>>>>>>>>>"+msg);
			producer.send(new ProducerRecord<>(TOPIC, IdWorker.getIdStr(), msg));
		}
	}

	public static void closeProducer(){
		if(null!=producer){
			// producer.flush();
			producer.close();
		}
	}

/*	@Override
	public int partition(String topic, Object key, byte[] bytes, Object value, byte[] bytes1, Cluster cluster) {
		System.err.println(">>>>>>>>>>>>>>>"+topic);
		System.err.println(">>>>>>>>>>>>>>>"+key);
		System.err.println(">>>>>>>>>>>>>>>"+value);
		List<PartitionInfo> partitions = cluster.partitionsForTopic(topic);
		int num = partitions.size();
		int partNum;
		try {
			partNum = key.toString().hashCode();
		} catch (Exception e) {
			partNum = IdWorker.getIdStr().hashCode();
		}
		System.err.println(partNum);
		System.err.println(num);

		System.err.println(Math.abs(partNum % num));
		return Math.abs(partNum % num);
	}

	@Override
	public void close() {

	}

	@Override
	public void configure(Map<String, ?> map) {

	}*/
}

 我这里使用了线程池跑了两个线程,创建了两个group.id相同的消费者。测试数据可以清楚的看到,,每个消费者都有分配到自己的分区,然后消费各自的消息。

什么是consumer group? consumer group是kafka提供的可扩展且具有容错性的消费者机制。既然是一个组,那么组内必然可以有多个消费者或消费者实例(consumer instance),它们共享一个公共的ID,即group ID。组内的所有消费者协调在一起来消费订阅主题(subscribed topics)的所有分区(partition)。当然,每个分区只能由同一个消费组内的一个consumer来消费。三个特性:

  • consumer group下可以有一个或多个consumer 实例,可以是一个进程,也可以是一个线程

  • group.id是一个字符串,唯一标识一个consumer group

  • consumer group下订阅的topic下的每个分区只能分配给某个group下的一个consumer(当然该分区还可以被分配给其他group)

四、总结

kafka不单单是那么简单,,其中涉及到的概念还有很多。比如:消息传播模式、消息提交方式(为了消息可靠,会有手动提交、异步提交、自动提交等等)、zero-copy、offset偏移、存储机制等等。更详细的原理请参考:https://blog.csdn.net/ychenfeng/article/details/74980531。以上是个人使用心得,有什么不对的地方,,请多多指教!

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值