kafka线上环境部署(集群环境规划)

本文摘自胡夕 《Apache Kafka实战》,详细内容,请购买正版书籍

集群环境规划

典型的生产环境至少需要部署多个节点共同组成一个分布式集群整体为我们提供服务。本章将会详细讨论生产环境中集群的安装、配置与验证。不过在此之前,我们还需要解决 3 个方面的问题。它们分别是操作系统的选型、硬件规划和容量规划。

操作系统的选型

谈到操作系统,很多人可能会问: Kafka 不是JVM系的大数据框架吗?而 Java 又是跨平台的语言,那么使用什么操作系统有什么区别吗?当然有区别!

众所周知, Kafka 的服务器端代码是由 Scala 语言编写的,而新版本客户端代码是由 Java语言编写的。和 Java 一样, Scala 编译器会把源程序 .scala 文件编译成.class 文件,因此 Scala 也是 JVM系的语言。这样来看的话,貌似只要是支持 Java 程序部署的平台都应该能够部署Kafka。但既然本章讨论 的是生产环境的部署 ,那么我们就需要仔细地选型各种操作系统并梳理出它们对于 Kafka 的相适性。

目前部署 Kafka 最多的 3 类操作系统分别是 Linux、 OS X 和 Windows,其中部署在 Linux上的最多,而 Linux 也是推荐的操作系统。为什么呢?且不说当前的现状的确是 Linux 服务器数量最多,单论它与 Kafka 本身的相性, Linux 也要比 Windows 等其他操作系统更加适合部署 Kafka。这里笔者罗列出自己能想到的两个主要原因: I/O 模型的使用和数据网络传输效率。

谈到 I/O 模型,就不能不说当前主流且耳熟能详的 5 种模型:阻塞 I/O、非阻塞 I/O、 I/O多路复用、信号驱动 I/O 和异步 I/O。每一种 I/O 模型都有典型的使用场景,比如 Socket 的阻塞模式和非阻塞模式就对应于前两种模型,而 Linux 中的 select 函数就属于 I/O 多路复用模型,至于第 5 种模型其实很少有 UNIX 和类 UNIX 系统支持, Windows 的 IOCP ( l/O Completion Port,简称 IOCP )属于此模型 。至于大名鼎鼎的 Linux epoll 模型,则可以看作兼具第 3 种和第 4 种模型的特性。

由于篇幅有限,我们不会针对每种 I/O 模型进行详细的展开,但通常情况下我们会认为epoll 比 select 模型高级。毕竟 epoll 取消了轮询机制,取而代之的是回调机制( callback )。这样当底层连接 Socket 数较多时,可以避免很多无意义的 CPU 时间浪费。另外, Windows 的IOCP 模型可以说是真正的异步 I/O 模型,但由于其母系统的局限性, IOCP 并没有广泛应用。

说了这么多,这些和 Kafka 又有什么关系呢?关键就在于 clients 底层网络库的设计。Kafka 新版本 clients 在设计底层网络库时采用了 Java 的 Selector 机制,而后者在 Linux 上的 实现机制就是epoll;但是在 Windows 平台上, Java NIO 的 Selector 底层是使用 select 模型而非IOCP 实现的,只有 Java NIO2 才是使用 IOCP 实现的 。因此在这一点上,在 Linux 上部署Kafka 要比在 Windows 上部署能够得到更高效的 I/O 处理性能 。

对于第二个方面,即数据网络传输效率而言, Linux 也更有优势。具体来说, Kafka 这种应用必然需要大量地通过网络与磁盘进行数据传输 ,而大部分这样的操作都是通过 Java 的FileChannel.transferTo 方法实现的。在Linux 平台上该方法底层会调用 sendfile 系统调用,即采用了 Linux 提供的零拷贝( Zero Copy )技术。
如前面章节所言,这种零拷贝技术可以有效地改善数据传输的性能。在内核驱动程序处理I/O 数据的时候,它可以减少甚至完全规避不必要的 CPU 数据拷贝操作,避免数据在操作系统内核地址空间和用户应用程序地址空间的缓冲区间进行重复拷贝,因而可以获得很好的性能。Linux 提供的诸如 mmap 、 sendfile 以及 splice 等系统调用即实现了这样的技术 。

