Kafka介绍

目录

1 Kafka概述

2 Kafka基本架构

3 基本原理

4 Kafka核心组件

4.1 Replications、Partitions 和Leaders

4.2 Producer

4.3 Consumer

5 Kafka主要配置

5.1 Broker配置

5.2 Producer配置

6 Kafka部署

6.1 准备工作

6.2 安装Kafka

6.3 启动并测试Kafka

7 Kafka开发代码实例

7.1 Maven依赖

7.2 生产者

7.3 消费者

8 Kafka小结


1 Kafka概述

当今社会各种应用系统诸如商业、社交、搜索、浏览等像信息工厂一样不断的生产出各种信息,在大数据时代,我们面临如下几个挑战:如何收集这些巨大的信息;如何分析它;如何及时做到如上两点。以上几个挑战形成了一个业务需求模型,即生产者生产(produce)各种信息,消费者消费(consume)(处理分析)这些信息,而在生产者与消费者之间,需要一个沟通两者的桥梁-消息系统。从一个微观层面来说,这种需求也可理解为不同的系统之间如何传递消息。

Apache kafka 是一个分布式的基于push-subscribe的消息系统,它具备快速、可扩展、可持久化的特点。它现在是Apache旗下的一个开源系统,作为hadoop生态系统的一部分,被各种商业公司广泛应用。它的最大的特性就是可以实时的处理大量数据以满足各种需求场景:比如基于hadoop的批处理系统、低延迟的实时系统、storm/spark流式处理引擎。

2 Kafka基本架构

Kafka中发布订阅的对象是topic。我们可以为每类数据创建一个topic,把向topic发布消息的客户端称作producer,从topic订阅消息的客户端称作consumer。Producers和consumers可以同时从多个topic读写数据。一个kafka集群由一个或多个broker服务器组成,它负责持久化和备份具体的kafka消息。如图4-1所示:

图4-1 Kafka基本架构

上图中可以看出,生产者将数据发送到Broker代理,Broker代理有多个话题topic,消费者从Broker获取数据。

3 基本原理

我们将消息的发布(publish)称作 producer,将消息的订阅(subscribe)表述为 consumer,将中间的存储阵列称作 broker(代理).。生产者将数据生产出来,交给 broker 进行存储,消费者需要消费数据了,就从broker中去拿出数据来,然后完成一系列对数据的处理操作,大致流程如下图所示:

图4-2 Kafka基本原理

多个 broker 协同合作,producer 和 consumer 部署在各个业务逻辑中被频繁的调用,三者通过 zookeeper管理协调请求和转发。这样一个高性能的分布式消息发布订阅系统就完成了。图中有个细节需要注意,producer 到 broker 的过程是 push,也就是有数据就推送到 broker,而 consumer 到 broker 的过程是 pull,是通过 consumer 主动去拉数据的。

4 Kafka核心组件

4.1 Replications、Partitions 和Leaders

通过上面介绍的我们可以知道,kafka中的数据是持久化的并且能够容错的。Kafka允许用户为每个topic设置副本数量。一般推荐副本数量至少为2,这样就可以保证增减、重启机器时不会影响到数据消费。如果对数据持久化有更高的要求,可以把副本数量设置为3或者更多。

Kafka中topic的物理存储是以partition的形式存放的,每一个topic都可以设置它的partition数量,Partition的数量决定了组成topic的log的数量。Producer在生产数据时,会按照一定规则(这个规则是可以自定义的)把消息发布到topic的各个partition中。上面将的副本都是以partition为单位的,不过只有一个partition的副本会被选举成leader作为读写用。

关于如何设置partition值需要考虑的因素。一个partition只能被一个消费者消费(一个消费者可以同时消费多个partition),因此,如果设置的partition的数量小于consumer的数量,就会有消费者消费不到数据。所以,推荐partition的数量一定要大于同时运行的consumer的数量。另外一方面,建议partition的数量大于集群broker的数量,这样leader partition就可以均匀的分布在各个broker中,最终使得集群负载均衡。在Cloudera,每个topic都有上百个partition。需要注意的是,kafka需要为每个partition分配一些内存来缓存消息数据,如果partition数量越大,就要为kafka分配更大的heap space。

