Spark,Hadoop交流群,群QQ号:521066396,欢迎加入共同学习,一起进步~
一、Apache Kafka简介
官方网址:http://kafka.apache.org/
Kafka™ is used for building real-time data pipelines and streaming apps. It is horizontally scalable, fault-tolerant, wicked fast, and runs in production in thousands of companies.
Kafka 是分布式的发布-订阅消息系统。它最初由 LinkedIn公司开发,使用 Scala语言编写,于2010年12月份开源,成为 Apache 项目的一部分。Kafka 是一个高吞吐量的、持久性的、分布式发布订阅消息系统。它主要用于处理活跃的流式数据(登录、浏览、点击、分享、喜欢等)。
高吞吐量:可以满足百万级别消息处理、非常适合产生大量数据的互联网服务的数据收集业务。
持久性:有一套完善的消息存储机制,确保数据的高效安全的持久化。
分布式:基于分布式的扩展、容错机制;Kafka的数据都会复制到几台服务器上。当某一台故障失效时,生产者和消费者转而使用其它的机器。
1、Kafka概述-消息队列
(1)消息队列(Message Queue)
(2)消息:网络中的两台计算机之间传递的数据。例如:文本、音乐、视频等内容。
(3)队列:一种特殊的线性表,特殊之处在于只允许在首部删除元素和在尾部追加元素。入队、出队。
(4)消息队列:保存消息的队列。消息的传输过程中的容器;主要提供生产、消费接口。
(5)主要的MQ产品:RabbitMQ、ActiveMQ、IBM WEBSPHERE MQ、kafka等。
2、MQ分类:点对点(P2P)、发布订阅(Pub/Sub)
1、共同点:
消息生产者生产消息发送到queue中,然后消息消费者从queue中读取并且消费消息。
2、不同点:
P2P模型包含:消息队列(Queue)、发送者(Sender)、接收者(Receiver)
一个生产者生产的消息只有一个消费者(Consumer),一旦被消费,消息就不在消息队列中。
Pub/Sub包含:消息队列(Queue)、主题(Topic)、发布者(Publisher)、订阅者(Subscriber)
每个消息可以有多个消费者,彼此互不影响。
3、Kafka组件
kafka从大的方面分为:主题[存储实现为代理]、生产者、消费者。
Topic:主题,Kafka处理的消息的不同分类。
Producer:消息和数据的生产者,向Kafka的一个topic发布消息。
Consumer:消息和数据的消费者,订阅topic并处理其发布的消息。
Broker:消息的代理,Kafka集群中的一个kafka服务节点称为一个broker,主要存储消息数据。
Partition:Topic物理上的分组,一个topic在broker中被分为1个或者多个partition。
Message:消息,是通信的基本单位,每个消息都属于一个partition。
4、Kafka拓扑
二、Kafka的安装
下载 http://kafka.apache.org/downloads.html
解压 tar -zxvf kafka_2.11-0.8.2.2.tgz -C /opt
mv /opt/kafka_2.11-0.8.2.2/ /opt/kafka
启动服务
1、配置和启动zookeeper服务
使用kafka内置zk
配置zk文件:/opt/kafka/config/zookeeper.properties 主要是:dataDir设置
启用zk服务:
./zkServer.sh start
或者/opt/kafka/bin/zookeeper-server-start.sh /opt/kafka/config/zookeeper.properties >> /opt/logs/kafka-zk.log 2>&1 &
netstat -an | grep 2181
使用公共的zk
在/opt/kafka/config/server.properties中的zookeeper.connect配置外界zk的地址
2、启动Kafka-server
配置相关参数/opt/kafka/config/server.properties
主要参数:broker.id、port、log.dirs
启动:bin/kafka-server-start.sh config/server.properties > /dev/null 2>&1 &
或者/opt/kafka/bin/kafka-server-start.sh /opt/kafka/config/server.properties >>/opt/logs/kafka-server.log 2>&1 &
三、操作Kafka-Topic
1、增:新增一个topic:”hello”,为它分配2个分区,保存一个副本
bin/kafka-topics.sh --create --zookeeper localhost:2181 --replication-factor 1 --partitions 2 --topic hello
replication-factor不能大于broker数
bin/kafka-topics.sh --create --zookeeper localhost:2181 --replication-factor 1 --partitions 3 --topic world
2、查:查询hello的信息
bin/kafka-topics.sh --describe --zookeeper localhost:2181 --topic hello
Topic:hello PartitionCount:2 ReplicationFactor:1 Configs:
Topic: hello Partition: 0 Leader: 0 Replicas: 0 Isr: 0
Topic: hello Partition: 1 Leader: 0 Replicas: 0 Isr: 0
Leader:partition的leader,主要用的brokerid 0
Replicas:partition的总的副本brokerid的集合 0
Isr:partition的可用的副本brokerid的集合 0
Topic: hello Partition: 0 Leader: 1 Replicas: 1,2,0 Isr: 1,2,0
Topic: hello Partition: 1 Leader: 2 Replicas: 2,0,1 Isr: 2,0,1
Topic: hello Partition: 2 Leader: 0 Replicas: 0,1,2 Isr: 0,1,2
Topic: hello Partition: 3 Leader: 1 Replicas: 1,0,2 Isr: 1,0,2
所有可以使用的topic
bin/kafka-topics.sh --list --zookeeper localhost:2181
3、改:修改hello为2个分区 alter:修改partition数(只能增加)和配置项
bin/kafka-topics.sh --alter --zookeeper localhost:2181 --partitions 3 --topic hello --config segment.bytes=1000000000
4、删:删除world的topic
bin/kafka-topics.sh --delete --zookeeper localhost:2181 --topic world
是否开启topic的删除功能:默认为false。 delete.topic.enable
四、操作Kafka-生产消费
1、创建生产者 producer
创建生产者 producer(往哪些broker生产,生产主题是什么)
bin/kafka-console-producer.sh --broker-list localhost:9092 --topic hello
2、创建消费者 consumer
创建消费者 consumer(上次消费到哪儿了【存在zookeeper上】,消费主题是什么)
bin/kafka-console-consumer.sh --zookeeper localhost:2181 --topic hello --from-beginning
3、标记删除的topic也可以使用
4、生产者:topic、broker-list
5、消费者:topic 、zookeeper
五、broker扩展
Broker:考虑什么问题:数据和硬盘的交互IO。数据的保存期限。
Broker:配置文件server.properties
1、为了减少磁盘写入的次数,broker会将消息暂时buffer起来,当消息的个数达到一定阀值或者过了一定的时间间隔时,再flush到磁盘,这样减少了磁盘IO调用的次数。
配置:Log Flush Policy
log.flush.interval.messages=10000
log.flush.interval.ms=1000
默认都是Long.MAX_VALUE即:9223372036854775807
2、kafka的消息保存一定时间(通常为7天)后会被删除。配置:Log Retention Policy
3、Broker只关心数据存储,不保存消费者的状态,由消息订阅者自己维护。消息订阅者可以rewind back【倒带】到任意位置重新进行消费,当订阅者故障时,可以选择最小的offset(id)进行重新读取消费消息。重新消费数据公司中经常用到。
六、producer扩展
Producer:配置文件:producer.properties
1、自定义partition
Producer也根据用户设置的算法来根据消息的key来计算输入哪个partition:partitioner.class
2、异步或者同步发送
配置项:producer.type
3、批量发送可以很有效的提高发送效率。
Kafka producer的异步发送模式允许进行批量发送,先将消息缓存在内存中,然后一次请求批量发送出去。
具体配置queue.buffering.max.ms、queue.buffering.max.messages。
默认值分别为5000和10000
七、consumer扩展
consumers:配置文件:consumer.properties
1、每个consumer属于一个consumer group,可以指定组id。group.id
2、宏观上看,对于一个Topic的消息,每个消费组消费相同的数据,互不影响;组内的消费者消费同一份数据,各自的内容不同。
3、一个Topic中的一个partions,对于同一个消费者组,只会被一个consumer消费,不过一个consumer可以消费多个partitions中的消息。所以,对于一个topic,同一个group中推荐不能有多于partitions个数的consumer同时消费,否则将意味着某些consumer将无法得到消息。
4、在一个consumer多个线程的情况下,一个线程相当于一个消费者。
例如:partition为3,一个consumer起了3个线程消费另一个后来的consumer就无法消费。
一个partition中的消息只会被group中的一个consumer消费;
每个group中consumer消息消费互相独立;
消费的顺序问题:
在同一个partiton中消费消息是顺序的。
例如:一个消费者在一个partition中的消费顺序和产生的顺序一致。
但是如果一个消费者消费多个partiton的话只能保证消费的顺序在一个partition是顺序的。
比如:一个生产者生产数据:1,2,3,4,5,6
其中1、3、5落在p1,2、4、6落在p2.则一个消费者消费的话顺序不能保证总的顺序是1,2,3,4,5,6。。。也不是消费完p1再消费p2.
问题一:为什么要分组?
(1)增加组内消费者,不会导致数据生产过快,消费不了的问题。
举个例子:一份数据用户的登陆行为。。。
两个部门:实时统计部门、财务部门。2个消费者组。
每个部门内想提高消费效率怎么做?请增加消费者!!!
八、topic、partition、message
1、partition里面的存储层面是append log文件。新消息都会被直接追加到log文件的尾部,每条消息在log文件中的位置称为offset(偏移量)。
2、每条Message包含了以下三个属性:
offset 对应类型:long
MessageSize 对应类型:int32
data 是message的具体内容。
3、每条Message由offset来表示它在这个partition中的偏移量,这个offset不是该Message在partition数据文件中的实际存储位置,而是逻辑上一个值,它唯一确定了partition中的一条Message。因此,可以认为offset是partition中Message的id。
4、越多的partitions意味着可以容纳更多的consumer,有效提升并发消费的能力。
总之:业务区分增加topic、数据量大增加partition。
5、Message的分发
九、kafka集群
部署kafka集群:master、slave1、slave2
zk和kafka的存储路径不要和单节点的一致。如果存储路径一致,最好把原来的topic等数据都删掉,防止数据不一致问题。!!!
1、启动zookeeper(可以使用奇数个节点的zk集群)。
注意zk集群,不是简单的把三个节点自带的zk启动!!!!
判断zk集群的方法:
在一个zk的主机上创建一个zk的文件节点在其它机器上查询。
或者/opt/zookeeper/bin/zkServer.sh status
2、修改配置文件
在master节点的配置/opt/kafka/config/server.properties broker.id=0
修改配置log.dirs=/opt/kafka/kafka-logs
zookeeper.connect=master:2181,slave1:2181,slave2:2181
3、同步其它节点:
scp -r /opt/kafka/ root@slave1:/opt/
scp -r /opt/kafka/ root@slave2:/opt/
修改
slave1的/opt/kafka/config/server.properties broker.id=1
slave2/opt/kafka/config/server.properties broker.id=2
4、启动所有server
/opt/kafka/bin/kafka-server-start.sh /opt/kafka/config/server.properties >>/opt/logs/kafka-server.log 2>&1 &
十、kafka的容错和扩展机制
当kafka集群中的一个broker挂掉(fails),则zk会选择新的broker提供服务。
kill -9 杀掉master的进程测试:
杀掉后如果要存在master机器上只是个警告并且会立马转到其它地方去。
十一、kafka开发
1、java操作kafka
添加maven依赖:
org.apache.kafka
kafka_2.11
0.8.2.2
配置hosts文件 做zookeeper服务器的映射配置。[如果我们的hosts中没有做hosts的配置kafka经多次尝试连接不上就会报错误]
生产者配置文件参数
http://kafka.apache.org/082/documentation.html#producerconfigs
消费者配置文件参数
http://kafka.apache.org/082/documentation.html#consumerconfigs
2、java操作kafka-producer
(1)将生产者的配置文件放在程序的资源目录里。
(2)java加载配置文件生产数据
//加载和配置文件
Properties prop=new Properties();
prop.load(ProducerTest.class.getClassLoader().getResourceAsStream("producer.properties"));
// System.out.println(prop.getProperty("metadata.broker.list"));
Producer<String,String> stringProducer=new Producer<String, String>(new ProducerConfig(prop));
//key是作为分区用的
stringProducer.send(new KeyedMessage<String, String>("hello","first"));
stringProducer.close();
3、java操作kafka-partitioner
public class SimplePartitioner implements Partitioner {
private VerifiableProperties properties;
public SimplePartitioner(VerifiableProperties properties) {
this.properties=properties;
}
public int partition(Object key, int numPartitions) {
String key_str= (String) key;
System.out.println(key_str);
System.out.println(numPartitions);
if (key_str.length()<10){
return 0;
}else{
return 1;
}
}
}
VerifiableProperties 里面是producer的配置信息。注意一个坑!!!
配置:partitioner.class=com.zenith.kafka.SimplePartitioner
partition测试:
01:key=”keykeykeykeykeykeykey” value:”valuesnew” 消费者打印结果:partition:1 offset:5 message:valuenew
01:key=”key” value:”value” 消费者打印结果:partition:0 offset:1 message:value
4、java操作kafka-consumer
(1)将消费者的配置文件放在程序的资源目录里。
(2)java加载配置文件消费数据
offset消费后自动同步功能auto.commit.enable = true、auto.commit.interval.ms = 1000
//加载和配置文件
Properties prop=new Properties();
prop.load(ProducerTest.class.getClassLoader().getResourceAsStream("consumer.properties"));
//创建连接
ConsumerConnector connector= Consumer.createJavaConsumerConnector(new ConsumerConfig(prop));
Map<String,Integer> topicCountMap=new HashMap<String,Integer>();
//消费者线程数
Integer consumerNum=2;
String topic="hello";
topicCountMap.put(topic,consumerNum);
Map<String, List<KafkaStream<byte[], byte[]>>> topicMessageStreams
=connector.createMessageStreams(topicCountMap);
List<KafkaStream<byte[], byte[]>> consumers= topicMessageStreams.get(topic);
ExecutorService threadPool= Executors.newFixedThreadPool(consumerNum);
for(KafkaStream<byte[], byte[]> consumer: consumers){
threadPool.execute(new MessageRunner(consumer));
}
static class MessageRunner implements Runnable{
private KafkaStream<byte[], byte[]> consumer;
MessageRunner(KafkaStream<byte[], byte[]> consumer) {
this.consumer= consumer;
}
public void run(){
ConsumerIterator<byte[], byte[]> it = consumer.iterator();
while(it.hasNext()){
MessageAndMetadata<byte[],byte[]> item = it.next();
System.out.println(String.format("thread:%s partition:%s offset:%s message:%s",Thread.currentThread().getName(),item.partition(),item.offset(),new String(item.message())));
}
}
}
测试:当consuemr数大于partition数目时的测试情况。结果是多于partition的消费者未消费。
十二、kafka分布式协调
1、kafka分布式协调-broker
分布式zk主要体现在Producer,Broker,Consumer在zookeeper上的协调;
Broker在zookeeper中保存为一个节点,每个节点会保存对应broker的IP以及端口等信息。
Broker注册信息:/brokers/ids/[0…N]
ls /brokers/ids :[0, 1, 2]
get /brokers/ids/0
{“jmx_port”:-1,”timestamp”:”1451008496749”,”endpoints”:[“PLAINTEXT://master:9092”],”host”:”master”,”version”:2,”port”:9092}
2、kafka分布式协调-topic
一个topic会被分成多个partition并被分到多个broker上,partition的信息以及broker的分布情况都保存在zookeeper中。
topic创建的时候已经确定了partitions和brokers
(1)topic注册信息:/brokers/topics/[topic] :存储某个topic的partitions所有分配信息
ls /brokers/topics:[hello, world]
get /brokers/topics/hello: {“version”:1,”partitions”:{“1”:[0],”0”:[0]}}
(2)partition状态信息:/brokers/topics/[topic]/partitions/[partitionId]/state
ls /brokers/topics/hello/partitions:[0, 1]
get /brokers/topics/hello/partitions/0/state: {“controller_epoch”:3,”leader”:0,”version”:1,”leader_epoch”:1,”isr”:[0]}
3、kafka分布式协调-consumer
消费者以及消费者组的信息topic、partition、offset也存在zookeeper中。
(1)consumers节点下面为sonsumer组。
s /consumers:[console-consumer-96356, console-consumer-61919]
(2)组内的每个consumer都有一个唯一的ID(consumerId可以通过配置文件指定,也可以由系统生成),此id用来标记消费者信息:/consumers/[groupId]/ids/[consumerIdString]
ls /consumers/console-consumer-61919/ids :[console-consumer-61919_master-1451011792045-d7fdc6a5] 消费者在运行才会显示。
get /consumers/console-consumer-61919/ids/console-consumer-61919_master-1451011792045-d7fdc6a5:{“version”:1,”subscription”:{“hello”:1},”pattern”:”white_list”,”timestamp”:”1451011792113”}
(3)一个topic中的一个partition只有一个消费者消费:消费者在运行才会显示。
/consumers/[groupId]/owners/[topic]/[partitionId] -> consumerIdString + threadId索引编号
ls /consumers/console-consumer-61919/owners:[hello]
get /consumers/console-consumer-61919/owners/hello/0:console-consumer-61919_master-1451011792045-d7fdc6a5-0
(4)一个topic中的一个partition中消费的offset记录信息:/consumers/[groupId]/offsets/[topic]/[partitionId] -> long (offset)
ls /consumers/console-consumer-61919/offsets:[hello]
get /consumers/console-consumer-61919/offsets/hello/0:1
十三、存储策略
在kafka中每个topic包含1到多个partition,每个partition存储一部分Message。每条Message包含了以下三个属性,其中有一个是offset。问题:
offset相当于partition中这个message的唯一ID,那么通过id高效的找到message?
两大法宝:分段、索引
具体存储方式:
1、每个partition有多个segment【片段】组成,每个segment中存储多条消息,
2、每个partition在内存中对应一个index,记录每个segment中的第一条消息偏移。
具体的流程:
发布者发到某个topic的 消息会被分布到多个partition上(随机或根据用户指定的函数进行分布),broker收到发布消息往对应part的最后一个segment上添加 该消息,segment达到一定的大小后将不会再往该segment写数据,broker会创建新的segment。
存储策略-高效查询
1、每个片段一个文件并且此文件以该片段中最小的offset命名,这样在查找指定offset的Message的时候,用二分查找就可以定位到该Message在哪个段中。
2、为每个分段后的数据文件建立了索引文件,文件名与数据文件的名字是一样的,只是文件扩展名为.index,索引文件里存储的分别为相对offset和此message在文件中的position。
3、index文件中并没有为数据文件中的每条Message建立索引,而是采用了稀疏存储的方式,每隔一定字节的数据建立一条索引。这样避免了索引文件占用过多的空间,从而可以将索引文件保留在内存中。
十四、kafka的配置文件
kafka中的配置文件参数主要分为以下三类:
broker配置文件参数
http://kafka.apache.org/082/documentation.html#brokerconfigs
其中有一部分是topic级别的:即可以被topic创建时覆盖。
可以参看:
http://kafka.apache.org/082/documentation.html#topic-config
或者看注释。
生产者配置文件参数
http://kafka.apache.org/082/documentation.html#producerconfigs
消费者配置文件参数
http://kafka.apache.org/082/documentation.html#consumerconfigs
生产环境中根据业务场景来设置参数
主要关注点:生产的方式、存储的策略
十五、Kafka在生产环境中的性能评估
根据自己的集群的配置和业务实际情况来测试性能。
https://cwiki.apache.org/confluence/display/KAFKA/Performance+testing
生产能力:多测试几次求平均。
在kafka的安装目录的bin里有性能的评估工具bin/kafka-producer-perf-test.sh
测试:
bin/kafka-producer-perf-test.sh –broker-list master:9092,slave1:9092,slave2:9092 –topics hello –messages 1000000 –threads 3
2016-01-27 13:43:43:652, 2016-01-27 13:44:01:559, 0, 100, 200, 95.37, 5.3257, 999999, 55844.0275
消费能力:
kafka-consumer-perf-test.sh 多测试几次求平均。
测试:
bin/kafka-consumer-perf-test.sh –zookeeper master:2181,slave1:2181,slave2:2181 –topic hello –messages 1000000 –threads 2
2016-01-27 13:44:55:915, 2016-01-27 13:44:58:350, 1048576, 190.6978, -74.3461, 2000000, -779727.0955
十六、kafka的应用
1、作为消息队列的应用在传统的业务中使用高吞吐、分布式、使得处理大量业务内容轻松自如。
2、作为互联网行业的日志行为实时分析,比如:实时统计用户浏览页面、搜索及其他行为,结合实时处理框架使用实现实时监控,或放到 hadoop/离线数据仓库里处理。
3、作为一种为外部的持久性日志的分布式系统提供服务。主要利用节点间备份数据,文件存储、日志压缩等功能。