Apache Kafka-12-硬件与操作系统
硬件和操作系统
我们正在使用双四核24GB的Intel Xeon 机器。
您需要足够的内存来缓存活动的readers和writers。
您可以通过假设您希望缓存30秒,将您的内存需求计算为 write_throughput * 30
来进行内存需求的后期估计。
磁盘的吞吐量很重要。我们有8x7200转的SATA硬盘。
通常磁盘的吞吐量是瓶颈,磁盘是越多越好。
您能不能从更昂贵的磁盘中受益取决于你的刷新配置(如果您经常强制刷新,那么更高转速的SAS硬盘可能更好)。
OS
Kafka应该在任何Unix系统运行良好,并且已经在Linux和Solaris上进行了测试。
我们已经发现了在windows运行的一些问题,目前windows还不是一个理想的支持平台,虽然我们很乐意改变这个问题。
Kafka不需要太多的操作系统层面的调优,但是有两个潜在重要的操作系统级别的配置:
文件描述符限制: Kafka把文件描述符用于日志段和打开连接。如果一个broker上有许多分区,则考虑broker至少 (number_of_partitions)*(partition_size/segment_size)
个文件描述符来跟踪所有的日志段和broker所创建的连接。
我们推荐每一个broker一开始至少配置100000个文件描述符。
最大套接字缓冲区大小:可以增加以实现数据中心之间的高性能数据传输,如此处所述。
磁盘和文件系统
我们建议使用多个驱动器以获得良好的吞吐量,并且为了确保良好的延迟,不应该与应用程序日志或其他的操作系统文件系统活动共享用于Kafka数据的相同驱动器。
您可以将这些驱动器RAID成单个卷或格式,并且把每个驱动器挂载到它自己的目录。
Kafka的副本冗余功能可以由RAID或者应用程序级别提供,可以折衷选择实现。
如果您配置了多个数据目录,那么分区将被循环分配到数据目录。每个分区只属于一个数据目录,如果分区间的数据不均衡,则可能导致磁盘间的负载不均衡。
RAID可以更好地平衡磁盘之间的负载(尽管似乎并不总是如此),因为它在较低的级别上进行平衡负载。
RAID的主要缺点是通常会大幅度影响写入性能并且降低可用磁盘空间。
RAID的另一个潜在好处是能够容忍磁盘故障。
然而,我们的经验是,重建RAID阵列是I/O密集型操作以至于服务器不可用,所以这不提供太多的实际可用性改进。
应用程序 vs. OS 刷新管理
Kafka总是立即将所有数据写入文件系统,并支持配置刷新策略的功能,该策略控制何时将数据从OS缓存中强制刷新到磁盘上。
该刷新策略可以控制在一段时间之后或者在写入一定数量的消息之后把数据持久化到磁盘。
这里有几个可选配置项。
Kafka最总必须调用fsync指令才能知道数据已经被刷新。当从任何不被fsync所知的日志段崩溃中恢复时,Kafka将通过每个消息的CRC来检查其完整性,并且在启动时执行的恢复过程中会重建相应的偏移量索引文件。
请注意,Kafka中的持久性并不需要将数据同步到磁盘,因为失败的节点将始终从其副本中恢复。
我们建议使用完全禁用应用程序fsync的默认刷新设置。这意味着依靠操作系统和Kafka自己的后台完成的刷新操作。
这种设置对大多数用途是最好的选择:无需调整,巨大的吞吐量和延时,以及完全的恢复保证。
我们认为通过复制提供的保证比同步到本地磁盘更好,但是一些偏执的人仍然可能喜欢让OS,Kafka和应用程序级别的fsync策略都得到支持。
使用应用程序级别刷新设置的缺点是它的磁盘使用模式效率低下(它是操作系统在重新排序时没有什么回旋余地),并且在大多数Linux文件系统block中fsync写入文件时会引入延时,而后台刷新则会做更多粒度的页面级锁定。
通常你不需要对文件系统进行任何低级别的调整,但是,在接下来的几节中,我们也会介绍其中的一些内容,以防万一。
理解Linux操作系统刷新行为
在Linux中,写入文件系统的数据在pagecache中保存,直到必须写入磁盘(由于应用程序级别的fsync或操作系统自己的刷新策略)。
数据的刷新是通过一组叫做pdflush的后台线程来完成的(或者在2.6.32内核中的“flusher threads”)。
pdflush有一个可配置的策略,可以控制在缓存中可以维护多少脏数据,以及多久时间之前必须将数据写回到磁盘。
当Pdflush无法跟上数据写入的速率时,最终会导致写入过程阻塞发生写入延时来减慢数据的堆积。
您可以通过执行下面命令来查看当前OS内存使用状态
> cat /proc/meminfo
这些值的含义在上面的链接中有描述。
相对于进程内缓存,使用 pagecache 来存储将被写入到磁盘的数据有几个优势:
I/O 调度器将一批连续的小写入转换成为更大的物理写入,从而提高吞吐量。
I/O调度器将尝试重新排序写入操作,以尽量减少磁盘磁头的移动,从而提高吞吐量I/O
它会自动使用机器上的所有可用内存
文件系统的选择
Kafka在磁盘上使用常规的文件,不依赖于特定的文件系统。
然而,使用最多的两个文件系统是EXT4和XFS。
从历史上看,EXT4使用更多,但最近对XFS文件系统的改进已经表明它对Kafka的负载具有更好的性能,而且不会影响稳定性。
通过尝试各种文件系统的创建和挂载选项,在具有重要消息负载的集群上执行对比测试。
Kafka监测的主要指标是“Request Local Time”,它表示追加操作的时间。
XFS的本地时间更短(160ms比250ms +最好的EXT4配置),以及更低的平均等待时间。
随着磁盘性能变化,XFS的性能也表现出较小的波动。
一般文件系统注意事项
对于用于数据目录的任何文件系统,在Linux系统上,建议在挂载时使用以下选项:
noatime:此选项禁止在读取文件时更新文件的atime(上次访问时间)属性。
这可以消除大量的文件系统写入,特别是在引导consumer的情况下。 Kafka根本不依赖atime属性,因此禁用这个属性是安全的。
XFS 注意事项
XFS文件系统具有大量的自动调整功能,因此无需在文件系统创建时或挂载时对默认设置进行任何更改。
唯一值得考虑的调整参数是:
largeio: 这会影响统计调用报告的首选I/O大小。
虽然这可以允许在更大的磁盘写入时获得更高的性能,但是实际上它对性能的影响很小或者没有影响。
nobarrier: 对于具有 battery-backed cache 的底层设备,此选项可以通过禁用定期写入刷新来提供更多的性能。
但是,如果底层设备运行良好,则会向文件系统报告不需要刷新,此选项不起作用。
EXT4 注意事项
EXT4是Kafka数据目录的文件系统的一个可选择的选项,但是为了获得最高的性能需要调整几个挂载选项。
另外,这些选项在故障情况下通常是不安全的,并且会导致更多的数据丢失和损坏。
对于单个 broker 失败,这不是一个问题,因为可以擦除磁盘,并从集群重建副本。
但在诸如停电等多故障情况下,这可能意味着不容易恢复损坏的底层文件系统(数据)。
以下选项可以调整:
data=writeback:Ext4默认为data = ordered,这会导致某些写入操作上有很强的顺序性。Kafka不需要这样的顺序,因为它在所有未刷新的日志上进行非常偏执的数据恢复。此设置消除了排序约束,似乎显著减少了延迟。
Disabling journaling: Journaling 是一个折衷:在服务器崩溃之后,它会使重新启动更快,但会引入大量额外的锁定,从而增加写入性能的差异。那些不关心重启时间,想要减少写入延迟尖峰的主要来源,可以完全关闭Journaling。
commit=num_secs: 这调整了ext4向其元数据日志提交的频率。将其设置为较低的值可以减少崩溃期间未刷新数据的丢失。将其设置为更高的值则将提高吞吐量。
nobh: 当使用 data=writeback 模式时,此设置控制额外的排序保证。 Kafka应该是安全的,因为我们不依赖写入顺序并提高吞吐量和延迟。
delalloc: 延迟分配意味着文件系统避免分配任何 block 直到物理写入发生。这使得ext4可以在很大程度上分配连续区域而不是较小的页面,并有助于确保数据连续写入。这个功能非常适合吞吐量。它似乎涉及到文件系统中的一些锁定,这增加了一些延迟差异。
Operationalizing ZooKeeper
在操作上,我们有一下符合规范的ZooKeeper安装方式:
在物理/硬件/网络上的冗余:尽量不要把他们放在同一个机架上,合适的硬件配置(但不要过分),尽量保持电源,网络等。
一个典型的ZooKeeper集群有5或7台服务器,分别允许宕机2台和3台服务器。如果你想部署一个小型集群,3台服务器也可以部署,但是要记住,在这种情况下你只能宕机1台服务器。
I/O隔离:如果你有大量的写入操作流入,你几乎肯定会把事务日志放在一组特定的磁盘上。写入事物日志是同步的(但为了性能会分批写入),因此并发写入会明显影响性能。数据快照是异步落盘,因此通常可以与操作系统和消息日志文件共享磁盘性能。你可以配置dataLogDir参数单独为服务器配置磁盘组。
应用隔离:除非你真的了解其他应用的运行模式,否则不要和ZooKeeper安装在一起,最好是单独部署运行ZooKeeper(尽管ZooKeeper可以均衡的利用硬件资源)。
谨慎使用虚拟化:他的运行状况取决于你的集群架构,读写模式和SLA,即便是由虚拟化层引入的微小开销也可能造成ZooKeeper的中断,毕竟ZooKeeper对此十分敏感。
ZooKeeper配置: 他是java运行的,首先确保你给他分配足够的堆空间(我们通常配置3-5G,但这是根据我们现有数据实际情况来定的)。
不幸的是,我们没有一个好的固定公式来确定他的值,但是要记住分配个ZooKeeper的堆空间越大,快照也就越大,从而会影响快照的恢复时间。实际上,如果快照变得太大(几个G),那你能需要增加initlimit参数的值,以便为服务器提供足够的时间来恢复并加入集群。
监控:JMX和4个字母的命令(ZooKeeper提供的一系列命令,如:conf,cons,dump等)非常有用,他们在某些功能上重复了(这种情况下我们更喜欢4lw命令,他们似乎更容易预测情况,至少,他们和基础设施监控兼容性更好)
不要过度构建集群:大型集群,尤其是大量写入的情况下,意味着大量的集群内部通信(集群成员节点的写入和后续的仲裁更新),但是过小的将集群将承担不必要的风险。添加更多的服务器可以增加集群的读取能力。
总体来看,我们应尽量保持zookeeper尽可能小的处理负载(标准增长容量规划) 并尽可能的简单。与官方版本相比,我们尽量对配置和应用布局不做什么更改,尽可能保持官方原版。基于这些原因,我们倾向于跳过操作系统打包的版本。
因为为了有更好的表现,它倾向于把关注点放在可能“混乱”的标准系统层上。