4.2 Producer

Producers直接发送消息到broker上的leader partition,不需要经过任何中介一系列的路由转发。为了实现这个特性,kafka集群中的每个broker都可以响应producer的请求,并返回topic的一些元信息,这些元信息包括哪些机器是存活的,topic的leader partition都在哪,现阶段哪些leader partition是可以直接被访问的。

Producer客户端自己控制着消息被推送到哪些partition。实现的方式可以是随机分配、实现一类随机负载均衡算法,或者指定一些分区算法。Kafka提供了接口供用户实现自定义的分区,用户可以为每个消息指定一个partitionKey,通过这个key来实现一些hash分区算法。比如,把userid作为partitionkey的话,相同userid的消息将会被推送到同一个分区。

以Batch的方式推送数据可以极大的提高处理效率,kafka Producer 可以将消息在内存中累计到一定数量后作为一个batch发送请求。Batch的数量大小可以通过Producer的参数控制,参数值可以设置为累计的消息的数量(如500条)、累计的时间间隔(如100ms)或者累计的数据大小(64KB)。通过增加batch的大小,可以减少网络请求和磁盘IO的次数,当然具体参数设置需要在效率和时效性方面做一个权衡。

Producers可以异步的并行的向kafka发送消息,但是通常producer在发送完消息之后会得到一个future响应,返回的是offset值或者发送过程中遇到的错误。这其中有个非常重要的参数“acks”,这个参数决定了producer要求leader partition 收到确认的副本个数,如果acks设置数量为0,表示producer不会等待broker的响应,所以,producer无法知道消息是否发送成功,这样有可能会导致数据丢失,但同时,acks值为0会得到最大的系统吞吐量。 若acks设置为1,表示producer会在leader partition收到消息时得到broker的一个确认,这样会有更好的可靠性,因为客户端会等待直到broker确认收到消息。若设置为-1,producer会在所有备份的partition收到消息时得到broker的确认,这个设置可以得到最高的可靠性保证。

4.3 Consumer

Kafka提供了两套consumer api,分为high-level api和sample-api。Sample-api 是一个底层的API,它维持了一个和单一broker的连接,并且这个API是完全无状态的,每次请求都需要指定offset值,因此,这套API也是最灵活的。 在kafka中,当前读到消息的offset值是由consumer来维护的,因此,consumer可以自己决定如何读取kafka中的数据。比如,consumer可以通过重设offset值来重新消费已消费过的数据。不管有没有被消费,kafka会保存数据一段时间,这个时间周期是可配置的,只有到了过期时间,kafka才会删除这些数据。

High-level API封装了对集群中一系列broker的访问,可以透明的消费一个topic。它自己维持了已消费消息的状态,即每次消费的都是下一个消息。High-level API还支持以组的形式消费topic,如果consumers有同一个组名,那么kafka就相当于一个队列消息服务,而各个consumer均衡的消费相应partition中的数据。若consumers有不同的组名,那么此时kafka就相当与一个广播服务,会把topic中的所有消息广播到每个consumer。

5 Kafka主要配置

5.1 Broker配置

Broker配置的主要参数如下图所示:

图4-3 Broker配置

5.2 Producer配置

Producer配置的主要参数如下图所示:

图4-4 Producer配置

 

5.3 Consumer配置

Consumer配置的主要参数如下图所示:

标题

 

6 Kafka部署

6.1 准备工作

1. 配置各主机IP。将各主机IP配置为静态IP(保证各主机可以正常通信,为避免过多的网络传输,建议在同一网段)

2. 修改机器主机名。Kafka集群中的所有主机都需要修改。

3. 配置各主机映射。修改hosts文件,加入各主机IP和主机名的映射。

4. 开放相应端口。后面文档中配置的端口都需要开放(或者关闭防火墙),root权限。