然而对于 Windows 平台而言,虽然它也提供了 TransmitFile 函数来支持零拷贝技术,但是直到 Java 8u60 版本 Windows 平台才正式让 FileChannel 的 transferTo 方法调用该函数。具体详见这个 JDK bug: http://bugs.java.com/view_bug.do?bug_id=8064407 。

鉴于很多公司目前的生产环境中还没有正式上线 Java 8 ,因而在 Windows 平台上部署Kafka 将很有可能无法享受到零拷贝技术带来的高效数据传输 。

综合以上两点差异以及目前主流服务器通常在 Linux 上部署的事实,笔者强烈推荐 Kafka的生产环境集群首选 Linux 操作系统。当然至于是 Linux 的哪个发行版,笔者倒没有特别的偏
好,只要是读者熟悉的即可 。

磁盘规划

前面主要讨论了该如何选择合适的操作系统平台来安装部署 Kafka 。 从现在开始,我们将分别从磁盘、内存、带宽和 CPU 等几个方面探讨部署 Kafka 集群所必要的关键规划因素。首先从磁盘开始说起。

如果问哪个因素对 Kafka 性能最重要?磁盘无疑是排名靠前的答案。众所周知, Kafka 是大量使用磁盘的。Kafka 的每条消息都必须被持久化到底层的存储中,并且只有被规定数量的broker 成功接收后才能通知 clients 消息发送成功, 因此消息越是被更快地保存在磁盘上,处理clients 请求的延时越低,表现出来的用户体验也就越好。

在确定磁盘时,一个常见的问题就是选择普通的机械硬盘 C HDD )还是固态硬盘 CSSD )。机械硬盘成本低且容量大,而 SSD 通常有着极低的寻道时间 ( seek time)和存取时间 ( accesstime ),性能上的优势很大,但同时也有着非常高的成本 。因此在规划 Kafka 线上环境时, 读者就需要根据公司自身的实际条件进行有针对性的选型。但以笔者使用 Kafka 的经验来看,Kafka 使用磁盘的方式在很大程度上抵消了 SSD 提供的那些突出优势 。众所周知, SSD 强就强在它不是机械装置,而全部由电子芯片及电路板组成,因而可以极大地避免传统机械硬盘缓慢的磁头寻道时间。一般机械硬盘的寻道时间都是毫秒级的 。若有大量的随机 VO 操作,则整体的磁盘延时将是非常可观的,但 SSD 则不受这样的拖累 。可是这点差异对于 Kafka 来说又显得不是那么重要。为什么?因为 Kafka 是顺序写磁盘的,而磁盘顺序 I/O 的性能,即使机械硬盘也是不弱的一一顺序 I/O 不需要频繁地移动磁头,因而节省了耗时的寻道时间 。 所以从磁盘的使用这个方面来看,笔者并不认为两者有着巨大的性能差异。关于Kafka 底层的持久化实现,我们会在第 6 章中详细讨论。因此对于预算有限且追求高性价比的公司而言 ,机械硬盘完全可以胜任 Kafka 存储的任务 。

关于磁盘的选择,另一个比较热门的争论就在于, JBOD 与磁盘阵列(下称 RAID )之争。这里的 JBOD 全称是 Just Bunch Of Disks,翻译过来就是一堆普通磁盘的意思。在部署线上Kafka 环境时,应当如何抉择呢?是使用 一堆普通商用磁盘进行安装还是搭建专属 的 RAID 呢?
答案依然是具体问题具体分析 。

