1、kafka概要设计



设计之初的4个问题

  • 吞吐量/延时
  • 消息持久化
  • 负载均衡和故障转移
  • 伸缩性

吞吐量/延时

吞吐量:某种处理能力的最大值;

延时:发出操作 到 收到响应 之间的时间;


kafka写入 —— 如何做到高吞吐量、低延时

这得益于它对于磁盘的使用方法不同。虽然kafka会持久化所有数据到磁盘,但本质上每次写入操作其实都只是把数据写入到操作系统的也缓存(page cache)中,然后由操作系统决定什么时候把也缓存写回到磁盘上。

这样设计的优势:

  • 操作系统的页缓存是在内存中分配的,所以消息写入速度非常快;
  • kafka不必直接与底层文件系统打交道,所有繁琐的I/O操作 都交给操作系统来处理;
  • kafka写入操作采用追加写入(append)的方式,避免了磁盘随机写操作;

kafka消费端 —— 如何做到高吞吐量、低延时

kafka在读取消息时会首先尝试从OS页缓存中读取,如果命中便把消息经页缓存直接发送到网络的socket上,这个过程利用linux的sendfile系统调用实现,这就是大名鼎鼎的零拷贝(Zero Copy)技术。

零拷贝

1、DMA copy 将 磁盘数据 复制到 kernel buffer 中;

2、向 socket buffer 中追加当前要发送的数据在 kernel buffer 中的位置和偏移量;

3、DMA gather copy 根据 socket buffer 中的位置和偏移量直接将 kernel buffer 中的数据copy到网卡上;

经过上述过程,数据只经过了2次copy就从磁盘传送出去了。(事实上这个Zero copy是针对内核来讲的,数据在内核模式下是Zero-copy的)。

当前许多高性能http server都引入了sendfile机制,如nginx,lighttpd等。

1
2
// Java中的零拷贝
FileChannel.transferTo(long position,long count, WriteableByteChannel target);

Java NIO中FileChannel.transferTo(long position, long count, WriteableByteChannel target)方法将当前通道中的数据传送到目标通道target中,在支持Zero-Copy的linux系统中,transferTo()的实现依赖于 sendfile()调用;


高吞吐量、低延时总结

1、大量使用操作系统页缓存,内存操作速度快,命中率高;

2、kafka不直接参与物理 I/O 操作,而是交由最擅长此事的操作系统来完成;

3、采用顺序追加写入方式,摒弃了缓慢的磁盘随机读/写操作;

4、使用以sendfile为代表的零拷贝技术加强网络间的数据传输效率;


消息持久化

持久化的好处

  • 解耦消息发送和消息消费
  • 实现灵活的消息处理

负载均衡和故障转移

负载均衡

实现方式:智能化的分区领导者选举(partition leader election)


故障转移

定义:服务器意外终止时,整个集群可以快速检测到该失效(failure),并立即将该服务器上的应用和服务转移到其他服务器上;

实现方式:心跳或会话机制,kafka通过会话机制来实现。每台kafka服务器把自己注册到zk上,一旦出现故障,与zk的会话不能保持而超时失效。此时,kafka集群会选举出另一台服务器来完全替代这太服务器继续提供服务;


伸缩性

伸缩性,即scalability。表示向分布式系统中增加额外的计算资源(CPU、内存、存储、带宽)时吞吐量提升的能力;

阻碍线性扩容的因素:状态的保存。

  • 如果服务器自己保存自己的状态信息,则必须处理一致性问题;
  • 如果服务器时无状态的,状态的保存和管理交给zookeeper这类服务来做,则大大降低维护复杂度。只需要简单的启动新节点进行自动负载均衡就能扩容集群节点;