Kafka权威指南
上QQ阅读APP看书,第一时间看更新

2.6 Kafka集群

单个Kafka服务器足以满足本地开发或POC要求,不过集群也有它的强大之处。使用集群最大的好处是可以跨服务器进行负载均衡,再则就是可以使用复制功能来避免因单点故障造成的数据丢失。在维护Kafka或底层系统时,使用集群可以确保为客户端提供高可用性。本节只是介绍如何配置Kafka集群,第6章将介绍更多关于数据复制的内容。

图2-2:一个简单的Kafka集群

2.6.1 需要多少个broker

一个Kafka集群需要多少个broker取决于以下几个因素。首先,需要多少磁盘空间来保留数据,以及单个broker有多少空间可用。如果整个集群需要保留10TB的数据,每个broker可以存储2TB,那么至少需要5个broker。如果启用了数据复制,那么至少还需要一倍的空间,不过这要取决于配置的复制系数是多少(将在第6章介绍)。也就是说,如果启用了数据复制,那么这个集群至少需要10个broker。

第二个要考虑的因素是集群处理请求的能力。这通常与网络接口处理客户端流量的能力有关,特别是当有多个消费者存在或者在数据保留期间流量发生波动(比如高峰时段的流量爆发)时。如果单个broker的网络接口在高峰时段可以达到80%的使用量,并且有两个消费者,那么消费者就无法保持峰值,除非有两个broker。如果集群启用了复制功能,则要把这个额外的消费者考虑在内。因磁盘吞吐量低和系统内存不足造成的性能问题,也可以通过扩展多个broker来解决。

2.6.2 broker配置

要把一个broker加入到集群里,只需要修改两个配置参数。首先,所有broker都必须配置相同的zookeeper.connect,该参数指定了用于保存元数据的Zookeeper群组和路径。其次,每个broker都必须为broker.id参数设置唯一的值。如果两个broker使用相同的broker.id,那么第二个broker就无法启动。在运行集群时,还可以配置其他一些参数,特别是那些用于控制数据复制的参数,这些将在后续的章节介绍。

2.6.3 操作系统调优

大部分Linux发行版默认的内核调优参数配置已经能够满足大多数应用程序的运行需求,不过还是可以通过调整一些参数来进一步提升Kafka的性能。这些参数主要与虚拟内存、网络子系统和用来存储日志片段的磁盘挂载点有关。这些参数一般配置在/etc/sysctl.conf文件里,不过在对内核参数进行调整时,最好参考操作系统的文档。

1.虚拟内存

一般来说,Linux的虚拟内存会根据系统的工作负荷进行自动调整。我们可以对交换分区的处理方式和内存脏页进行调整,从而让Kafka更好地处理工作负载。

对于大多数依赖吞吐量的应用程序来说,要尽量避免内存交换。内存页和磁盘之间的交换对Kafka各方面的性能都有重大影响。Kafka大量地使用系统页面缓存,如果虚拟内存被交换到磁盘,说明已经没有多余内存可以分配给页面缓存了。

一种避免内存交换的方法是不设置任何交换分区。内存交换不是必需的,不过它确实能够在系统发生灾难性错误时提供一些帮助。进行内存交换可以防止操作系统由于内存不足而突然终止进程。基于上述原因,建议把vm.swappiness参数的值设置得小一点,比如1。该参数指明了虚拟机的子系统将如何使用交换分区,而不是只把内存页从页面缓存里移除。要优先考虑减小页面缓存,而不是进行内存交换。

为什么不把vm.swappiness设为零

先前,人们建议尽量把vm.swapiness设为0,它意味着“除非发生内存溢出,否则不要进行内存交换”。直到Linux内核3.5-rc1版本发布,这个值的意义才发生了变化。这个变化被移植到其他的发行版上,包括Red Hat企业版内核2.6.32-303。在发生变化之后,0意味着“在任何情况下都不要发生交换”。所以现在建议把这个值设为1。

脏页会被冲刷到磁盘上,调整内核对脏页的处理方式可以让我们从中获益。Kafka依赖I/O性能为生产者提供快速的响应。这就是为什么日志片段一般要保存在快速磁盘上,不管是单个快速磁盘(如SSD)还是具有NVRAM缓存的磁盘子系统(如RAID)。这样一来,在后台刷新进程将脏页写入磁盘之前,可以减少脏页的数量,这个可以通过将vm.dirty background ratio设为小于10的值来实现。该值指的是系统内存的百分比,大部分情况下设为5就可以了。它不应该被设为0,因为那样会促使内核频繁地刷新页面,从而降低内核为底层设备的磁盘写入提供缓冲的能力。

