【Kafka系列】生产级集群参数配置

目录

1. 概述

2. Bocker 端参数

2.1 存储相关配置

2.2 Zookeeper 相关配置

2.3 Brocker 连接相关配置

2.4 Topic 管理相关配置

2.5 数据存留 相关配置

3. Topic 级别参数

4. JVM 参数

5. 操作系统参数

6. 小结


【Kafka系列】生产级集群参数配置_第1张图片

1. 概述

本文将从 Bocker 端参数、Topic 级别参数、JVM 端参数、操作系统级别参数分别介绍 Kafka 集群参数应该怎么配置。文中提到的这些参数都很重要,请读者仔细阅读理解,因为有些配置并未体现在官方文档中,并且从实际表现看,很多参数对系统的影响要比从文档上看更加明显。

2. Bocker 端参数

目前 Kafka Broker 提供了近 200 个参数,这其中绝大部分参数都不用你亲自过问。当谈及这些参数的用法时,网上的文章多是罗列出一些常见的参数然后一个一个地给出它们的定义。我们换个方法,按照大的用途类别一组一组的介绍它们,希望可以更有针对性,也更方便你记忆。

2.1 存储相关配置

Broker 是需要配置存储信息的,即 Brocker 使用哪些磁盘。

  • log.dirs:这是非常重要的参数,指定了 Broker 需要使用的若干个文件目录路径。要知道这个参数是没有默认值的,这说明什么?这说明它必须由你亲自指定。
  • log.dir:注意这是 dir,结尾没有 s,说明它只能表示单个路径,它是补充上一个参数用的。

一般只配置 log.dirs,不要设置log.dir。在线上生产环境中一定要为log.dirs配置多个路径,比如 /home/kafka1,/home/kafka2,/home/kafka3 这样。如果有条件的话你最好保证这些目录挂载到不同的物理磁盘上。这样做有两个好处:

  • 提升读写性能:比起单块磁盘,多块物理磁盘同时读写数据有更高的吞吐量。
  • 能够实现故障转移:即 Failover。不过这是 Kafka 1.1 版本才新引入的功能。如果低于该版本,我们就只能依靠 RAID 来提供保障。

2.2 Zookeeper 相关配置

首先 ZooKeeper 是做什么的呢?它是一个分布式协调框架,负责协调管理并保存 Kafka 集群的所有元数据信息,比如集群都有哪些 Broker 在运行、创建了哪些 Topic,每个 Topic 都有多少分区以及这些分区的 Leader 副本都在哪些机器上等信息。

  • zookeeper.connect:配置 Zookeeper的连接信息,比如可以指定值为 zk1:2181,zk2:2181,zk3:2181。2818 是 Zookeeper 额默认端口。

如果想要多个 Kafka 集群使用同一套 Zookeeper 集群,可以配置 chroot 参数。这个 chroot 是 ZooKeeper 的概念,类似于别名。

如果你有两套 Kafka 集群,假设分别叫它们 kafka1 和 kafka2,那么两套集群的zookeeper.connect 参数可以这样指定:zk1:2181,zk2:2181,zk3:2181/kafka1和zk1:2181,zk2:2181,zk3:2181/kafka2。切记 chroot 只需要写一次,而且是加到最后的。

2.3 Brocker 连接相关配置

即客户端程序或其他 Broker 如何与该 Broker 进行通信的设置。

listeners:学名叫监听器,其实就是告诉外部连接者要通过什么协议访问指定主机名和端口开放的 Kafka 服务。

advertised.listeners:和 listeners 相比多了个 advertised。Advertised 的含义表示宣称的、公布的,就是说这组监听器是 Broker 用于对外发布的。

host.name/port:列出这两个参数就是想说你把它们忘掉吧,压根不要为它们指定值,毕竟都是过期的参数了。

具体说说监听器的概念,从构成上来说,它是若干个逗号分隔的三元组,每个三元组的格式为<协议名称,主机名,端口号>

  • 协议名称:可以是标准的协议名字,比如 PLAINTEXT 表示明文传输、SSL 表示使用 SSL 或 TLS 加密传输等;也可以是你自己定义的协议名字,比如CONTROLLER: //localhost:9092。一旦你自己定义了协议名称,你必须还要指定listener.security.protocol.map参数告诉这个协议底层使用了哪种安全协议,比如指定listener.security.protocol.map=CONTROLLER:PLAINTEXT表示CONTROLLER这个自定义协议底层使用明文不加密传输数据。
  • 主机名:建议最好全部使用主机名,即 Broker 端和 Client 端应用配置中全部填写主机名。使用 IP 地址可能会发生无法连接的问题。
  • 端口号:默认端口号 9092。

