Kafka 设计思想
参考
动机
Kafka 被设计为一个统一的平台来处理大公司可能拥有的所有实时数据馈送。要做到这点,需要考虑相当广泛的用例。
Kafka 必须具有高吞吐量来支持高容量事件流,例如实时日志聚合。
Kafka 需要能够处理大量的数据挤压,以便能够支持来自离线系统的周期性数据加载。
这也意味者系统必须低延迟分发,来处理更传统的传递用例。
持久化
Kafka 对消息的存储和缓存严重依赖于文件系统。人们对于 “磁盘速度慢” 的普遍印象,使得人们对于持久化的架构能够提供强有力的性能产生怀疑。事实上,磁盘
的速度比人们预期的要慢的多,也快得多,这取决于人们使用磁盘的方式。而且设计合理的磁盘结构通常可以和网络一样快。
关于磁盘性能的关键事实是,磁盘的吞吐量和过去十年里磁盘的寻址延迟不同。因此,使用 6 个 7200 RPM、SATA 接口、 RAID-5 的磁盘阵列在 JBOD 的配置下
的顺序写入的性能约为 600MB/s, 但随机写入的性能仅约为 100K/s,相差 6000 被以上。因为线性的读取和写入是磁盘使用模式中最有规律的,而且操作系统
进行了大量的优化。现在操作系统提供了 read-ahead 和 write-behind 技术,read-ahead 是以大的 data block 为单位预先读取数据,而 write-behind 是
将多个小型的逻辑写并成一次大型的物理磁盘写入。关于该问题的进一步讨论可以参考 ACM Queue article,他们发现实际上顺序磁盘访问在某些情况下比随机内存访问还要快!
为了弥补这种性能差异,现代操作系统在越来约重视使用内存对磁盘进行 cache。现代操作系统主动将所有空闲内存用作 disk caching,代价是内存回收时性能会有所降低。
所有对磁盘的读写操作都会通过这个统一的 cache。如果不使用直接 I/O,该功能不能轻易关闭。因此即使进程维护了 in-process cache,该数据也可能被复制到
操作系统的 pagecache 中,事实上所有内容都被存储了两份。
此外,Kafka 建立在 JVM 之上,任何了解 Java 内存使用的人都直到两点:
- 对象的内存开销非常高,通常是所存储的数据的两杯(甚至更多)。
- 随着堆中数据的增加,Java 的垃圾回收变得越来越复杂和缓慢。
受这些因素影响,相比于维护 in-memory cache 或者其他结构,使用文件系统和 pagecache 显得更有优势——我们可以通过自动访问所有空闲内存将可以缓存的
容量至少翻倍,并且通过存储紧凑的字节结构而不是对立的对象,有望将缓存容量再翻一番。这样使得 32 GB 的机器缓存容量可以达到 28-30 GB,并且不会产生额外
的 GC 负担。此外,即使服务重新启动,缓存依旧可用,而 in-process cache 则需要在内存中重建(重建一个 10 GB 的缓存可能需要 10 分钟),否则进程既要从
cold cache 的状