Kafka相关笔试题

### Kafka

> *昨天阿里网商银行实习内推一面,被惨虐。以为一面也就问问一些基础的东西,结果上来就怼项目,问Kafka,从头问到脚指尖。不过也怨不得别人,只能怪自己学艺不精,有很多该回答上的问题也没有回答上……所以特此再来深入理解一下Kafka。*

------------


 

#### 1. 为什么选择消息队列?

>1)**解耦**:可以独立的扩展或修改数据写入和处理的过程。

2)**冗余**:把数据进行持久化直到它们已经被完全处理,通过这一方式规避数据丢失的风险。

3)**扩展性**:由于解耦了处理过程,所以增大消息入队和处理的频率变得很容易,只要另外增加处理过程即可。

4)**可恢复性:**:系统的一部分组件失效时,不会影响到整个系统。即使一个处理消息的进程挂掉,加入队列中的消息仍然可以在系统恢复后被处理。

5)**缓冲**:有助于控制和优化数据流经过系统的速度,解决生产消息和消费消息的处理速度不一致的情况。

6)**异步通信**:消息队列提供了异步处理机制,允许用户把一个消息放入队列,但并不立即处理它。

------------


 

#### 2. 为什么选择Kafka?

>(与其他消息队列相比,从哪些方面进行比较)

对比Kafka、RabbitMQ和ACtiveMQ(**吞吐量、可靠性、模型架构、可用性、负载均衡方面**)

    

>**1. 吞吐量**:Kafka > RabbitMQ > ActiveMQ

kafka具有较高的吞吐量,**内部采用消息的批量处理,zero-copy机制,数据的存储和获取是本地磁盘顺序批量操作,具有O(1)的复杂度,消息处理的效率很高**。

>**2. 可靠性**:kafka < RabbitMQ。

**RabbitMQ支持对消息的可靠的传递,支持事务,不支持批量的操作;基于存储的可靠性的要求存储可以采用内存或者硬盘**。

>**3. 模型架构方面**:

RabbitMQ遵循AMQP协议,RabbitMQ的broker由Exchange,Binding,queue组成,其中exchange和binding组成了消息的路由键;客户端Producer通过连接channel和server进行通信,Consumer从queue获取消息进行消费(长连接,queue有消息会推送到consumer端,consumer循环从输入流读取数据)。**rabbitMQ以broker为中心;有消息的确认机制**。

kafka遵从一般的MQ结构,producer,broker,consumer,**以consumer为中心,消息的消费信息保存的客户端consumer上**,consumer根据消费的点,从broker上批量pull数据;**无消息确认机制**。

>**4. 可用性方面**:

rabbitMQ支持miror的queue,主queue失效,miror queue接管。kafka的broker支持主备模式。activeMq也支持主备模式。

>**5. 负载均衡方面**:

kafka采用zookeeper对集群中的broker、consumer进行管理,producer可以基于语义指定分片,消息发送到broker的某个分片上。

rabbitMQ的负载均衡需要单独的loadbalancer进行支持。

------------

#### 3. Kafka为什么快?

>在写/读数据的时候通过哪些方法来实现?

(写数据:顺序写入,MMFile。读数据:sendfile,数据压缩)

>*数据压缩:Producer端可以通过GZIP或Snappy格式对消息集合进行压缩,减少数据传输量*

    

>**1.写数据(生产者):**

**1).顺序写入**

  因为硬盘是机械结构,每次读写都会先寻址再写入,其中寻址是一个很耗时的操作。磁盘随机访问I/O的耗时大大地高于顺序I/O。因此,为了提高读写硬盘的速度,Kafka使用顺序I/O的方式。

**2).MMFile**

  Memory Mapped Files(内存映射文件)(mmap)。

  只是顺序写入硬盘,硬盘的访问速度还是不可能追上内存。所以Kafka的数据并不是实时的写入硬盘 ,它充分利用了现代操作系统**分页存储**来利用内存提高I/O效率。

  它的工作原理是直接利用操作系统的Page来**实现文件到物理内存的直接映射**。映射成功后,用户对这段内存区域的修改可以直接反映到内核空间,同样,内核空间对这段区域的修改也直接反映用户空间。

  使用这种方式可以获取很大的I/O提升, 省去了用户空间到内核空间 复制的开销(调用文件的read会把数据先放到内核空间的内存中,然后再复制到用户空间的内存中。)也有一个很明显的缺陷——不可靠, 写到mmap中的数据并没有被真正的写到硬盘,操作系统会在程序主动调用flush的时候才把数据真正的写到硬盘。 Kafka提供了一个参数——producer.type来控制是不是主动flush,如果Kafka写入到mmap之后就立即flush然后再返回Producer叫 同步 (sync);写入mmap之后立即返回Producer不调用flush叫 异步 (async)。

>注意:

>采用内存映射文件,文件的读写是由操作系统来负责的,所以即使Java程序在写入内存后就挂了,操作系统仍然会对内存中的文件写入文件系统。

>但是,如果电源故障或者主机瘫痪,有可能内存映射文件还没有写入磁盘,因此会丢失数据。

>**2.读数据(消费者):**

**Zero Copy + sendfile(优化web Server静态文件的速度)**