2.4 Topic 管理相关配置

  • auto.create.topics.enable:是否允许自动创建 Topic,建议设置成 false。
  • unclean.leader.election.enable:是否允许 Unclean Leader 选举,建议设置成 false。
  • auto.leader.rebalance.enable:是否允许定期进行 Leader 选举,建议设置成 false。

auto.create.topics.enable 参数建议最好设置成 false,即不允许自动创建 Topic。

unclean.leader.election.enable 是关闭 Unclean Leader 选举的。何谓 Unclean?还记得 Kafka 有多个副本这件事吗?每个分区都有多个副本来提供高可用。在这些副本中只能有一个副本对外提供服务,即所谓的 Leader 副本。那么问题来了,这些副本都有资格竞争 Leader 吗?显然不是,只有保存数据比较多的那些副本才有资格竞选,那些落后进度太多的副本没资格做这件事。设置成 false,坚决不能让那些落后太多的副本竞选 Leader。后果是这个分区就不可用了,因为没有 Leader 了。反之如果是 true,那么 Kafka 允许落后太多副本竞选 Leader。后果是数据有可能丢失。这个参数在最新版的 Kafka 中默认就是 false。

auto.leader.rebalance.enable 对生产环境影响非常大。如果设置为 true 表示允许 Kafka 定期地在满足一定条件的情况下对一些 Topic 分区进行 Leader 重选举,你要知道换一次 Leader 代价是很高的。

2.5 数据存留 相关配置

log.retention.{hours|minutes|ms}:这是个“三兄弟”,都是控制一条消息数据被保存多长时间。从优先级上来说 ms 设置最高、minutes 次之、hours 最低。

log.retention.bytes:这是指定 Broker 为消息保存的总磁盘容量大小。

log.segment.bytes:单个日志文件的大小,默认 1073741824。

message.max.bytes:控制 Broker 能够接收的最大消息大小。

基于日志大小的清理策略计算公式:

sum(单个 partition 内的 log 大小) - log.segment.bytes > log.retention.bytes,满足条件则开始按照时间顺序标记删除。

3. Topic 级别参数

说起 Topic 级别的参数,你可能会有这样的疑问:如果同时设置了 Topic 级别参数和全局 Broker 参数,到底听谁的呢?哪个说了算呢?答案就是 Topic 级别参数会覆盖全局 Broker 参数的值,而每个 Topic 都能设置自己的参数值,这就是所谓的 Topic 级别参数。

从保存消息方面来考量的话,下面这组参数是非常重要的:

retention.ms:规定了该 Topic 消息被保存的时长。默认是 7 天,即该 Topic 只保存最近 7 天的消息。一旦设置了这个值,它会覆盖掉 Broker 端的全局参数值。

retention.bytes:规定了要为该 Topic 预留多大的磁盘空间。和全局参数作用相似,这个值通常在多租户的 Kafka 集群中会有用武之地。当前默认值是 -1,表示可以无限使用磁盘空间。

max.message.bytes:它决定了 Kafka Broker 能够正常接收该 Topic 的最大消息大小。

4. JVM 参数

Kafka 服务器端代码是用 Scala 语言编写的,但终归还是编译成 Class 文件在 JVM 上运行,因此 JVM 参数设置对于 Kafka 集群的重要性不言而喻。

Kafka 自 2.0.0 版本开始,已经正式摒弃对 Java 7 的支持了,所以有条件的话至少使用 Java 8 吧。

说到JVM 端设置,堆大小这个参数至关重要。这里无脑给出通用的建议:将你的 JVM 堆大小设置成 6GB 吧,这是目前业界比较公认的一个合理值。我见过很多人就是使用默认的 Heap Size 来跑 Kafka,说实话默认的 1GB 有点小,毕竟 Kafka Broker 在与客户端进行交互时会在 JVM 堆上创建大量的 ByteBuffer 实例,Heap Size 不能太小。

