总结一下自己对于kafka的理解,可能说的没有那么官方,也不像别的博客都是抄来抄去,都是结合别人的看法和自己的理解写的一篇关于kafka入门的教程。
基础概念
- broker(多个实例集群)、producer、consumer
- topic、broker、consumer都依赖zookeeper(08以后consumer就不依赖zk了)
- topic可以有多个分区 partition,分区就是个文件夹里面存数据,在logs目录下
- topic也可以有多个副本(副本数不能超过broker数),多副本下每个partition都分leader和follower。每次都是往leader中写数据,follower自己去往leader中同步数据。
- 可以往不存在的topic中发数据,会自己创建该topic,默认分区和副本都是在server.properties中配置的,都是1。
- ISR(In-Sync Replicas 副本同步队列):isr的顺序,为了leader挂了之后选举用的,排的顺序谁在前谁当leader
- 08以后新版本offset是维护在本地,存在topic中的(__consumer_offsets),减少和zk的通信,增加效率。
工作流程分析
生产者:
- 采用推(push)模式将消息发布到broker,每条消息都被追加到分区中,属于顺序写磁盘(顺序写磁盘比随机写内存要高,保障kafka吞吐率)
- 发送消息时都是被发送到一个topic,其本质就是一个目录,topic是由一些PartitionLogs组成,分区内有序,生产的消息被追加到partition上,每个消息在分区内被赋予一个唯一的offset。
- 分区的原因:
做负载;
增加吞吐量,提高并发,可以多个消费者同时消费数据。 - 分区原则:
1)指定partition,则直接使用
2)未指定partition,指定了key,按照key进行hash出一个partition
3)partition和Key都未指定,通过轮询来选出一个partition
4)可以自定义分区选择器,实现Partitioner接口,重写partition()方法,然后使用自定义的分区选择器就行。(关于这点,后续有具体说明) - 副本:一个partition有多个replication,如果没有replication,一旦broker宕机,其上所有partition的数据都不可被消费。
- ack应答机制:
0:不需要确认leader是否收到消息
1:只需要确认leader收到消息(默认的)
all:需要所有副本多写入成功
设置 acks=all 时,如果延迟增大:可以增大 num.replica.fetchers(follower 同步数据的线程数)来调解
注:(两个副本的情况下,0和all的效率差距10倍) - 写入流程:
producer先从brokers中找到该partition的leader,producer发消息给leader,leader将消息写入本地log,followers从leader中pull消息,写入本地log后向leader发送ack,leader收到所有ISR中的replication的ACK之后,增加HW,并向producer发送ACK。
保存消息:
- 存储方式:存在logs文件中,.log后缀的文件,在磁盘中。
- 存储策略:无论消息是否被消费,kafka都会保留所有消息,两种策略删除旧数据
log.retention.hours=168
log.segment.bytes=1073741824
删除过期文件与kafka性能无关
消费过程:
- 同一个消费组中,同一个消费者可以消费不同分区中的数据,但是不同的消费者不能消费同一个分区中的数据。
- 一般有多少分区就设置多少消费者,能保证最大化吞吐。
ISR机制
再详细说下Kafka的ISR机制:
1.首先ISR,即In-Sync Replicas 副本同步队列,每个partition都有一个ISR,它是由leader维护的,表示这个partition的数据在哪几个服务器上,可以shell命令查看ISR:
[root@tourbis kafka_2.10-0.8.2.1]# bin/kafka-topics.sh --describe --zookeeper localhost:2181 --topic test
Topic:test PartitionCount:3 ReplicationFactor:3 Configs:
Topic: test Partition: 0 Leader: 1 Replicas: 1,3,2 Isr: 1,3,2
Topic: test Partition: 1 Leader: 2 Replicas: 2,1,3 Isr: 2,1,3
Topic: test Partition: 2 Leader: 3 Replicas: 3,2,1 Isr: 3,2,1
表示1个Topic,3个分区,每个分区有3个副本。Isr的数字表示broker.id,如果Leader宕机了,会在剩下的Isr中选举一个出来当Leader。
2.follower是自己主动从leader批量拉取消息的,这个和kafka的消费者有点类似;是在后台启动线程ReplicaFetcherThread,个数是由num.replica.fetchers配置决定,如果acks设置为-1的时候,消息写入延迟有点大,可以适当增加这个配置,加快副本同步速度。
3.leader会追踪和维护ISR中所有follower的滞后状态,包括数量和时间这两个维度(replica.lag.time.max.ms和replica.lag.max.message),超过的话就会从ISR中剔除,进入OSR(Outof-Sync Replicas);剔除的目的是为了不影响写的数据,因为要ISR中所有副本都想Leader发送ACK时,Leader才commit成功,只有commit成功的数据才会对消费者可见,即HW。
其他
-
为什么要使用 kafka,为什么要使用消息队列
缓冲和削峰:上游数据时有突发流量,下游可能扛不住,或者下游没有足够多的机器来保证冗余,kafka在中间可以起到一个缓冲的作用,把消息暂存在kafka中,下游服务就可以按照自己的节奏进行慢慢处理。
解耦和扩展性:项目开始的时候,并不能确定具体需求。消息队列可以作为一个接口层,解耦重要的业务流程。只需要遵守约定,针对数据编程即可获取扩展能力。
冗余:可以采用一对多的方式,一个生产者发布消息,可以被多个订阅topic的服务消费到,供多个毫无关联的业务使用。
健壮性:消息队列可以堆积请求,所以消费端业务即使短时间死掉,也不会影响主要业务的正常进行。
异步通信:很多时候,用户不想也不需要立即处理消息。消息队列提供了异步处理机制,允许用户把一个消息放入队列,但并不立即处理它。想向队列中放入多少消息就放多少,然后在需要的时候再去处理它们。 -
kafka 为什么那么快
Cache Filesystem Cache PageCache缓存
顺序写 由于现代的操作系统提供了预读和写技术,磁盘的顺序写大多数情况下比随机写内存还要快。
Zero-copy 零拷技术减少拷贝次数
Batching of Messages 批量量处理。合并小的请求,然后以流的方式进行交互,直顶网络上限。
Pull 拉模式 使用拉模式进行消息的获取消费,与消费端处理能力相符。