通过设置vm.dirty ratio参数可以增加被内核进程刷新到磁盘之前的脏页数量,可以将它设为大于20的值(这也是系统内存的百分比)。这个值可设置的范围很广,60~80是个比较合理的区间。不过调整这个参数会带来一些风险,包括未刷新磁盘操作的数量和同步刷新引起的长时间I/O等待。如果该参数设置了较高的值,建议启用Kafka的复制功能,避免因系统崩溃造成数据丢失。

为了给这些参数设置合适的值,最好是在Kafka集群运行期间检查脏页的数量,不管是在生存环境还是模拟环境。可以在/proc/vmstat文件里查看当前脏页数量。

        # cat /proc/vmstat | egrep "dirty|writeback"
        nr dirty 3875
        nr writeback 29
        nr writeback temp 0
        #

2.磁盘

除了选择合适的磁盘硬件设备和使用RAID外,文件系统是影响性能的另一个重要因素。有很多种文件系统可供选择,不过对于本地文件系统来说,EXT4(第四代可扩展文件系统)和XFS最为常见。近来,XFS成为很多Linux发行版默认的文件系统,因为它只需要做少量调优就可以承担大部分的工作负荷,比EXT4具有更好的表现。EXT4也可以做得很好,但需要做更多的调优,存在较大的风险。其中就包括设置更长的提交间隔(默认是5),以便降低刷新的频率。EXT4还引入了块分配延迟,一旦系统崩溃,更容易造成数据丢失和文件系统毁坏。XFS也使用了分配延迟算法,不过比EXT4的要安全些。XFS为Kafka提供了更好的性能,除了由文件系统提供的自动调优之外,无需额外的调优。批量磁盘写入具有更高的效率,可以提升整体的I/O吞吐量。

不管使用哪一种文件系统来存储日志片段,最好要对挂载点的noatime参数进行合理的设置。文件元数据包含3个时间戳:创建时间(ctime)、最后修改时间(mtime)以及最后访问时间(atime)。默认情况下,每次文件被读取后都会更新atime,这会导致大量的磁盘写操作,而且atime属性的用处不大,除非某些应用程序想要知道某个文件在最近一次修改后有没有被访问过(这种情况可以使用realtime)。Kafka用不到该属性,所以完全可以把它禁用掉。为挂载点设置noatime参数可以防止更新atime,但不会影响ctime和mtime。

3.网络

默认情况下,系统内核没有针对快速的大流量网络传输进行优化,所以对于应用程序来说,一般需要对Linux系统的网络栈进行调优,以实现对大流量的支持。实际上,调整Kafka的网络配置与调整其他大部分Web服务器和网络应用程序的网络配置是一样的。首先可以对分配给socket读写缓冲区的内存大小作出调整,这样可以显著提升网络的传输性能。socket读写缓冲区对应的参数分别是net.core.wmem default和net.core.rmem default,合理的值是131072(也就是128KB)。读写缓冲区最大值对应的参数分别是net.core.wmem max和net.core.rmem max,合理的值是2097 152(也就是2MB)。要注意,最大值并不意味着每个socket一定要有这么大的缓冲空间,只是说在必要的情况下才会达到这个值。

除了设置socket外,还需要设置TCP socket的读写缓冲区,它们的参数分别是net.ipv4. tcp wmem和net.ipv4.tcp rmem。这些参数的值由3个整数组成,它们使用空格分隔,分别表示最小值、默认值和最大值。最大值不能大于net.core.wmem max和net.core.rmem max指定的大小。例如,“4096655362048000”表示最小值是4KB、默认值是64KB、最大值是2MB。根据Kafka服务器接收流量的实际情况,可能需要设置更高的最大值,为网络连接提供更大的缓冲空间。

还有其他一些有用的网络参数。例如,把net.ipv4.tcp window scaling设为1,启用TCP时间窗扩展,可以提升客户端传输数据的效率,传输的数据可以在服务器端进行缓冲。把net.ipv4.tcp max syn backlog设为比默认值1024更大的值,可以接受更多的并发连接。把net.core.netdev max backlog设为比默认值1000更大的值,有助于应对网络流量的爆发,特别是在使用千兆网络的情况下,允许更多的数据包排队等待内核处理。