前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Kafka-7.设计

Kafka-7.设计

作者头像
悠扬前奏
发布2019-06-11 10:06:14
5280
发布2019-06-11 10:06:14
举报
文章被收录于专栏:悠扬前奏的博客

4.1 动机

Kafka设计的目的是为能作为一个统一的平台来处理大公司可能有的实时数据流。为此,需要考虑相当广泛的用例。

它必须有高吞吐量来支持高容量事件流,例如实时日志聚合。

它需要优雅的处理大量数据的积压,以支持离线系统的定期数据加载。

这也意味着系统必须低延迟交付以处理更传统的消息用例。

我们希望支持对这些feed进行分区,分布式实时处理,来创建新的派生出来的流。这激发了我们使用分区和消费者模式。

最后,在将流传输到其他数据系统进行服务的情况下,我们知道系统需要能够在机器故障时保证容错。

支持这些用途,使我们的设计具有一些独特的元素,更类似于一个数据库日志而不是传统消息传递系统。我们将在以下部分描述一些设计的元素。

4.2 Persistence

不要害怕文件系统

Kafka在很大程度上依赖文件系统来存储和缓存消息。通常大家认为“磁盘很慢”,这让人们怀疑持久性的结构能否提供有竞争力的性能。事实上,根据使用方式的不同,硬盘可以比大家认为得慢得多,也可能快得多。并且设计合理的磁盘结构能够和网络一样快。

关于磁盘性能的关键事实是硬盘的吞吐量和过去十年中磁盘的搜索延迟不同。事实上,有6个7200rpm SATA RAID-5阵列配置的JBOD线性写入性能大于600MB/秒,随机写入性能只有大约100k/秒,-相差超过6000倍。这些线性读取和写入是所有使用模式中最可预测的,并且由操作系统进行了大量优化。现代操作系统提供预读和后写技术,以大块多次预取数据,并将较小的逻辑写入分组为大的物理写入。

为了弥补这种性能差异,现代操作系统在使用主内存作为磁盘缓存方面变得越来越积极。现代操作系统很乐意将所有可用内存转移到磁盘缓存,在回收内存时没有任何性能损失。所有磁盘读写都通过这个统一缓存。这如果不适用直接I/O,这个功能不能轻松关闭,因此即使进程维护了一份数据在进程内的缓存,此数据也可能在操作系统页面缓存中重复,有效地将所有内容重复两次。

此外,我们在构建于JVM之上,任何在Java内存使用上花了时间的人都知道两件事: 对象的内存开销非常高,通常会使存储的数据加倍(甚至更遭)。 随着堆内数据的增加,Java垃圾回收变得越来越频繁和缓慢。 由于这些原因,使用文件系统并依赖于页缓存优于维护内存缓存或其他结构——我们通过自动访问所有可用内存至少能把可用缓存加倍,并且可能通过存储压缩的字节结构而不是单个对象来再加倍。这样做UI在32GB的机器上产生高达28~30GB的缓存,而不会产生GC惩罚。此外,即使服务重启,这些缓存也是warm的,而进程内缓存需要再内存中重建(对于10GB缓存可能需要10分钟),否则它将需要以完全cold的缓存启动(这意味着可怕的初始化性能)。这也极大的简化了代码,因为用于维护高速缓存和文件系统之间的一致性的所有逻辑现在都在操作系统中,与一次性进程内的尝试相比,这旺旺更有效,更正确。如果磁盘使用有利于线性读取,则预读取有效地预先填充此缓存,并在每个磁盘读取时使用有用的数据。 这表明了一个非常简单的设计:当我们用尽空间时,与其尽可能在内存中维护,然后将其全部flush到文件系统中,不如反过来,所有数据立即写入文件系统上的持久化日志中,而不必flush到磁盘。实际上,这意味着它被转移到内核的页缓存中。

这种以页缓存为中心的设计风格在一篇关于Varnish设计的文章中有所描述。

Constant Time Suffices

消息系统中使用的持久化数据结构通常是具有相关联的BTree或其他通用随机访问数据结构的消费队列,以维护关于消息的元数据。BTrees死最通用的数据结构,可以在消息传递系统中支持各种事务和非事务语义。但通常具有相当高的成本:BTree操作是O(log N)。通常认为O(log N)基本上等于constant时间,但是对于磁盘操作则不然。磁盘搜搜速度为10ms,每个磁盘一次只能进行一次搜索,因此并行性有限。因此少数磁盘寻道也会导致非常高的开销。由于存储系统将非常快的高速缓存操作与非常慢的物理磁盘操作混合在一起,因此随着数据随固定的高速缓存的增加,观测到树结构的性能是超线性的——例如,两倍的数据量远不止慢两倍。

直观的,可以在简单读取上构建持久化队列,并将其附加到文件,这与日志记录解决方案的情况一样。该结构的有点事所有操作都是O(1)并且读取不会阻止写入或者相互阻塞。这具有明显的性能优势,应为性能与数据大小分离——一台服务器现在可以充分利用一些连接,低速的1+TB SATA驱动器。虽然他们的搜索性能很差,但是这些驱动器在大量读写时具有可接受的性能,价格是其三分之一,容量是三倍。

在没有任何性能损失的情况下爱访问几乎无限的磁盘空间意味着我们可以提供消息传递系统中通常不具备的一些功能。例如,在Kafka中,我们可以在消费者消费后立即删除消息,而不是试图将消息保留一段相对较长的时间(例如一周)。正如我们将要描述的那样,这为消费者带来了极大的灵活性。

4.3 Efficiency 效率

我们在效率方面投入了非常大的精力。我们的主要使用场景之一是处理Web活动数据,这是非常大量的数据:每个视图页面可能会产生十几个写入。为此我们假设每个发布的内容至少由一个消费者(通常很多)读取,因此我们尽量使消费简单。

我们还从经历过的构建和运行一些类似的系统中发现,效率是影响多租户运行的关键。如果下游基础架构服务因为应用程序的少量使用就很容易成为了瓶颈,那么这样的小改变就产生了问题。通过速度,我们确保应用程序在基础架构之前tip-over under load。 当在一个集中式集群上面尝试运行一个支持数十或上百个应用程序的集中式服务时,这一点尤其重要,因为使用模式的变化几乎每天都在发生。

在上一节我们讨论了磁盘效率,一旦消除了不良的磁盘访问模式,这种类型的系统就有两种常见的低效率的原因:太多小的I/O操作和过多的字节复制。

小I/O问题发生在客户端和服务器之间以及服务器作为自己的持久化操作中。

为了避免这种情况,我们的协议是围绕“消息集”抽象构建的,该抽象自然地将消息组合在一起。这允许网络请求将消息分组在一起并分摊网络往返的开销,而不是一次发送单个消息。服务器依次将消息添加到其日志中,并且消费者一次获取大的线性块。

这种简单的优化可以加速数量级

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019.06.10 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 4.1 动机
  • 4.2 Persistence
    • 不要害怕文件系统
      • Constant Time Suffices
      • 4.3 Efficiency 效率
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档