设计之初的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 | // Java中的零拷贝 |
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这类服务来做,则大大降低维护复杂度。只需要简单的启动新节点进行自动负载均衡就能扩容集群节点;