Kafka大量依赖文件系统去存储和缓存消息。对于硬盘有个传统的观念是硬盘总是很慢,这使很多人怀疑基于文件系统的架构能否提供优异的性能。实际上硬盘的快慢完全取决于使用它的方式。设计良好的硬盘架构可以和内存一样快。
在6块7200转的SATA RAID-5磁盘阵列的线性写速度差不多是600MB/s,但是随即写的速度却是100k/s,差了差不多6000倍。现代的操作系统都对次做了大量的优化,使用了 read-ahead 和 write-behind的技巧,读取的时候成块的预读取数据,写的时候将各种微小琐碎的逻辑写入组织合并成一次较大的物理写入。对此的深入讨论可以查看这里,它们发现线性的访问磁盘,很多时候比随机的内存访问快得多。
为了提高性能,现代操作系统往往使用内存作为磁盘的缓存,现代操作系统乐于把所有空闲内存用作磁盘缓存,虽然这可能在缓存回收和重新分配时牺牲一些性能。所有的磁盘读写操作都会经过这个缓存,这不太可能被绕开除非直接使用I/O。所以虽然每个程序都在自己的线程里只缓存了一份数据,但在操作系统的缓存里还有一份,这等于存了两份数据。
另外再来讨论一下JVM,以下两个事实是众所周知的:

  • Java对象占用空间是非常大的,差不多是要存储的数据的两倍甚至更高。
  • 随着堆中数据量的增加,垃圾回收回变的越来越困难。

基于以上分析,如果把数据缓存在内存里,因为需要存储两份,不得不使用两倍的内存空间,Kafka基于JVM,又不得不将空间再次加倍,再加上要避免GC带来的性能影响,在一个32G内存的机器上,不得不使用到28-30G的内存空间。并且当系统重启的时候,又必须要将数据刷到内存中( 10GB 内存差不多要用10分钟),就算使用冷刷新(不是一次性刷进内存,而是在使用数据的时候没有就刷到内存)也会导致最初的时候新能非常慢。但是使用文件系统,即使系统重启了,也不需要刷新数据。使用文件系统也简化了维护数据一致性的逻辑。

所以与传统的将数据缓存在内存中然后刷到硬盘的设计不同,Kafka直接将数据写到了文件系统的日志中。

常量时间的操作效率

在大多数的消息系统中,数据持久化的机制往往是为每个cosumer提供一个B树或者其他的随机读写的数据结构。B树当然是很棒的,但是也带了一些代价:比如B树的复杂度是O(log N),O(log N)通常被认为就是常量复杂度了,但对于硬盘操作来说并非如此。磁盘进行一次搜索需要10ms,每个硬盘在同一时间只能进行一次搜索,这样并发处理就成了问题。虽然存储系统使用缓存进行了大量优化,但是对于树结构的性能的观察结果却表明,它的性能往往随着数据的增长而线性下降,数据增长一倍,速度就会降低一倍。
直观的讲,对于主要用于日志处理的消息系统,数据的持久化可以简单的通过将数据追加到文件中实现,读的时候从文件中读就好了。这样做的好处是读和写都是 O(1) 的,并且读操作不会阻塞写操作和其他操作。这样带来的性能优势是很明显的,因为性能和数据的大小没有关系了。
既然可以使用几乎没有容量限制(相对于内存来说)的硬盘空间建立消息系统,就可以在没有性能损失的情况下提供一些一般消息系统不具备的特性。比如,一般的消息系统都是在消息被消费后立即删除,Kafka却可以将消息保存一段时间(比如一星期),这给consumer提供了很好的机动性和灵活性,这点在今后的文章中会有详述。

