1. Kafka的特性?
吞吐量/延时
1)Kafka虽然会持久化,但每次写入操作都是写入操作系统缓存页,然后由操作系统决定在某时刻写入硬盘。
- 操作系统页缓存是内存分配,写入速度快
- 利用partition并行化处理消息,不同分区位于不同机器,发挥了集群的优势
- 零拷贝
- I/O由操作系统完成,解放Kafka,提高了效率
- 写入采用append的方式,比磁盘随机写操作要快得多
- 批量读写
2)读取数据时,首先读缓存页,命中则直接发送到网络Socket上,实现零拷贝(避免了数据在内核态和用户态之间的来回拷贝)。
消息持久化
1)解耦了消息生产者和消息消费者,提高了吞吐量。
2)消息灵活处理:对已经处理过的消息在某个时间点再重演,例如 ETL,以及实时应用程序。
3)用副本机制进行系统冗余,实现高可用。
负载均衡和故障转移(高吞吐和高可用保证)
通过Leader选举实现负载均衡,通过以会话形式注册到Zookeeper上,故障时重选Leader实现故障转移。
伸缩性
每台Kafka服务器只保存轻量级的内部状态,其他状态交于Zookeeper保存,扩展时可直接启动新服务器,降低维护工作量。
2. Kafka中的分区器、序列化器、拦截器是否了解?它们之间的处理顺序是什么?
分区器
消息在通过 send()方法发往 broker 的过程 中, 有可能需要经过拦截器( Interceptor)、序列化器(Serializer)和分区器(Partitioner)的一系列作用之后才能被真正地发往 broker
消息经过序列化之后就需要确定它发往的分区,如果消息 ProducerRecord 中指定了 partition 字段, 那么就不需要分区器的作用 ,因 为 partition 代表的就是所要发往的分区号。如果消息 ProducerRecord 中没有指定 partition 字段,那么就需要依赖分区器 , 根据 key这个字段来计算 partition 的值。分区器的作用就是为消息分配分区
默认分区器:org.apache.kafka.clients.producer.intemals.DefaultPartitioner
//如果不指定消息的key(消息中可以只指定topic和value),则消息发送到的分区是随着时间不停变换的。
//如果指定了消息的key,则会根据消息的hash值和topic的分区数取模来获取分区的
public int partition(String topic, Object key, byte[] keyBytes, Object value, byte[] valueBytes, Cluster cluster) {
// 获取所有的分区集合
List<PartitionInfo> partitions = cluster.partitionsForTopic(topic);
int numPartitions = partitions.size();
// 如果key为空 则使用轮训方式
if (keyBytes == null) {
int nextValue = nextValue(topic);
//可用分区
List<PartitionInfo> availablePartitions = cluster.availablePartitionsForTopic(topic);
if (availablePartitions.size() >