首先分析一下 RAID 与 Kafka 的相适性。常见的 RAID 是 RAID 10,也被称为 RAID 1+0,它结合了磁盘镜像和磁盘条带化两种技术共同保护数据,既实现了不错的性能也提供了很高的可靠性。 RAID 10 集合了 RAID 0 和 RAID 1 的优点,但在空间上使用了磁盘镜像,因此整体的磁盘使用率只有 50%,换句话说就是将一半的磁盘容量都用作提供冗余。自 Kafka 0.8.x 版本开始,用户就可以使用 RAID 作为存储来为 Kafka 提供服务了。事实上,根据公开的资料显示, Linkedln 公司的 Kafka 集群就是使用 RAID 10 作为底层存储的 。除了默认提供的数据冗余之外, RAID 10 还可以将数据自动地负载分布到多个磁盘上 。
由此可见, RAID 作为 Kafka 的底层存储其实主要的优势有两个。

  • 提供冗余的数据存储空间。
  • 天然提供负载均衡。

以上两个优势对于任何系统而言都是非常好的特性。不过对于 Kafka 而言,就像在第 1 章中介绍的那样, Kafka 在框架层面其实己经提供了这两个特性 : 通过副本机制提供冗余和高可靠性,以及通过分散到各个节点的领导者选举机制来实现负载均衡,所以从这方面来看,RAID 的优势就显得不是那么明显了 。当然笔者绝没有全盘否定 RAID 的意思,实际上,依然有很多公司和组织使用或者打算在 RAID 之上构建 Kafka 集群。不过既然是资源规划和硬件选型,我们不妨看下 Linkedln 公司是怎么做的。

之前提到过, Linkedln 公司目前的 Kafka 就搭建于 RAID 10 之上 。 他们在 Kafka 层面设定的副本数是 2,因此根据 RAID 10 的特性,这套集群实际上提供了 4 倍的数据冗余,且只能容忍一台 broker 岩机(因为副本数=2 )。若 Linkedln 公司把副本数提高到 3 ,那么就提供了 6 倍的数据冗余。这将是一笔很大的成本开销。但是,如果我们假设 Linkedln 公司使用的是JBOD方案。虽然目前 JBOD 有诸多限制,但其低廉的价格和超高的性价比的确是非常大的优势。另外通过一些简单的设置,JBOD 方案可以达到和 RAID 方案一样的数据冗余效果。比如说,如果使用 JBOD 并且设置副本数为 4,那么 Kafka 集群依然提供 4 倍的数据元余,但是这个方案中整个集群可以容忍最多 3 台 broker 岩机而不丢失数据。对比之前的 RAID 方案, JBOD 方案没有牺牲任何高可靠性或是增加硬件成本,同时还提升了整个集群的高可用性。
事实上, Linkedln 公司目前正在计划将整个 Kafka 集群从 RAID 10 迁移到 JBOD 上,只不过在整个过程中 JBOD 方案需要解决当前 Kafka 一些固有缺陷,比如:

  • 任意磁盘损坏都会导致 broker岩机一一普通磁盘损坏的概率是很大的,因此这个缺陷从某种程度上来说是致命的。不过社区正在改进这个问题,未来版本中只要为broker配置的多块磁盘中还有状态良好的磁盘, broker 就不会挂掉。
  • JBOD 的管理需要更加细粒度化一一一目前 Kafka 没有提供脚本或其他工具用于在不同磁盘问进行分区手动分配,但这是使用 JBOD 方案中必要的功能。
  • JBOD 也应该提供类似于负载均衡的功能一一 目前只是简单地依赖轮询的方式为新副本数据选择磁盘,后续需要提供更加丰富的策略。

结合 JBOD 和 RAID 幻、司的优劣对比以及 Linkedln 公司的实际案例,笔者认为:对于一般的公司或组织而言,选择 JBOD 方案的性价比更高 。 另外推荐用户为每个 broker 都配置多个日志路径,每个路径都独立挂载在不同的磁盘上,这使得多块物理磁盘磁头同时执行物理 I/O 写操作,可以极大地加速 Kafka 消息生产的速度。

最后关于磁盘的一个建议就是,尽量不要使用 NAS (Network Attached Storage )这样的网络存储设备 。 对比本地存储,人们总是以为 NAS 方案速度更快也更可靠,其实不然 。 NAS 一个很大的弊端在于,它们通常都运行在低端的硬件上,这就使得它们的性能很差 ,可能比一台笔记本电脑的硬盘强不了多少,表现为平均延时有很大的不稳定性,而几乎所有高端的 NAS设备厂商都售卖专有的硬件设备,因此成本的开销也是一个需要考虑的因素 。
综合以上所有的考量,笔者给硬盘规划的结论性总结如下 。

  • 追求性价比的公司可以考虑使用 JBOD 。
  • 使用机械硬盘完全可以满足 Kafka 集群的使用, SSD 更好 。

