Apache kafka是消息中间件的一种,消息中间件是什么,做一下粗略的讲解,目前Kafka可以做更多的事情。
举个例子,生产者消费者,生产者生产鸡蛋,消费者消费鸡蛋,生产者生产一个鸡蛋,消费者就消费一个鸡蛋,假设消费者消费鸡蛋的时候噎着了(系统宕机了),生产者还在生产鸡蛋,那新生产的鸡蛋就丢失了。再比如生产者很强劲(大交易量的情况),生产者1秒钟生产100个鸡蛋,消费者1秒钟只能吃50个鸡蛋,那要不了一会,消费者就吃不消了(消息堵塞,最终导致系统超时),消费者拒绝再吃了,“鸡蛋”又丢失了,这个时候我们放个篮子在他们中间,生产出来的鸡蛋其实就是“数据流”,系统之间的交互都是通过“数据流”来传输的(就是tcp/http什么的)也称为报文,也叫“消息”。
消息队列满了,其实就是篮子满了,“鸡蛋”放不下了,那赶紧多放几个篮子,其实就是kafka的扩容。
现在清楚kafka是干什么的了把,他就是那个“篮子”。
kafka是什么
Apache kafka官方定义kafka是一个分布式流式计算平台。而在大部分企业开发人员中,都是把kafka当成消息系统使用,即它是一个分布式消息队列,很少会使用kafka的流式计算。四个关键的概念:
kafka名词解释
后面大家会看到一些关于kafka的名词,比如 topic/producer/consumer/broker,这边来简单说明一下。
producer:生产者,就是用来生产“鸡蛋”的。 往kafka发送消息的用户。
consumer:消费者,生出的“鸡蛋”它来消费。接收kafka消息的用户。
topic:你把它理解为标签,生产者每生产出来一个鸡蛋就贴上一个标签(topic),消费者可不是谁生产的“鸡蛋”都吃的,这样不同的生产者出来的“鸡蛋”,消费者就可以选择性的“吃”了。kafka把收到的消息按topic进行分类,因此可以理解为topic是一种类别。
broker:就是篮子了。kafka集群可以由多个kafka实例组成,每个实例(server)称为broker
无论是kafka broker本身,还是producer或者consumer,都依赖于zookeeper集群保存一些meta信息,保证系统可用性,以及使用zookeeper的选举机制。
大家一定要学会抽象的去思考,上面只是属于业务的角度,如果从技术角度,topic标签实际就是队列,生产者把所有“鸡蛋(消息)”都放到对应的队列里了,消费者到指定的队列里取。
消息队列实现原理
点对点模式
一对一,消费者主动拉取数据,消息收到后消息清除。点对点模式通常是一个基于拉取或轮询的消息发送模型。此模型中,消费者从队列主动拉取消息,而不是消息系统推送消息给消费者,并且,消息只能被一个且只有一个消费者接收处理,即使有多个消息监听者也是如此。
发布订阅模式
一对多,数据生产后,推送给所有订阅者。发布订阅模型则是一个基于推送的消息传送模型。发布订阅模型可以有多种不同的订阅者,临时订阅者只在主动监听主题时才接收消息,而持久订阅者则监听主题的所有消息,即使当前订阅者不可用,处于离线状态。
消息队列的作用
解耦
服务与服务之间不需要紧密结合,可以独立扩展,只要确保它们遵守一致的数据结构定义。也可以作为一种异步的实现方式。
冗余
消息队列把数据持久化直到它明确被处理,通过这一方式规避了数据丢失的风险。许多消息队列采用的“插入-获取-删除”范式中,在把一个消息从队列中删除之前,需要你的处理系统明确的指出该消息已经被处理完毕,从而确保你的数据被安全的保存直到你使用完毕。
扩展性
因为消息队列解耦了你的处理过程,所以增大消息入队和处理的频率是很容易的,只要另外增加处理过程即可。
灵活性 & 峰值处理能力
在访问量剧增的情况下,应用仍然需要继续发挥作用,但是这样的突发流量并不常见。如果为以能处理这类峰值访问为标准来投入资源随时待命无疑是巨大的浪费。使用消息队列能够使关键组件顶住突发的访问压力,而不会因为突发的超负荷的请求而完全崩溃
顺序保证
在大多使用场景下,数据处理的顺序都很重要。大部分消息队列本来就是排序的,并且能保证数据会按照特定的顺序来处理。(Kafka 保证一个 Partition 内的消息的有序性)
异步通信
很多时候,用户不想也不需要立即处理消息。消息队列提供了异步处理机制,允许用户把一个消息放入队列,但并不立即处理它。想向队列中放入多少消息就放多少,然后在需要的时候再去处理它们。
kafka架构
1)producer:消息生产者,就是向kafka broker发消息的客户端
2)consumer:消息消费者,就是向 kafka broker 获取消息的客户端
3)topic:消息类别,也可以理解为一个队列
4)consumer group(CG):这是 kafka 用来实现一个 topic 下的消息的广播语义(发给所有的 consumer)和单播语义(发给任意一个 consumer)的手段。一个 topic 可以有多个 consumer group。topic 下的消息会复制给 consumer。**如果需要实现广播,那么只要每个 consumer 有一个独立的 consumer group。要实现单播,只要所有的 consumer 在同一个 consumer group。**consumer group 还可以将 consumer 进行自由的分组,而不需要多次发送消息到不同的 topic。
5)broker:一台 kafka 服务器就是一个 broker。一个集群由多个 broker 组成。一个broker 可以容纳多个 topic。
6)partition:为了实现扩展性,一个非常大的 topic 可以分布到多个 broker(即服务器)上,一个 topic 可以分为多个 partition,每个 partition 是一个有序的队列。partition 中的每条消息都会被分配一个有序的 id(offset)。kafka 只保证按一个 partition 中的顺序将消息发给 consumer,不保证一个 topic 的整体(多个partition间)的顺序。
7)offset:kafka 的存储文件都是按照 offset.kafka 来命名,用 offset 做名字的好处是方便查找。例如你想找位于 2049 的位置,只要找到 2048.kafk a的文件即可。当然t he first offset 就是00000000000.kafka。
分布式模型
Kafka 每个主题的多个分区日志分布式地存储在 Kafka 集群上,同时为了故障容错,每个分区都会以副本的方式复制到多个消息代理节点上。其中一个节点会作为主副本(Leader),其他节点作为备份副本(Follower,也叫作从副本)。主副本会负责所有的客户端读写操作,备份副本仅仅从主副本同步数据。当主副本出现故障时,备份副本中的一个副本会被选择为新的主副本。因为每个分区的副本中只有主副本接受读写,所以每个服务器端都会作为某些分区的主副本,以及另外一些分区的备份副本,这样 Kafka 集群的所有服务端整体上对客户端是负载均衡的。
Kafka 的生产者和消费者相对于服务器端而言都是客户端。 Kafka 生产者客户端发布消息到服务端的指定主题,会指定消息所属的分区。生产者发布消息时根据消息是否有键,采用不同的分区策略。消息没有键时,通过轮询方式进行客户端负载均衡;消息有键时,根据分区语义(例如 hash)确保相同键的消息总是发送到同一分区。 Kafka 的消费者通过订阅主题来消费消息,并且每个消费者都会设置一个消费组名称。因为生产者发布到主题的每一条消息都只会发送给消费者组的一个消费者。所以,如果要实现传统消息系统的“队列”模型,可以让每个消费者都拥有相同的消费组名称,这样消息就会负责均衡到所有的消费者;如果要实现“发布-订阅”模型,则每个消费者的消费者组名称都不相同,这样每条消息就会广播给所有的消费者。
分区是消费者现场模型的最小并行单位。如下图(图1)所示,生产者发布消息到一台服务器的3个分区时,只有一个消费者消费所有的3个分区。在下图(图2)中,3个分区分布在3台服务器上,同时有3个消费者分别消费不同的分区。假设每个服务器的吞吐量时300MB,在下图(图1)中分摊到每个分区只有100MB,而在下图(图2)中,集群整体的吞吐量有900MB。
可以看到,增加服务器节点会提升集群的性能,增加消费者数量会提升处理性能。 同一个消费组下多个消费者互相协调消费工作,Kafka 会将所有的分区平均地分配给所有的消费者实例,这样每个消费者都可以分配到数量均等的分区。Kafka 的消费组管理协议会动态地维护消费组的成员列表,当一个新消费者加入消费者组,或者有消费者离开消费组,都会触发再平衡操作。
Kafka 的消费者消费消息时,只保证在一个分区内的消息的完全有序性,并不保证同一个主题汇中多个分区的消息顺序。而且,消费者读取一个分区消息的顺序和生产者写入到这个分区的顺序是一致的。比如,生产者写入 “hello” 和 “Kafka” 两条消息到分区 P1,则消费者读取到的顺序也一定是 “hello” 和 “Kafka”。如果业务上需要保证所有消息完全一致,只能通过设置一个分区完成,但这种做法的缺点是最多只能有一个消费者进行消费。一般来说,只需要保证每个分区的有序性,再对消息假设键来保证相同键的所有消息落入同一分区,就可以满足绝大多数的应用。