JVM 端配置的另一个重要参数就是垃圾回收器的设置,也就是平时常说的 GC 设置。如果你在使用 Java 8,那么可以手动设置使用 G1 收集器。在没有任何调优的情况下,G1 表现得要比 CMS 出色,主要体现在更少的 Full GC,需要调整的参数更少等,所以使用 G1 就好了。

设置的方法只需要设置下面两个环境变量即可:

  • KAFKA_HEAP_OPTS:指定堆大小。
  • KAFKA_JVM_PERFORMANCE_OPTS:指定 GC 参数。

启动 Kafka Broker前,先设置上这两个环境变量:

$> export KAFKA_HEAP_OPTS=--Xms6g  --Xmx6g
$> export KAFKA_JVM_PERFORMANCE_OPTS= -server -XX:+UseG1GC -XX:MaxGCPauseMillis=20 -XX:InitiatingHeapOccupancyPercent=35 -XX:+ExplicitGCInvokesConcurrent -Djava.awt.headless=true
$> bin/kafka-server-start.sh config/server.properties

5. 操作系统参数

最后我们来聊聊 Kafka 集群通常都需要设置哪些操作系统参数。通常情况下,Kafka 并不需要设置太多的 OS 参数,但有些因素最好还是关注一下,比如下面这几个:

  • 文件描述符限制
  • 文件系统类型
  • Swappiness
  • 提交时间

首先是ulimit -n。我觉得任何一个 Java 项目最好都调整下这个值。实际上,文件描述符系统资源并不像我们想象的那样昂贵,你不用太担心调大此值会有什么不利的影响。通常情况下将它设置成一个超大的值是合理的做法,比如ulimit -n 1000000。还记得电影《让子弹飞》里的对话吗:“你和钱,谁对我更重要?都不重要,没有你对我很重要!”。这个参数也有点这么个意思。其实设置这个参数一点都不重要,但不设置的话后果很严重,比如你会经常看到“Too many open files”的错误。

其次是文件系统类型的选择。这里所说的文件系统指的是如 ext3、ext4 或 XFS 这样的日志型文件系统。根据官网的测试报告,XFS 的性能要强于 ext4,所以生产环境最好还是使用 XFS。

第三是 swap 的调优。网上很多文章都提到设置其为 0,将 swap 完全禁掉以防止 Kafka 进程使用 swap 空间。我个人反倒觉得还是不要设置成 0 比较好,我们可以设置成一个较小的值。为什么呢?因为一旦设置成 0,当物理内存耗尽时,操作系统会触发 OOM killer 这个组件,它会随机挑选一个进程然后 kill 掉,即根本不给用户任何的预警。但如果设置成一个比较小的值,当开始使用 swap 空间时,你至少能够观测到 Broker 性能开始出现急剧下降,从而给你进一步调优和诊断问题的时间。基于这个考虑,我个人建议将 swappniess 配置成一个接近 0 但不为 0 的值,比如 1。

最后是提交时间或者说是 Flush 落盘时间。向 Kafka 发送数据并不是真要等数据被写入磁盘才会认为成功,而是只要数据被写入到操作系统的页缓存(Page Cache)上就可以了,随后操作系统根据 LRU 算法会定期将页缓存上的“脏”数据落盘到物理磁盘上。这个定期就是由提交时间来确定的,默认是 5 秒。一般情况下我们会认为这个时间太频繁了,可以适当地增加提交间隔来降低物理磁盘的写操作。当然你可能会有这样的疑问:如果在页缓存中的数据在写入到磁盘前机器宕机了,那岂不是数据就丢失了。的确,这种情况数据确实就丢失了,但鉴于 Kafka 在软件层面已经提供了多副本的冗余机制,因此这里稍微拉大提交间隔去换取性能还是一个合理的做法。

6. 小结

以上介绍了关于 Kafka 集群设置的各类配置,包括 Broker端参数、Topic 级别参数、JVM 参数以及操作系统参数。我希望这些最佳实践能够在你搭建 Kafka 集群时助你一臂之力,但切记配置因环境而异,一定要结合自身业务需要以及具体的测试来验证它们的有效性。

你可能感兴趣的:(kafka,kafka,分布式)