赞
踩
一:介绍
Kafka是最初由Linkedin公司开发,是一个分布式、支持分区的(partition)、多副本的(replica),基于zookeeper协调的分布式消息系统,它的最大的特性就是可以实时的处理大量数据以满足各种需求场景:比如基于hadoop的批处理系统、低延迟的实时系统、storm/Spark流式处理引擎,web/nginx日志、访问日志,消息服务等等,用scala语言编写,Linkedin于2010年贡献给了Apache基金会并成为顶级开源 项目。
二:特性
三:使用场景
- 日志收集:一个公司可以用Kafka可以收集各种服务的log,通过kafka以统一接口服务的方式开放给各种consumer,例如hadoop、Hbase、Solr等。
- 消息系统:解耦和生产者和消费者、缓存消息等。
- 用户活动跟踪:Kafka经常被用来记录web用户或者app用户的各种活动,如浏览网页、搜索、点击等活动,这些活动信息被各个服务器发布到kafka的topic中,然后订阅者通过订阅这些topic来做实时的监控分析,或者装载到hadoop、数据仓库中做离线分析和挖掘。
- 运营指标:Kafka也经常用来记录运营监控数据。包括收集各种分布式应用的数据,生产各种操作的集中反馈,比如报警和报告。
- 流式处理:比如spark streaming和storm
- 事件源
四:文件存储机制
Kafka中发布订阅的对象是topic。我们可以为每类数据创建一个topic,把向topic发布消息的客户端称作producer,从topic订阅消息的客户端称作consumer。Producers和consumers可以同时从多个topic读写数据。一个kafka集群由一个或多个broker服务器组成,它负责持久化和备份具体的kafka消息。
Broker:Kafka节点,一个Kafka节点就是一个broker,多个broker可以组成一个Kafka集群。
Topic:一类消息,消息存放的目录即主题,例如page view日志、click日志等都可以以topic的形式存在,Kafka集群能够同时负责多个topic的分发。
Partition:topic物理上的分组,一个topic可以分为多个partition,每个partition是一个有序的队列
Segment:partition物理上由多个segment组成,每个Segment存着message信息
Producer : 生产message发送到topic
Consumer : 订阅topic消费message, consumer作为一个线程来消费
Consumer Group:一个Consumer Group包含多个consumer, 这个是预先在配置文件中配置好的。各个consumer(consumer 线程)可以组成一个组(Consumer group ),partition中的每个message只能被组(Consumer group ) 中的一个consumer(consumer 线程 )消费,如果一个message可以被多个consumer(consumer 线程 ) 消费的话,那么这些consumer必须在不同的组。Kafka不支持一个partition中的message由两个或两个以上的consumer thread来处理,即便是来自不同的consumer group的也不行。它不能像AMQ那样可以多个BET作为consumer去处理message,这是因为多个BET去消费一个Queue中的数据的时候,由于要保证不能多个线程拿同一条message,所以就需要行级别悲观所(for update),这就导致了consume的性能下降,吞吐量不够。而kafka为了保证吞吐量,只允许一个consumer线程去访问一个partition。如果觉得效率不高的时候,可以加partition的数量来横向扩展,那么再加新的consumer thread去消费。这样没有锁竞争,充分发挥了横向的扩展性,吞吐量极高。这也就形成了分布式消费的概念。
五:拓扑结构
一个典型的Kafka集群中包含若干Producer(可以是web前端FET,或者是服务器日志等),若干broker(Kafka支持水平扩展,一般broker数量越多,集群吞吐率越高),若干ConsumerGroup,以及一个Zookeeper集群。Kafka通过Zookeeper管理Kafka集群配置:选举Kafka broker的leader,以及在Consumer Group发生变化时进行rebalance,因为consumer消费kafka topic的partition的offsite信息是存在Zookeeper的。Producer使用push模式将消息发布到broker,Consumer使用pull模式从broker订阅并消费消息。
六:搭建zk集群
Kafka集群是把状态保存在Zookeeper中的,首先要搭建Zookeeper集群。
1、软件环境
(3台服务器-我的测试)
192.168.229.135 cluster1
192.168.229.130 cluster2
192.168.229.136 cluster3
推荐使用3.4.6 因为kafka在此版本上进行了大量测试 修复了很多bug,经生产环境验证,此版本很稳定。
搭建步骤:
请参考https://blog.csdn.net/qq_35314762/article/details/81463294
注意:
1.示例中使用的是3.4.5 请注意更换版本。
2.修改zoo.cfg 中clientPort=12181 默认是2181
启动ZK:
cd /usr/softAddress/zookeeper/zookeeper-3.4.6/bin
./zkServer.sh start
七:搭建kafka集群
1、软件环境
1、linux一台或多台,大于等于2
2、已经搭建好的zookeeper集群
3、软件版本kafka_2.11-0.9.0.1.tgz
2、创建目录并下载安装软件
cd /usr/softAddress;
mkdir kafka #创建项目目录
cd kafka
mkdir kafkalogs #创建kafka消息目录,主要存放kafka消息
下载软件
wget http://archive.apache.org/dist/kafka/0.9.0.1/kafka_2.11-0.9.0.1.tgz
解压软件
tar -zxvf kafka_2.11-0.9.0.1.tgz
3、修改三台机器的配置文件
进入到config目录
cd /usr/softAddress/kafka/kafka_2.11-0.9.0.1/config
有很多文件,这里可以发现有Zookeeper文件,我们可以根据Kafka内带的zk集群来启动,但是建议使用独立的zk集群
修改
cd /usr/softAddress/kafka/kafka_2.11-0.9.0.1/config
vi server.properties
broker.id=0 每台服务器的broker.id都不能相同 三台分别为0,1,2
hostname
host.name=192.168.229.135
advertised.host.name=192.168.229.130
log.dirs=/usr/softAddress/kafka/kafkalogs
在log.retention.hours=168 下面新增下面三项
message.max.byte=5242880
default.replication.factor=2
replica.fetch.max.bytes=5242880
设置zookeeper的连接端口
zookeeper.connect=192.168.229.135:12181,192.168.229.136:12181,192.168.229.130:12181
参数解释:了解即可
broker.id=0 #当前机器在集群中的唯一标识,和zookeeper的myid性质一样
port=9092 #当前kafka对外提供服务的端口默认是9092
host.name=192.168.7.100 #这个参数默认是关闭的,在0.8.1有个bug,DNS解析问题,失败率的问题。
num.network.threads=3 #这个是borker进行网络处理的线程数
num.io.threads=8 #这个是borker进行I/O处理的线程数
log.dirs=/opt/kafka/kafkalogs/ #消息存放的目录,这个目录可以配置为“,”逗号分割的表达式,上面的num.io.threads要大于这个目录的个数这个目录,如果配置多个目录,新创建的topic他把消息持久化的地方是,当前以逗号分割的目录中,那个分区数最少就放那一个
socket.send.buffer.bytes=102400 #发送缓冲区buffer大小,数据不是一下子就发送的,先回存储到缓冲区了到达一定的大小后在发送,能提高性能
socket.receive.buffer.bytes=102400 #kafka接收缓冲区大小,当数据到达一定大小后在序列化到磁盘
socket.request.max.bytes=104857600 #这个参数是向kafka请求消息或者向kafka发送消息的请请求的最大数,这个值不能超过java的堆栈大小
num.partitions=1 #默认的分区数,一个topic默认1个分区数
log.retention.hours=168 #默认消息的最大持久化时间,168小时,7天
message.max.byte=5242880 #消息保存的最大值5M
default.replication.factor=2 #kafka保存消息的副本数,如果一个副本失效了,另一个还可以继续提供服务
replica.fetch.max.bytes=5242880 #取消息的最大直接数
log.segment.bytes=1073741824 #这个参数是:因为kafka的消息是以追加的形式落地到文件,当超过这个值的时候,kafka会新起一个文件
log.retention.check.interval.ms=300000 #每隔300000毫秒去检查上面配置的log失效时间(log.retention.hours=168 ),到目录查看是否有过期的消息如果有,删除
log.cleaner.enable=false #是否启用log压缩,一般不用启用,启用的话可以提高性能
zookeeper.connect=192.168.7.100:12181,192.168.7.101:12181,192.168.7.107:1218 #设置zookeeper的连接端口
4.启动Kafka集群并测试
1、启动服务
从后台启动Kafka集群(3台都需要启动)
cd /usr/softAddress/kafka/kafka_2.11-0.9.0.1/bin
./kafka-server-start.sh -daemon ../config/server.properties
2、检查服务是否启动
执行命令jps
创建Topic来验证是否创建成功
创建Topic
./kafka-topics.sh –create –zookeeper 192.168.229.135:12181 –replication-factor 2 –partitions 1 –topic test
–replication-factor 2 #复制两份
–partitions 1 #创建1个分区
–topic #主题为shuaige
”’在192.168.229.135服务器上创建一个发布者”’
./kafka-console-producer.sh –broker-list 192.168.229.135:9092 –topic test
”’在192.168.229.136服务器上创建一个订阅者”’
./kafka-console-consumer.sh –zookeeper 192.168.229.136:12181 –topic test –from-beginning
效果如下:
发送消息:
接收消息:
八:kafka生产者模型
8.1、同步生产模型
发送一条消息,如果没有收到kafka集群的确认收到的信号,则再次重发,直到发送次数超过设置的最大次数为止。其中有一次收到了确认,就接着发送下一条消息。
8.2异步生产模型
消息发送到客户端的缓冲队列中,如果队列中条数到了设置的队列最大数或存放时间达到最大值,就把队列中的消息打包,一次性发送给kafka服务端。
两种生产模型对比:
同步生产模型:
(1)低消息丢失率;
(2)高消息重复率(由于网络原因,回复确认未收到);
(3)高延迟
异步生产模型:
(1)低延迟;
(2)高发送性能;
(3)高消息丢失率(无确认机制,发送端队列满)
九:Kafka消费者模型
Kafka消息系统基于发布-订阅模式,相对于ActiveMQ,Rabbitmq没有点对点消息处理机制。
9.1、分区消费模型
2台kafka 服务器,4个分区(P0-P3) ,分区消费模型即为:1个分区对应1个消费实例,如图4个分区,需要4个消费者实例从分区中取数据。
9.2 分区消费编码思路
(1)获取分区的size,一共多少个分区;
(2)针对每一个分区,分别创建一个线程,去消费该分区的数据
(3)每个线程即为一个消费者实例,通过连接;执行消费者构建;消费offset (偏移量);记录消息偏移量。
9.3 组消费模型
同样4个分区,P0-P3,这里使用GroupA,GroupB,GroupA可获取0,3,1,2分区的数据,GourpB也是。分组消费模型中,每个组都能拿到kafka集群当前全量数据。
4、组消费实现思路
(1)获取group里有多少个consumer实例
(2)根据实例个数,创建线程
(3)执行run方法,启动消费
两种消费模型对比:
分区消费模型更加灵活但是:
(1)需要自己处理各种异常情况;
(2)需要自己管理offset(以实现消息传递的其他语义);
组消费模型更加简单,但是不灵活:
(1)不需要自己处理异常情况,不需要自己管理offset;
(2)只能实现kafka默认的最少一次消息传递语义;
十:Java编写生产者和消费者
生产者:
10.1 创建maven工程,pom.xml中增加如下
<dependency>
<groupId>org.apache.kafka</groupId>
<artifactId>kafka_2.10</artifactId>
<version>0.8.2.0</version>
</dependency>
10.2.向主题test内写入数据
package com.kafka;
import java.util.Properties;
import java.util.concurrent.TimeUnit;
import kafka.javaapi.producer.Producer;
import kafka.producer.KeyedMessage;
import kafka.producer.ProducerConfig;
import kafka.serializer.StringEncoder;
public class kafkaProducer extends Thread{
private String topic;
public kafkaProducer(String topic){
super();
this.topic = topic;
}
@Override
public void run() {
Producer producer = createProducer();
int i=0;
while(true){
producer.send(new KeyedMessage<Integer, String>(topic, "message: " + i++));
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private Producer createProducer() {
Properties properties = new Properties();
properties.put("zookeeper.connect", "192.168.229.130:12181,192.168.229.136:12181,192.168.229.135:12181");//声明zk
properties.put("serializer.class", StringEncoder.class.getName());
properties.put("metadata.broker.list", "192.168.229.130:9092,192.168.229.135:9092,192.168.229.136:9092");// 声明kafka broker
return new Producer<Integer, String>(new ProducerConfig(properties));
}
public static void main(String[] args) {
new kafkaProducer("test").start();// 使用kafka集群中创建好的主题 test
}
}
消费者:
package com.kafka;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import kafka.consumer.Consumer;
import kafka.consumer.ConsumerConfig;
import kafka.consumer.ConsumerIterator;
import kafka.consumer.KafkaStream;
import kafka.javaapi.consumer.ConsumerConnector;
public class kafkaConsumer extends Thread{
private String topic;
public kafkaConsumer(String topic){
super();
this.topic = topic;
}
@Override
public void run() {
ConsumerConnector consumer = createConsumer();
Map<String, Integer> topicCountMap = new HashMap<String, Integer>();
topicCountMap.put(topic, 1); // 一次从主题中获取一个数据
Map<String, List<KafkaStream<byte[], byte[]>>> messageStreams = consumer.createMessageStreams(topicCountMap);
KafkaStream<byte[], byte[]> stream = messageStreams.get(topic).get(0);// 获取每次接收到的这个数据
ConsumerIterator<byte[], byte[]> iterator = stream.iterator();
while(iterator.hasNext()){
String message = new String(iterator.next().message());
System.out.println("接收到: " + message);
}
}
private ConsumerConnector createConsumer() {
Properties properties = new Properties();
properties.put("zookeeper.connect", "192.168.229.130:12181,192.168.229.136:12181,192.168.229.135:12181");//声明zk
properties.put("group.id", "group1");// 必须要使用别的组名称, 如果生产者和消费者都在同一组,则不能访问同一组内的topic数据
return Consumer.createJavaConsumerConnector(new ConsumerConfig(properties));
}
public static void main(String[] args) {
new kafkaConsumer("test").start();// 使用kafka集群中创建好的主题 test
}
}
测试:
运行生产者和消费者
查看消费者输出
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。