一、kafka概述:
1、消息队列:
1)、原理及其有点:
客户端消费Queue种的数据有两种方式:1、发布/订阅模式,也就是一对多,数据生产之后,推给所有的订阅者,打个比方:就像是手机上面的QQ消息,你没有打开手机看消息,但是如果有消息就会一直有消息推送过来。2、点对点模式,也就是一对一,这个是主动模式,第一种模式更像是被动模式,这个就是消费者主动拉取生产后的数据。
2、消息队列的优点:
1)、解耦。2)、冗余。3)、扩展性。4)、灵活性and峰值处理能力。5)、可恢复性。6)、顺序保证。(ps:kafka保证一个partition内的数据是有序的)7)、缓冲。8)、异步通信。
3、kafka基本术语:
1)、无论是kafka集群还是consumer,都依赖zookeeper集群来保存一些meta信息。
2)、Producer:消息生产者,向kafka broker发消息的客户端。
3)、consumer:消息消费者,向kafka broker取消息的客户端。
4)、Topic:可以理解是一个队列,一个topic里有很多个partition。
5)、consumer group:这是kafka用来实现topic广播的和单播的手段。topic的消息会复制(不是真正的复制)到所有的CG,但是每个partition只会把消息发给该CG中的一个consumer。广播的实现方法是:只要每个consumer有一个独立的CG就行了。单播的实现方法是:只要所有的consumer在同一个CG。
6)、Broker:一台kafka服务器就是一个broker,一个集群由多个broker。一个broker可以容纳多个topic。
7)、partition:一个非常大恶的topic可以分布在多个broker上,一个topic可以分成多个partition,每个partition是一个有序队列。partition中的每条消息都会被分配一个有序的ID,kafka只保证按一个partition中的顺序将消息发给consumer,不保证一个topic的整体(多个partition)的顺序。
二、kafka工作流程:
1、Kafka生产过程:
1)、producer采用推(push)模式将消息发布到broker,每条消息都被追加(append)到分区(patition)中,属于顺序写磁盘(顺序写磁盘效率比随机写内存要高,保障kafka吞吐率)。
2)、分区:消息发送时都被发送到一个topic,其本质就是一个目录,而topic是由一些Partition Logs(分区日志)组成。
我们可以看到,每个Partition中的消息都是有序的,生产的消息被不断追加到Partition log上,其中的每一个消息都被赋予了一个唯一的offset值。
①分区的原因:1、方便在集群中扩展,每个Partition可以通过调整以适应它所在的机器,而一个topic又可以有多个Partition组成,因此整个集群就可以适应任意大小的数据了;2、可以提高并发,因为可以以Partition为单位读写了。
②分区的原则:1、指定了patition,则直接使用;2、未指定patition但指定key,通过对key的value进行hash出一个patition;3、patition和key都未指定,使用轮询选出一个patition。
3)、副本:
同一个partition可能会有多个replication,没有replication的情况下,一旦broker 宕机,其上所有 patition 的数据都不可被消费,同时producer也不能再将数据存于其上的patition,没有replication的情况下,一旦broker 宕机,其上所有 patition 的数据都不可被消费,同时producer也不能再将数据存于其上的patition。
4)、写入流程:
2、Broker保存消息:
1)、存储方式:
物理上把topic分成一个或多个patition,每个patition物理上对应一个文件夹(该文件夹存储该patition的所有消息和索引文件)。
2)、存储策略:
无论消息是否被消费,kafka都会保留所有消息。有两种策略可以删除旧数据:
1)基于时间:log.retention.hours=168
2)基于大小:log.retention.bytes=1073741824
需要注意的是,因为Kafka读取特定消息的时间复杂度为O(1),即与文件大小无关,所以这里删除过期文件与提高 Kafka 性能无关。
3)、zookeeper的存储结构:
4)、kafka消费过程分析:
(1)、高级API优点:
1、高级API 写起来简单
2、不需要自行去管理offset,系统通过zookeeper自行管理。
3、不需要管理分区,副本等情况,.系统自动管理。
4、消费者断线会自动根据上一次记录在zookeeper中的offset去接着获取数据(默认设置1分钟更新一下zookeeper中存的offset)。
5、可以使用group来区分对同一个topic 的不同程序访问分离开来(不同的group记录不同的offset,这样不同程序读取同一个topic才不会因为offset互相影响)
(2)、高级API缺点:
1、不能细化控制如分区、副本、zk等。
2、不能自行控制offset(对于某些特殊需求来说)。
(3)、低级API优点:
1、能够让开发者自己控制offset,想从哪里读取就从哪里读取。
2、自行控制连接分区,对分区自定义进行负载均衡
3、对zookeeper的依赖性降低(如:offset不一定非要靠zk存储,自行存储offset即可,比如存在文件或者内存中)
(4)低级API缺点
1、太过复杂,需要自行控制offset,连接哪个分区,找到分区leader 等。
(5)、消费者组:
在这种情况下,消费者可以通过水平扩展的方式同时读取大量的消息。另外,如果一个消费者失败了,那么其他的group成员会自动负载均衡读取之前失败的消费者读取的分区。消费者是以consumer group消费者组的方式工作,由一个或者多个消费者组成一个组,共同消费一个topic。每个分区在同一时间只能由group中的一个消费者读取,但是多个group可以同时消费这个partition。在图中,有一个由三个消费者组成的group,有一个消费者读取主题中的两个分区,另外两个分别读取一个分区。某个消费者读取某个分区,也可以叫做某个消费者是某个分区的拥有者。
(6)、消费方式:
1、consumer采用pull(拉)模式从broker中读取数据。
2、push(推)模式很难适应消费速率不同的消费者,因为消息发送速率是由broker决定的。它的目标是尽可能以最快速度传递消息,但是这样很容易造成consumer来不及处理消息,典型的表现就是拒绝服务以及网络拥塞。而pull模式则可以根据consumer的消费能力以适当的速率消费消息。
3、对于Kafka而言,pull模式更合适,它可简化broker的设计,consumer可自主控制消费消息的速率,同时consumer可以自己控制消费方式——即可批量消费也可逐条消费,同时还能选择不同的提交方式从而实现不同的传输语义。
4、pull模式不足之处是,如果kafka没有数据,消费者可能会陷入循环中,一直等待数据到达。为了避免这种情况,我们在我们的拉请求中有参数,允许消费者请求在等待数据到达的“长轮询”中进行阻塞(并且可选地等待到给定的字节数,以确保大的传输大小)。
三、kafka消息保证机制:
1、At most once:消息可能会丢,但是绝对不会重复传递。
读完消息之后先commit然后再处理消息,在这种模式下comsumer在commit后还没有来得及处理就crash了,下次重新开始工作之后无法读到刚刚已提交而未处理的消息,这就对应了At most once。
2、At least once:消息绝对不会丢,但是可能重复传递。
读完消息之后先处理消息然后再commit,如果在消息处理之后commite之前crash,下次重新开始工作的时候刚刚处理未提交commit消息,但是实际上该消息已经被处理过,这就对应了At least once。
3、Exactly once:每条消息之传输一次仅被传输一次。
如果要做到Exactly once,那么就需要offset来帮助实现,通用的方式是将offset和操作输出输出到同一个地方,但是对于high API来说,offset是保存在zk中的,无法输出到同一个低方,lower API是自己维护offset的,可以将它存在同一个地方,一般存在HDFS。
4、如何保证数据不丢失:
(1)、broker如何保证数据的不丢失:
acks=all : 所有副本都写入成功并确认。
retries = 一个合理值。
min.insync.replicas=2 消息至少要被写入到这么多副本才算成功。
unclean.leader.election.enable=false 关闭unclean leader选举,即不允许非ISR中的副本被选举为leader,以避免数据丢失。
(2)、consumer如果保证数据得不丢失:
enable.auto.commit=false 关闭自动提交offset。