磁盘容量规划

Kafka 集群到底需要多大的磁盘容量?这又是一个非常经典的规划问题 。 如前所述, Kafka的每条消息都保存在实际的物理磁盘中,这些消息默认会被 broker 保存一段时间之后清除 。 这段时间是可以配置的,因此用户可以根据自身实际业务场景和存储需求来大致计算线上环境所需的磁盘容量。

让我们以一个实际的例子来看下应该如何思考这个问题 。 假设在你的业务场景中, clients每天会产生 1亿条消息,每条消息保存两份并保留一周的时间,平均一条消息的大小是 1KB,那么我们需要为 Kafka 规划多少磁盘空间呢?如果每天 1 亿条消息,那么每天产生的消息会占用 1 亿 × 2 ×1KB / 1000 / 1000 = 200GB 的磁盘空间 。 我们最好再额外预留 10%的磁盘空间用于其他数据文件(比如索引文件等)的存储,因此在这种使用场景下每天新发送的消息将占用210GB 左右的磁盘空间 。 因为还要保存一周的数据,所以整体的磁盘容量规划是 210 × 7 句
1.5TB 。 当然,这是无压缩的情况 。 如果在 clients 启用了消息压缩,我们可以预估一个平均的压缩比(比如 0.5),那么整体的磁盘容量就是 0.75TB 。
总之对于磁盘容量的规划和以下多个因素有关。

  • 新增消息数 。
  • 消息留存时间。
  • 平均消息大小 。
  • 副本数。
  • 是否启用压缩。

内存规划

乍一看似乎关于内存规划的讨论没什么必要,毕竟用户能做的就只是分配一个合适大小的内存,其他也没有可以调整的地方了。其实不然! Kafka 对于内存的使用可称作其设计亮点之一。 虽然在前面我们强调了 Kafka 大量依靠文件系统和磁盘来保存消息,但其实它还会对消息进行缓存,而这个消息缓存的地方就是内存,具体来说是操作系统的页缓存( page cache ) 。

Kafka 虽然会持久化每条消息,但其实这个工作都是底层的文件系统来完成的, Kafka 仅仅将消息写入 page cache 而己,之后将消息“冲昂。”到磁盘的任务完全交由操作系统来完成 。另外 consumer 在读取消息时也会首先尝试从该区域中查找,如果直接命中则完全不用执行耗时的物理 1/0 操作,从而提升了 consumer 的整体性能。不论是缓冲己发送消息还是待读取消息,操作系统都要先开辟一块内存区域用于存放接收的 Kafka 消息,因此这块内存区域大小的设置对于 Kafka 的性能就显得尤为关键了 。

有些令人惊讶的是, Kafka 对于 Java 堆内存的使用反而不是很多,因为 Kafka 中的消息通常都属于“朝生夕灭”的对象实例,可以很快地垃圾回收 CGC )。一般情况下, broker 所需的堆内存都不会超过 6GB 。所以对于一台 16GB 内存的机器而言,文件系统 page cache 的大小甚至可以达到 10~14GB!

除以上这些考量之外,用户还需要把 page cache 大小与实际线上环境中设置的日志段大小相比较(关于日志段的描述会在第 6 章中详细展开)。假设单个日志段文件大小设置为 10GB,那么你至少应该给予 page cache 10GB 以上的内存空间 。这样,待消费的消息有很大概率会保存在页缓存中,故 consumer 能够直接命中页缓存而无须执行缓慢的磁盘 1/0 读操作。

总之对于内存规划的建议如下。

  • 尽量分配更多的内存给操作系统的 page cache 。
  • 不要为 broker 设置过大的堆内存,最好不超过 6GB 。
  • page cache 大小至少要大于一个日志段的大小。

你可能感兴趣的:(大数据之Kafka)