传统的消息队列的概念
Java中关于消息队列是有规范在的—JMS(Java Message Service)规范,概念如下图:
KafKa有哪些自己的特性呢?
分区和集群
- 将数据流分成多个分区,每个分区可以独立地进行读写操作。每个Topic由多个分区组成,这些分区可以分布在集群中的不同Broker上。
以发布订阅的模式为例,消息的生产和消费都是面向Topic的,既然Topic是分成多个分区的,每个分区又能独立的进行读写操作,所以在生产和消费的时候能够实现多实例并发操作,减轻单个实例的负载。
- 多个Broker协作组成了集群。
Controller选举过程
(抢占----上线----唯一----监听等待):
- 第一次启动Kafka集群时,会同时启动多个Broker节点,每一个Broker节点就会连接ZooKeeper,并尝试创建一个临时节点 /controller(抢占)
- 因为ZooKeeper中一个节点不允许重复创建,所以多个Broker节点,最终只能有一个Broker节点可以创建成功,那么这个创建成功的Broker节点就会自动作为Kafka集群控制器节点,用于管理整个Kafka集群。
- 没有选举成功的其他Slave节点会创建Node监听器,用于监听 /controller节点的状态变化。
- 一旦Controller节点出现故障或挂掉了,那么对应的ZooKeeper客户端连接就会中断。ZooKeeper中的 /controller 节点就会自动被删除,而其他的那些Slave节点因为增加了监听器,所以当监听到 /controller 节点被删除后,就会马上向ZooKeeper发出创建 /controller 节点的请求,一旦创建成功,那么该Broker就变成了新的Controller节点了, 称为Controller节点后会接管管理工作,加载最新的元数据,并将元数据同步给其他Slave Broker。
Controller作为管理人员主要的管理内容:
- 监听Broker的状态,上下线,数据在/brokers/ids
- 进行Topic的管理,增删改查。 /brokers/topics
- Partition的管理。
- 分区Leader的选举。
- 分区副本的分配。
Broker包含的服务:
kafka 的消息可靠性
生产端的ACK参数:
ACK值 | 含义 |
---|---|
0 | 当生产数据时,生产者对象将数据通过网络客户端将数据发送到网络数据流中的时候,Kafka就对当前的数据请求进行了响应(确认应答) |
1 | 当生产数据时,Kafka Leader副本将数据接收到并写入到了日志文件后,就会对当前的数据请求进行响应(确认应答) |
-1默认 | 当生产数据时,Kafka Leader副本和ISR Follower副本都已经将数据接收到并写入到了日志文件后,再对当前的数据请求进行响应(确认应答) |
问题优化过程
ACK参数可以根据不同业务场景对数据响应速度以及数据响应的准确度的要求进行配置。
实际业务场景中会存在不可预知的消息不可靠问题,比如网络因素发送不成功,或者响应的丢失等,由此kafka增加数据重试机制。
数据重试直接能导致的问题就是重复和乱序。解决方法是数据的幂等性。
幂等性是给Batch Data一个SeqNum并且结合生产者的ProducerID,给批数据一个唯一性的标识,同时消耗时间和性能(做部分缓冲比对)达到数据的有序和唯一。
KafKa实现事务的必要条件:原子性、一致性、隔离性和永久性(ACID)基本满足。
- 幂等性(Idempotence):事务支持确保生产者的幂等性,即同一条消息不会被重复写入。Kafka通过为每个生产者分配一个唯一的PID(Producer ID)来实现幂等性。
- 原子性(Atomicity):事务操作要么全部成功要么全部失败,保证消息的一致性。
- 隔离性(Isolation):事务消息对消费者不可见,直到事务提交。消费者可以配置isolation.level=read_committed来确保只读取已提交的消息。
- 持久性(Durability):一旦事务提交,消息被持久化到Kafka日志中,保证消息不会丢失。
所以实现数据传输精准一次的条件:
- ack=-1 + 分区副本数>=2 + ISR最小副本数量>=2
- 开启事务
- 幂等性
附录:
消息队列的对比:
Zookeeper中元数据的节点和作用
节点 | 类型 | 说明 |
---|---|---|
/admin/delete_topics | 持久化节点 | 配置需要删除的topic,因为删除过程中,可能broker下线,或执行失败,那么就需要在broker重新上线后,根据当前节点继续删除操作,一旦topic所有的分区数据全部删除,那么当前节点的数据才会进行清理 |
/brokers/ids | 持久化节点 | 服务节点ID标识,只要broker启动,那么就会在当前节点中增加子节点,brokerID不能重复 |
/brokers/topics | 持久化节点 | 服务节点中的主题详细信息,包括分区,副本 |
/brokers/seqid | 持久化节点 | seqid主要用于自动生产brokerId |
/config/changes | 持久化节点 | kafka的元数据发生变化时,会向该节点下创建子节点。并写入对应信息 |
/config/clients | 持久化节点 | 客户端配置,默认为空 |
/config/brokers | 持久化节点 | 服务节点相关配置,默认为空 |
/config/ips | 持久化节点 | IP配置,默认为空 |
/config/topics | 持久化节点 | 主题配置,默认为空 |
/config/users | 持久化节点 | 用户配置,默认为空 |
/consumers | 持久化节点 | 消费者节点,用于记录消费者相关信息 |
/isr_change_notification | 持久化节点 | ISR列表发生变更时候的通知,在kafka当中由于存在ISR列表变更的情况发生,为了保证ISR列表更新的及时性,定义了isr_change_notification这个节点,主要用于通知Controller来及时将ISR列表进行变更。 |
/latest_producer_id_block | 持久化节点 | 保存PID块,主要用于能够保证生产者的任意写入请求都能够得到响应。 |
/log_dir_event_notification | 持久化节点 | 主要用于保存当broker当中某些数据路径出现异常时候,例如磁盘损坏,文件读写失败等异常时候,向ZooKeeper当中增加一个通知序号,Controller节点监听到这个节点的变化之后,就会做出对应的处理操作 |
/cluster/id | 持久化节点 | 主要用于保存kafka集群的唯一id信息,每个kafka集群都会给分配要给唯一id,以及对应的版本号 |