&emsp;&emsp;一般的Web Server发送静态文件的过程:先将文件复制到内核空间(read调用)->复制到用户空间->再复制到内核空间(socket调用)->复制到网卡空间进行发送。

&emsp;&emsp;Kafka对此进行优化,采用Zero Copy的机制(页缓存,内存空间映射)减少复制的次数,提高速度。然后,Kafka把所有的消息都存放在一个一个的文件中, 当消费者需要数据的时候Kafka直接把“文件”发送给消费者。(近乎于带宽的速度)

#### 4. 怎样进行扩容?

**1)扩容**

新加入的broker可以向zookeeper注册,加入到集群中。(修改配置文件的zookeeper.connect配置项)

>**新加入的broker只对新的topic起作用**,对已有的topic如果不进行处理是不会承担任何任务的。

**2)topic迁移**

>已有的topic的数据不会自动迁移到新的broker上,需要利用kafka的重新分区分配工具手动操作。迁移是一个很费时的操作。

>步骤:创建json文件->指定要重新分配的topic->生成迁移分配规则文件->执行迁移分配->验证分配

>注意:在迁移过程中不能人为的结束或停止kafka服务,不然会有数据不一致的问题。

优化:1.在topic未被生产和消费时,进行重新分配,避免重复数据和出错;

&emsp;&emsp;&emsp;2.减少迁移的数据量(调整数据保持的默认时间,删除掉不必要的数据)。

#### 5. 容错机制?

主备模式。(partition有副本,但是broker没有副本,所以一旦broker挂掉,该broker的所有消息都不可用)

>每个分区都有一个leader节点,和多个follower节点。一个partition可以复制多份,放在不同的broker上,构成一个集群。

>**Leader副本:**

>负责直接响应client端的读写请求,即和生产者和消费者直接对接,生产者生产一条消息,直接进入Leader副本;

>**Follower副本:**

>作为特殊消费者,被动的接收leader副本中的数据。注意:follower副本不能响应client端的读写请求;

>**ISR集合:**

与leader保持同步的follower,属于ISR副本集合(同步的备份集合),反过来说,在某个时刻,还在被动接收,不是和leader完全一致的,不能属于ISR副本集合,同步完成后才属于ISR集合;

>**ISR集合作用:**

在当前Leader不可用时,Kafka集群会从ISR集合中选取一个Follower升级为新Leader;通过维护ISR集合,一个拥有(N+1)个备份的Topic可用容忍N个备份不可用。(即:**如果一个topic指定了replica factor为N,那么就允许有N-1个Broker出错**)

#### 6. Partition是怎样分配的?

>       1. 将所有Broker(假设共n个Broker)和待分配的Partition排序

>       2. 将第i个Partition分配到第(i mod n)个Broker上 (这个就是leader)

>       3. 将第i个Partition的第j个Replica分配到第((i + j) mode n)个Broker上

#### 7. Kafka是否存在数据丢失?

>可能存在数据丢失,是否丢失取决于采用哪一种Ack机制。

>a. 当Ack设置为0的时候,Producer不和Kafka集群进行确认,当网络发送故障的时候,数据会出现丢失的可能。

>b. 异步发送时,数据会先在Client端按一定规则缓存再批量发送,在这段时间内,如果Client端发送故障,将导致数据丢失。

>c. 异步发送时,Client端缓存的消息超出缓冲区的大小,也可能导致数据丢失。(*为防止缓冲区满,可以设置不限制阻塞超时时间,缓冲区满时就让他一直处于阻塞状态。*)

>d. 当Ack设置为1的时候,只返回leader的确认。当Leader副本接收成功返回确认后,此时Follower副本可能还在同步,这时如果Leader副本发生异常,重新选举出的Leader副本不能和原Leader副本保持一致,将出现数据丢失的情况。

>要想要完全不丢失,就设置为**同步模式**(写入mmap之后立即flush),并且**Ack设置为-1**(即数据写入leader和follower副本后再确认)。

但是这样会导致系统吞吐量大大降低。想要提高吞吐量就设置为异步模式,并且Ack设置为0。

#### 8.消费时的最优设计

>consumer group下的consumer thread的数量等于partition数量,这样效率是最高的。

>因为一个partition中的数据只能被一个consumer grop中的一个consumer线程消费。 一个consumer group下,无论有多少个consumer,这个consumer group一定回去把这个topic下所有的partition都消费了。

#### 9. 什么时候rebalance?

>a. 新consumer加入组、已有consumer主动离开组或已有consumer崩溃了

>b. 订阅topic数发生变更

>c. 订阅topic的分区数发生变更

#### 10. rebalance策略

>控制策略:

a. 在/consumers/[consumer-group]/下注册id

b. 设置对/consumers/[consumer-group] 的watcher

c. 设置对/brokers/ids的watcher

d. zk下设置watcher的路径节点更改,触发consumer rebalance

>算法:

a. 将目标 topic 下的所有 partirtion 排序,存于PT

b. 对某 consumer group 下所有 consumer 排序,存于 CG,第 i 个consumer 记为 Ci

c. N=size(PT)/size(CG),向上取整

d. 解除 Ci 对原来分配的 partition 的消费权(i从0开始)

e. 将第i*N到(i+1)*N-1个 partition 分配给 Ci

猜你喜欢

转载自blog.csdn.net/ZXW601498616/article/details/88798182