我们先看kafka的设计元素:
1. 通常来说,kafka的使用是为了消息的持久化(persistent messages)
2. 吞吐量是kafka设计的主要目标
3. 关于消费的状态被记录为consumer的一部分,而不是server。这点稍微解释下,这里的server还是只broker,谁消费了多少数据都记录在消费者自己手中,不存在broker中。按理说,消费记录也是一个日志,可以放在broker中,至于为什么要这么设计,我们写下去了再说。
4. Kafka的分布式可以表现在producer、broker、consumer都可以分布在多台机器上。
在讲实现原理之前,我们还得了解几个术语:
l Topic:其实官网上没有单独提这个词,但topic其实才是理解的关键,在kafka中,不同的数据可以按照不同的topic存储。
l Message:消息是kafka处理的对象,在kafka中,消息是被发布到broker的topic中。而consumer也是从相应的topic中拿数据。也就是说,message是按topic存储的。
l Consumer Group:虽然上面的设计元素第四条,我们说三者都可以部署到多台机器上,三者分别并作为一个逻辑的group,但对于consumer来说这样的部署需要特殊的支持。Consumer Group就是让多个(相关的)进程(机器)在逻辑上扮演一个consumer。这个group的定义其实是为了去支持topic这样的语义。在JMS中,大家最熟悉的是队列,我们将所有的consumer放到一个group中,这样就是队列。而topic则是将consumer放置到与它相关的topic中去。所以无论一个topic存在于多少个consumer中, a message is stored only a single time。你可能会有疑问,备份怎么办,接着看下去。
接下来,我们来看kafka的实现究竟依赖了哪些东西。
1. 硬件上,kafka选用了硬盘直接读写,当然这里也有策略。一个67200rpm STAT RAID5的阵列,线性读写速度是300MB/sec,如果是随机读写,速度则是50K/sec。差距很明显,所以kafka选的策略就是利用线性存储,至于怎么存,我们在存储中会说到。
2. 关于缓存,kafka没有使用内存作为缓存。操作系统用个特性,如果不用direct I/O,那些闲置的memory会去做disk caching,如果 a process maintains an in-process cache of the data,这样的情况下可能会产生双份的pagecache,会存储两遍。另外Kafka跑在JVM上,本身JVM垃圾回收、创建对象都非常的耗内存,所以不再依赖于内存做缓存。All data is immediately written to a persistent log on the filesystem without any call to flush the data. 当然内核自己的flush不算了。温泉做一次32G的内存缓存,需要大概10多分钟。
3. Liner writer/reader:这样做的虽然没有B树那样多样的变化,但却有O(1)的操作,而且读写不会相互影响。同时,线性的读写也解耦了数据规模的问题。用廉价的存储就可以达到很高的性价比。
4. Zero-copy:将数据从硬盘写到socket一般需要经过…你可以自己算一下,这是操作系统里的知识,答案在文章末尾,具体也可以看这里:http://my.oschina.net/ielts0909/blog/85147。一句话,Zero-copy减少了IO的操作步骤。
5. GZIP and Snappy compression:考虑到传输最大的瓶颈就在于网络上,kafka提供了对数据压缩的各种协议。
6. 事务机制:虽然kafka对事务的处理比较薄弱,但是在message的分发上还是做了一定的策略来保证数据递送的准确性: