Kafka 内部实现:

Kafka 官方说明了 Kafka 的各种优点,包含:

FileTransfer 的 zero copy 的 IO 实现;
直接写磁盘, 而不做复杂的内存和文件系统之间的转换;
磁盘顺序读写带来的高吞吐;
直接用系统的 page cache 做文件缓存管理, 程序本身不进行缓存管理;
实现了复制高可用;
依赖 Zookeeper 实现客户端的协调和状态存储;

但是这些简化设计是否是“优点”,是仁者见仁的。Broker 本身简单的设计带来的是客户端的复杂性。依赖 Zookeeper 也需要额外维护 Zookeeper 。

存储格式:

每个队列存储在一组序号自增、大小有上限的文件中。

数据持久化:

依赖操作系统的 pdflush 来做 pagecache 中的数据落地无法保证数据的可靠存储,所以 Kafka 提供了一个配置参数,可有由 Kafka 本身调用 fsync 强制落地。其实写文件不强制 fsync 系统也会用 pagecache 缓存这部分数据。

关于 pdflush 的原理可以看 http://www.westnet.com/~gsmith/content/linux-pdflush.htm

可配置参数:

/proc/sys/vm/nr_pdflush_threads
/proc/sys/vm/dirty_writeback_centisecs
/proc/sys/vm/dirty_expire_centiseconds
/proc/sys/vm/dirty_background_ratio

更多关于 Linux IO 调度的内容:
http://www.linuxjournal.com/article/6931

顺序写盘:
——————-
Linux 文件系统中当打开文件的时候是顺序写盘模式;当都是顺序写入的时候也是顺序写盘。
MMAP 会由系统优化尽量顺序读写盘。

Kafka 相关代码:

new RandomAccessFile(file, “rw”).getChannel()

https://github.com/apache/kafka/blob/a984f2fe5e3370163fb53586a04611ebd878c5ae/core/src/main/scala/kafka/utils/Utils.scala#L324

http://www.ericrochester.com/pages/code/parallel-io-with-mmap/

Zero-copy IO 优化:
——————-
Linux 系统底层调用为 sendfile

Java 提供 API:

public void transferTo(long position, long count, WritableByteChannel target);
channel.force(true); = fsync
channel.force(false); = fdatasync

更多参考和 Kafka 中的实现:

http://docs.oracle.com/javase/7/docs/api/java/nio/channels/FileChannel.html
https://github.com/apache/kafka/blob/0.7/core/src/main/scala/kafka/message/FileMessageSet.scala#L102
https://github.com/apache/kafka/blob/0.7/core/src/main/scala/kafka/message/FileMessageSet.scala#L169

Zero copy 避免了应用级别的复制,减少几次调用,提高了效率。

https://www.ibm.com/developerworks/library/j-zerocopy/

灾难恢复:
———–
由于每个 message 都存储了对应的 CRC ,恢复的时候遍历文件中的数据并且校验数据就可以得到可恢复的位置。Kafka 中的实现为:

https://github.com/apache/kafka/blob/a984f2fe5e3370163fb53586a04611ebd878c5ae/core/src/main/scala/kafka/message/FileMessageSet.scala#L189

客户端负载均衡:
—————
所有 broker 节点和生产者、消费者注册到 Zookeeper 。节点变化触发相关客户端的平衡操作。节点都尝试自平衡直到达成一致。

MetaQ:

原理和 Kafka 非常类似,但是接口和数据存储方式有些差异。

MMAP 文件的实现:
https://github.com/alibaba/metaq/blob/8a954248091d21636dd48468be65704aecd435dd/metaq-store/src/main/java/com/taobao/metaq/store/MapedFile.java#L71

我在这里实现了 MetaQ 的 PHP 客户端,需要的可以使用:

https://github.com/doubaokun/metaq-php

Beanstalkd:

简单的单线程应用,读写都使用内存,为了可以停机和恢复数据,写数据的时候会同时写 binlog 文件,binlog 文件的刷盘时间间隔可配置。

最新版本的实现已经将 fsync(2) 更换为 fdatasync 避免 2 次写盘 (即更新文件数据,又更新文件 meta 信息),新建文件为固定大小的文件。

目前实现:
————
只用内存存储,容量上限为内存大小。
通过 binlog 实现数据加载恢复。
将 binlog 周期 fsync 强制写入磁盘。
注意这里的 binlog 并不是 MySQL 类似的 oplog。

推荐这些相关文章

订阅这个博客:

关注我的微博:

关注我的推特: