一、kafka的作用
1.削峰填谷
削峰填谷是Kafka最常见的功能,所谓削峰填谷是指缓存上下游瞬时突发流量,使其更加平滑。特别是对于那种发送能力很强的上游系统,如果没有消息引擎的保护,“脆弱”下游系统可能会直接被压垮导致全链路服务“雪崩”。但是,一旦有了消息引擎,它能够有效的对抗上游的流量冲击,真正做到将上游的“峰”填满到“谷”中,避免了流量震荡
2.系统解藕
消息引擎另一好处在于发送方和接收方的耦合度,在一定程度上简化应用开发,减少系统不必要的交互。
二、kafka术语
1.生产者、消费者
Kafka属于分布式的消息引擎系统,它的主要功能是提供一套完备的消息发布与订阅解决方案。在Kafka中,发布订阅的对象是主题(Topic),你可以为每个业务、每个应用甚至是每类数据都创建专属的主题。向主题发布消息的客户端应用称为生产者(Producer)、生产者程序通常持续不断地向一个或多个主题发送消息,而订阅这些主题消息的客户端被称为消费者(Consumer)。我们将生产者和消费者统称客户端(Clients)。有客户端自然会有服务端,Kafka的服务器端由被称为Broker的服务进程构成。一个Kafka集群由多个Broker组成,Broker负责接收和处理客户端发送过来的请求,以及对消息的持久化。虽然存在多个Broker进程运行在同一台机器上。但更常见的做法是将不同的Broker分散运行在不同的机器上,这样如果集群中某一台机器宕机,即使在它上面运行的所有Broker进程都挂掉,其他机器上的Broker也依然能够对外提供服务。这是Kafka提供高可用的手段之一。
2.副本
Kafka实现高可用的另外一个手段就是备份机制(Replication),备份的思想很简单,就是将相同的数据拷贝到多台机器上,而这些相同的数据拷贝在Kafka中被称为副本(Replica)。这些副本虽然存储着相同的数据,却扮演着不同的角色,Kafka定义了两类副本:领导者副本(Leader Replica)和追随者副本(Follower Replica)前者对外提供服务(这里的对外是指和客户端的交互),而追随者副本只是被动的追随领导者副本,不能与外界交互。副本的工作机制非常简单:生产者向领导者副本写消息;而消费者总是从领导者副本读消息。至于追随者副本,它只做一件事:向领导者副本发送请求,请求领导者副本将最新生产的消息发送给他,与领导者副本保持同步。
2.分区
副本的机制可以保证数据的持久化或者叫不丢失,但是并没有解决伸缩性Scalability的问题,伸缩性是分布式系统中非常重要且必须要谨慎对待的问题,比如说副本机制,但倘若领导者副本积累了太多的数据以至于单台Broker机器都无法容纳了,这时应该怎么办,一个很自然的想法就是,是否能将数据分割成多份保存在不同的Broker上?这就是Kafka的设计的分区(Partitioning)。分区的概念在其他分布式系统中也是相同的原理,比如说MongoDB和Elasticsearch中的Sharding,HBase的Region。Kafka的分区将一个主题划分到多个分区(Partitioning)中,每个分区是一组有序的消息日志。生产者生产的每条消息只会被发送到一个分区中,也就是如果向一个双分区的主题发送一条消息,这条消息要么在分区0中,要么在分区1中。值的注意的是,Kafka的的分区编号是从0开始的。
3.分区与副本
在上面我们讲到了分区和副本,那么副本是基于Broker的还是基于分区的呢,实际上副本是基于分区这个层级定义的,每个分区下可以有多个副本,其中一个领导者副本和N-1个追随者副本。生产者向分区写入消息,每条消息在分区中的位置由位移(offset)来表示,分区位移也是从0开始,假设一个生产者向一个空分区写入了10挑选,那么这10条信息的offset分别是0、1、2.....9。
4.Kafka持久化
在前面我们提到了Kafka在Broker中使用了副本机制,持久化消息,Kafka使用的是消息日志(Log)来保存数据,消息日志就是磁盘上一个只能追加写(Append-Only)消息的物理文件,因为追加写入,不需要等待磁盘选区,所以避免了缓慢的随机I/O操作,使用了性能较好的顺序I/O写操作,这是Kafka高吞吐量特性的一个重要手段。由于不断向日志写入消息,终究会耗尽磁盘的空间,因此Kafka会定期的删除消息来回收磁盘,Kafka将日志分成日志段(Log Segment)的形式,在Kafka中一个日志被切分多个日志段,消息被追加在最新的日志段中,当写满一个日志段后,Kafka会重新生产一个新的日志段,并将老的日志段封存,Kafka会有定时任务定期检查老的日志段是否能删除。
5.消费组
在Kafka中会有两种消费模型,点对点模式(PeerToPeer,P2P),是指同一条消息只能被下游的一个消费者消费,其他消费者不能参与消费。在Kafka中实现这种P2P模型的方法就是引入了消费组(Consumer Group)多个消费者是例组成一个组来消费一组主题,这组主题的每个分区都只会被组内的一个消费者实例消费。为什么要引入消费组?其目的主要是为了提升消费者端的吞吐量,多个消费者实例消费,加速整个消费端的吞吐量(TPS)。消费组所有的消费者“瓜分”订阅主题的数据,而且他们还会彼此进行协作,比如说组内的某个消费实例挂掉了,Kafka能够自动检测到,然后将这个挂掉的实例负责的分区转移给其他活着的消费者,这个过程中就是Kafka大名鼎鼎的“重平衡”
开放问题
(1)Kafka中一个Broker会记录一个主题内所有分区吗?
不一定。在Kafka中,一个主题可以被划分为多个分区,每个分区都会有一个Broker作为它的"Leader"。同时,为了提高系统的可用性,Kafka还会在其他Broker上为这个分区创建若干个副本,这些副本称为"Follower"。 所以,一个Broker可能会记录一个主题内的一个或多个分区,这取决于该Broker是哪些分区的Leader或Follower。同时,一个分区的Leader和所有的Follower加起来,可能会分布在多个Broker上。
(2)Kafka中主题划分为多个分区,每个分区对应消费者组中一个消费者,那么如果消费者少了怎么办,比如说有4个分区,但是消费者组只有3个消费者可以正常消费吗?
可以的。在Kafka中,消费者数量少于分区数量是可以的。在这种情况下,会有一个或多个消费者消费多个分区的数据。 例如,如果有4个分区,但消费者组只有3个消费者,那么可能的分配方式是:消费者1消费分区1,消费者2消费分区2,消费者3消费分区3和分区4。
需要注意的是,Kafka的分区机制保证了同一个分区内的消息会按照它们的顺序被消费,但不同分区之间的消息并不保证顺序。所以,如果一个消费者消费多个分区,那么这些分区的消息可能会交错消费。
(3)为什么Kafka不支持主从同步,类似于Mysql的从对外提供也对外提供服务? Kafka的设计理念和MySQL不同,它主要是为了处理大规模的实时数据流,因此其数据复制策略也是为了满足这个目标。
在Kafka中,每个主题可以分为多个分区,每个分区有一个Leader和多个Follower。所有的读写操作都是通过Leader进行的,Follower只是用来备份数据和在Leader宕机时接管服务。
这样设计的原因主要有两点:
- 简化设计:所有的读写操作都通过Leader进行,可以避免数据不一致的问题,简化了系统的设计。
- 提高性能:Kafka的目标是处理大规模的实时数据流,如果Follower也对外提供服务,那么在数据复制时就需要保证数据的一致性,这会增加系统的复杂性和开销,降低性能。
所以,Kafka不支持主从同步,也不支持从对外提供服务。但这并不意味着Kafka的可用性差,因为Kafka通过分区和副本的机制,可以在Leader宕机时快速切换到Follower,保证服务的可用性。