漫游Kafka设计篇之数据持久化的更多相关文章

  1. 漫游Kafka设计篇之Producer和Consumer

    Kafka Producer 消息发送 producer直接将数据发送到broker的leader(主节点),不需要在多个节点进行分发.为了帮助producer做到这点,所有的Kafka节点都可以及时 ...

  2. 漫游Kafka设计篇之Producer和Consumer(4)

    Kafka Producer 消息发送 producer直接将数据发送到broker的leader(主节点),不需要在多个节点进行分发.为了帮助producer做到这点,所有的Kafka节点都可以及时 ...

  3. 漫游Kafka设计篇之性能优化

    Kafka在提高效率方面做了很大努力.Kafka的一个主要使用场景是处理网站活动日志,吞吐量是非常大的,每个页面都会产生好多次写操作.读方面,假设每个消息只被消费一次,读的量的也是很大的,Kafka也 ...

  4. 漫游Kafka设计篇之性能优化(7)

    Kafka在提高效率方面做了很大努力.Kafka的一个主要使用场景是处理网站活动日志,吞吐量是非常大的,每个页面都会产生好多次写操作.读方面,假设每个消息只被消费一次,读的量的也是很大的,Kafka也 ...

  5. 漫游Kafka设计篇之主从同步

    Kafka允许topic的分区拥有若干副本,这个数量是可以配置的,你可以为每个topci配置副本的数量.Kafka会自动在每个个副本上备份数据,所以当一个节点down掉时数据依然是可用的. Kafka ...

  6. 漫游Kafka设计篇之消息传输的事务定义

    之前讨论了consumer和producer是怎么工作的,现在来讨论一下数据传输方面.数据传输的事务定义通常有以下三种级别: 最多一次: 消息不会被重复发送,最多被传输一次,但也有可能一次不传输. 最 ...

  7. 漫游Kafka设计篇之消息传输的事务定义(5)

    之前讨论了consumer和producer是怎么工作的,现在来讨论一下数据传输方面.数据传输的事务定义通常有以下三种级别: 最多一次: 消息不会被重复发送,最多被传输一次,但也有可能一次不传输. 最 ...

  8. 漫游Kafka入门篇之简单介绍

    介绍 Kafka是一个分布式的.可分区的.可复制的消息系统.它提供了普通消息系统的功能,但具有自己独特的设计.这个独特的设计是什么样的呢?   首先让我们看几个基本的消息系统术语: Kafka将消息以 ...

  9. 漫游Kafka入门篇之简单介绍(1)

    介绍 Kafka是一个分布式的.可分区的.可复制的消息系统.它提供了普通消息系统的功能,但具有自己独特的设计.这个独特的设计是什么样的呢?   首先让我们看几个基本的消息系统术语: Kafka将消息以 ...

随机推荐

  1. HDOJ 1220 Cube

    CubeTime Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submiss ...

  2. close和shutdown的区别

    转的,没验证 close(sock_fd)会把sock_fd的内部计数器减1当sock_fd的内部计数器为0时, 才调用shutodwn(), 并最终释放文件描述符调用shutdown()只是进行了T ...

  3. leetcode course shedule

    题目就不说了,问题本质就是在一个有向图中查找它是不是存在环. 上网百度了一下,方法是,找出图中入度为0 的点,将以它为起点的边去掉. 重复这一动作,直到所有的边都被去掉(没有环)或者存在边但是无法再去 ...

  4. delphi的socket通讯 多个客户端 (转)

    ClientSocket组件为客户端组件.它是通信的请求方,也就是说,它是主动地与服务器端建立连接. ServerSocket组件为服务器端组件.它是通信的响应方,也就是说,它的动作是监听以及被动接受 ...

  5. POJ 3185

    The Water Bowls Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 4088   Accepted: 1609 D ...

  6. hdu 2639 Bone Collector II (01背包,求第k优解)

    这题和典型的01背包求最优解不同,是要求第k优解,所以,最直观的想法就是在01背包的基础上再增加一维表示第k大时的价值.具体思路见下面的参考链接,说的很详细 参考连接:http://laiba2004 ...

  7. x86虚拟地址到物理地址的映射学习

    这里只谈分页管理的机制,也是目前最重要的内存管理机制. 最初的设计想法: 结构图如下: 页的尺寸是4KB,虚拟地址的前20位用于指定一个物理页,后12位用于访问页内偏移. 页表项的结构: 各个位的含义 ...

  8. Maven的配置文件pom.xml

    Maven的配置文件pom.xml 简介: 什么是POM? POM是项目对象模型(Project Object Model)的简称,它是Maven项目中的文件,使用XML表示,名称叫做pom.xml. ...

  9. ArrayList,LinkedList,Vector,Stack之间的区别

    一,线程安全性 Vector.Stack:线程安全 ArrayList.LinkedList:非线程安全 二,实现方式 LinkedList:双向链表 ArrayList,Vector,Stack:数 ...

  10. RSS FEED的应用

    参考:http://inezha.com/help/feedrss 今天工作中遇到了一个知识是RSS FEED.当时觉得很奇怪,我们要这个干嘛用?RSS Feed就是一个xml文件.里面不包含数据,但 ...