5. 保证Zookeeper集群服务能够正常运行。其实只要Zookeeper集群部署成功,上面的准备工作基本都能做好了。

6.2 安装Kafka

1. 下载kafka安装包,访问Kafka官网下载对应版本即可。这里使用的版本为2.9.2-0.8.1.1。

2.  使用命令解压安装包:

tar -zxvf kafka_2.9.2-0.8.1.1.tgz

3. 修改配置文件,简单配置只需要修改/config/server.properties文件即可。

vim config/server.properties

需要修改的内容:broker.id(标示当前server在集群中的id,从0开始);port;host.name(当前的server host name);zookeeper.connect(连接的zookeeper集群);log.dirs(log的存储目录,需要提前创建)。如下图所示:

图4-6 server.properties配置

4 把配置好的kafka上传到其他节点上

scp -r kafka node2:/usr/

上传Kafka至另外两个节点之后,修改server.properties中broker.id依次为1、2,同时host.name修改每个节点的IP。

6.3 启动并测试Kafka

1首先启动Zookeeper,然后启动Kafka,启动成功之后会有信息提示。

./bin/zookeeper-server-start.sh config/zookeeper.properties &

./bin/kafka-server-start.sh config/server.properties &

2 创建Topic

创建一个名为“test”的Topic,设置3个分区两个副本

./bin/kafka-topics.sh -zookeeper node1:2181,node2:2181,node3:2181 -topic test -replication-factor 2 -partitions 3 –create

查看Topic

./bin/kafka-topics.sh -zookeeper node1:2181,node2:2181,node3:2181 –list

3 利用Kafka自带的命令行创建producer:

./bin/kafka-console-producer.sh -broker-list node1:9092,node2:9092,node3:9092 -topic test

在producer的控制台输入信息”Hello Kafka”,如下图所示:

图4-6 输入信息

4 利用Kafka自带的命令行创建consumer:

./bin/kafka-console-consumer.sh -zookeeper node1:2181,node2:2181,node3:2181 - from-begining -topic test

Consumer控制台输出结果,如下图所示:

图4-7 输出信息

7 Kafka开发代码实例

我们以java代码为例,分别实现Kafka的生产者和消费者。

7.1 Maven依赖

在maven工程中,pom.xml文件添加以下依赖:

<dependency>
   	<groupId>org.apache.kafka</groupId>
   	<artifactId>kafka-clients</artifactId>
   	<version>0.9.0.0</version>
</dependency>

7.2 生产者

生产者的发送数据函数如下所示:

public void Send2Kafka(){
    	String topicName = "STRU_IMAGE_TASK";
    	JSONObject jsonObject=new JSONObject();
    	Object 		a[]={1,1,1001754462761l,1536595200000l,1536668583572l,2,'0',1,1,180910661282l,0,'1'};
    	jsonObject.put("values",a);
    	Properties properties = new Properties();
    	//Kafka服务端的主机名和端口号
   		properties.put("bootstrap.servers", "10.3.64.97:9092");
    	//客户的ID
    	//properties.put("client.id", "ProducerDemo");
    	//消息的key和value都是字节数组,为了将Java对象转化为字节数组,可以配置
    	//key.serializer和value.serializer两个序列化器,完成转化
    	properties.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
    	// StringSerializer用来将String对象序列化成字节数组
    	properties.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
    	Producer<String, String> producer = new KafkaProducer<>(properties);
    	ProducerRecord<String, String> record = new ProducerRecord<>(topicName,"0000000000001" , jsonObject.toString());
   		 producer.send(record, new Callback() {
        	@Override
        	public void onCompletion(RecordMetadata recordMetadata, Exception e) {
            	System.out.println("send sucess");
        	}
    	});
    	producer.close();
	}

7.3 消费者

1 消费者消费数据并自动提交offset函数如下所示:

public void testConsumerFromKafka(){
    	Properties props = new Properties();
    	props. put("bootstrap.servers","10.3.64.97: 9092");
    	//制定consumer group
   		props. put("group.id","test");
    	//是否自动确认offset
    	props. put( "enable.auto.commit",  "true");
    	//自动确认offset的时间间隔
    	props. put("auto.commit.interval.ms","1000");
    	props. put("session.timeout.ms","30000");
    	// key value的序列化类
    	props. put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
    	props. put( "value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
    	//定义consumer
    	KafkaConsumer<String,String> consumer=new KafkaConsumer<String, String>(props);
    	//消费者订阅的topic,可同时订阅多个
    	consumer. subscribe(Arrays.asList("my-topic-test", "foo" , "bar"));
    	//读取数据,读取超时时间为100ms
    	while (true){
        	ConsumerRecords<String, String> records=consumer.poll(100);
        	for (ConsumerRecord<String, String> record : records)
            	System.out.printf("offset=%d, key=%s, value=%s",
                    	record.offset(),record.key(),record.value());
    	}
}

2 消费者消费数据并手动控制offset函数如下所示:

public void testConsumerFromKafka(){
    	Properties props = new Properties();
    	props. put("bootstrap.servers","10.3.64.97: 9092");
    	//制定consumer group
   		props. put("group.id","test");
    	//关闭自动确认offset
    	props. put( "enable.auto.commit",  "false");
    	//自动确认offset的时间间隔
    	props. put("auto.commit.interval.ms","1000");
    	props. put("session.timeout.ms","30000");
    	// key value的序列化类
    	props. put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
    	props. put( "value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
    	//定义consumer
    	KafkaConsumer<String,String> consumer=new KafkaConsumer<String, String>(props);
    	//消费者订阅的topic,可同时订阅多个
    	consumer. subscribe(Arrays.asList("my-topic-test", "foo" , "bar"));
	final int minBatchSize=200;
		List<ConsumerRecord<String, String>> buffer=new ArrayList<ConsumerRecord<String, 			String>>();
		while (true){
    		//读取数据,读取超时时间为10Oms
    		ConsumerRecords<String, String> records=consumer.poll(100);
    		for (ConsumerRecord<String, String> record : records){
        	buffer.add(record);
    		}
    		if(buffer.size()>=minBatchSize){
        	//将数据批量提交至数据库,可以根据需求自己实现
        	//insertIntoDb(buffer);
        	consumer.commitAsync();
        	buffer.clear();
		}
    	}
	//还可以精细的控制对具体分区具体offfset数据的确认
		/*try{
    		while(true){
        		ConsumerRecords<String, String> records= consumer.poll(Long.MAX_VALUE);
        		for (TopicPartition partition : records.partitions()) {
            		List<ConsumerRecord<String, String>> partitionRecords = records. records(partition) ;
            		for (ConsumerRecord<String,String> record : partitionRecords) {
                		System.out.println ( record.offset() + " :  " + record.value());
            		}
            		long  lastOffset  =  partitionRecords.get(partitionRecords.size()-1) .offset();
            		consumer.commitSync(Collections.singletonMap ( partition, new 		OffsetAndMetadata(lastOffset  +  1)) ) ;
        		}
    		}
		} finally{
    		consumer.close();
		}*/
	}

8 Kafka小结

Kafka是一种快速、可扩展的、分布式的服务,具有以下特点:

(1)高吞吐量、低延迟:kafka每秒可以处理几十万条消息,它的延迟最低只有几毫秒,每个topic可以分多个partition, consumer group 对partition进行consume操作;

(2)可扩展性:kafka集群支持热扩展;

(3)持久性、可靠性:消息被持久化到本地磁盘,并且支持数据备份防止数据丢失;

(4)容错性:允许集群中节点失败(若副本数量为n,则允许n-1个节点失败);

(5)高并发:支持数千个客户端同时读写;

(6)支持实时在线处理和离线处理:可以使用Storm这种实时流处理系统对消息进行实时进行处理,同时还可以使用Hadoop这种批处理系统进行离线处理。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值