下载APP
关闭
讲堂
前端训练营
客户端下载
兑换中心
企业版
渠道合作
推荐作者

07 | 最最最重要的集群参数配置(上)

2019-06-18 胡夕
Kafka核心技术与实战
进入课程

讲述:胡夕

时长12:53大小11.80M

你好,我是胡夕。今天我想和你聊聊最最最重要的 Kafka 集群配置。我这里用了 3 个“最”字并非哗众取宠,而是因为有些配置的重要性并未体现在官方文档中,并且从实际表现看,很多参数对系统的影响要比从文档上看更加明显,因此很有必要集中讨论一下。

我希望通过两期内容把这些重要的配置讲清楚。严格来说这些配置并不单单指 Kafka 服务器端的配置,其中既有 Broker 端参数,也有主题(后面我用我们更熟悉的 Topic 表示)级别的参数、JVM 端参数和操作系统级别的参数。下面我先从 Broker 端参数说起。

Broker 端参数

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

首先 Broker 是需要配置存储信息的,即 Broker 使用哪些磁盘。那么针对存储信息的重要参数有以下这么几个:

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

这两个参数应该怎么设置呢?很简单,你只要设置log.dirs,即第一个参数就好了,不要设置log.dir。而且更重要的是,在线上生产环境中一定要为log.dirs配置多个路径,具体格式是一个 CSV 格式,也就是用逗号分隔的多个路径,比如/home/kafka1,/home/kafka2,/home/kafka3这样。如果有条件的话你最好保证这些目录挂载到不同的物理磁盘上。这样做有两个好处:

  • 提升读写性能:比起单块磁盘,多块物理磁盘同时读写数据有更高的吞吐量。
  • 能够实现故障转移:即 Failover。这是 Kafka 1.1 版本新引入的强大功能。要知道在以前,只要 Kafka Broker 使用的任何一块磁盘挂掉了,整个 Broker 进程都会关闭。但是自 1.1 开始,这种情况被修正了,坏掉的磁盘上的数据会自动地转移到其他正常的磁盘上,而且 Broker 还能正常工作。还记得上一期我们关于 Kafka 是否需要使用 RAID 的讨论吗?这个改进正是我们舍弃 RAID 方案的基础:没有这种 Failover 的话,我们只能依靠 RAID 来提供保障。

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

Kafka 与 ZooKeeper 相关的最重要的参数当属zookeeper.connect。这也是一个 CSV 格式的参数,比如我可以指定它的值为zk1:2181,zk2:2181,zk3:2181。2181 是 ZooKeeper 的默认端口。

现在问题来了,如果我让多个 Kafka 集群使用同一套 ZooKeeper 集群,那么这个参数应该怎么设置呢?这时候 chroot 就派上用场了。这个 chroot 是 ZooKeeper 的概念,类似于别名。

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

第三组参数是与 Broker 连接相关的,即客户端程序或其他 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这个自定义协议底层使用明文不加密传输数据。

至于三元组中的主机名和端口号则比较直观,不需要做过多解释。不过有个事情你还是要注意一下,经常有人会问主机名这个设置中我到底使用 IP 地址还是主机名。这里我给出统一的建议:最好全部使用主机名,即 Broker 端和 Client 端应用配置中全部填写主机名。 Broker 源代码中也使用的是主机名,如果你在某些地方使用了 IP 地址进行连接,可能会发生无法连接的问题。

第四组参数是关于 Topic 管理的。我来讲讲下面这三个参数:

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

我还是一个个说。

auto.create.topics.enable参数我建议最好设置成 false,即不允许自动创建 Topic。在我们的线上环境里面有很多名字稀奇古怪的 Topic,我想大概都是因为该参数被设置成了 true 的缘故。

你可能有这样的经历,要为名为 test 的 Topic 发送事件,但是不小心拼写错误了,把 test 写成了 tst,之后启动了生产者程序。恭喜你,一个名为 tst 的 Topic 就被自动创建了。

所以我一直相信好的运维应该防止这种情形的发生,特别是对于那些大公司而言,每个部门被分配的 Topic 应该由运维严格把控,决不能允许自行创建任何 Topic。

第二个参数unclean.leader.election.enable是关闭 Unclean Leader 选举的。何谓 Unclean?还记得 Kafka 有多个副本这件事吗?每个分区都有多个副本来提供高可用。在这些副本中只能有一个副本对外提供服务,即所谓的 Leader 副本。

那么问题来了,这些副本都有资格竞争 Leader 吗?显然不是,只有保存数据比较多的那些副本才有资格竞选,那些落后进度太多的副本没资格做这件事。

好了,现在出现这种情况了:假设那些保存数据比较多的副本都挂了怎么办?我们还要不要进行 Leader 选举了?此时这个参数就派上用场了。

如果设置成 false,那么就坚持之前的原则,坚决不能让那些落后太多的副本竞选 Leader。这样做的后果是这个分区就不可用了,因为没有 Leader 了。反之如果是 true,那么 Kafka 允许你从那些“跑得慢”的副本中选一个出来当 Leader。这样做的后果是数据有可能就丢失了,因为这些副本保存的数据本来就不全,当了 Leader 之后它本人就变得膨胀了,认为自己的数据才是权威的。

这个参数在最新版的 Kafka 中默认就是 false,本来不需要我特意提的,但是比较搞笑的是社区对这个参数的默认值来来回回改了好几版了,鉴于我不知道你用的是哪个版本的 Kafka,所以建议你还是显式地把它设置成 false 吧。

第三个参数auto.leader.rebalance.enable的影响貌似没什么人提,但其实对生产环境影响非常大。设置它的值为 true 表示允许 Kafka 定期地对一些 Topic 分区进行 Leader 重选举,当然这个重选举不是无脑进行的,它要满足一定的条件才会发生。严格来说它与上一个参数中 Leader 选举的最大不同在于,它不是选 Leader,而是换 Leader!比如 Leader A 一直表现得很好,但若auto.leader.rebalance.enable=true,那么有可能一段时间后 Leader A 就要被强行卸任换成 Leader B。

你要知道换一次 Leader 代价很高的,原本向 A 发送请求的所有客户端都要切换成向 B 发送请求,而且这种换 Leader 本质上没有任何性能收益,因此我建议你在生产环境中把这个参数设置成 false。

最后一组参数是数据留存方面的,即:

  • log.retention.{hour|minutes|ms}:这是个“三兄弟”,都是控制一条消息数据被保存多长时间。从优先级上来说 ms 设置最高、minutes 次之、hour 最低。
  • log.retention.bytes:这是指定 Broker 为消息保存的总磁盘容量大小。
  • message.max.bytes:控制 Broker 能够接收的最大消息大小。

先说这个“三兄弟”,虽然 ms 设置有最高的优先级,但是通常情况下我们还是设置 hour 级别的多一些,比如log.retention.hour=168表示默认保存 7 天的数据,自动删除 7 天前的数据。很多公司把 Kafka 当做存储来使用,那么这个值就要相应地调大。

其次是这个log.retention.bytes。这个值默认是 -1,表明你想在这台 Broker 上保存多少数据都可以,至少在容量方面 Broker 绝对为你开绿灯,不会做任何阻拦。这个参数真正发挥作用的场景其实是在云上构建多租户的 Kafka 集群:设想你要做一个云上的 Kafka 服务,每个租户只能使用 100GB 的磁盘空间,为了避免有个“恶意”租户使用过多的磁盘空间,设置这个参数就显得至关重要了。

最后说说message.max.bytes。实际上今天我和你说的重要参数都是指那些不能使用默认值的参数,这个参数也是一样,默认的 1000012 太少了,还不到 1MB。实际场景中突破 1MB 的消息都是屡见不鲜的,因此在线上环境中设置一个比较大的值还是比较保险的做法。毕竟它只是一个标尺而已,仅仅衡量 Broker 能够处理的最大消息大小,即使设置大一点也不会耗费什么磁盘空间的。

小结

再次强调一下,今天我和你分享的所有参数都是那些要修改默认值的参数,因为它们的默认值不适合一般的生产环境。当然,我并不是说其他 100 多个参数就不重要。事实上,在专栏的后面我们还会陆续提到其他的一些参数,特别是那些和性能息息相关的参数。所以今天我提到的所有参数,我希望作为一个最佳实践给到你,可以有的放矢地帮助你规划和调整你的 Kafka 生产环境。

开放讨论

除了今天我分享的这些参数,还有哪些参数是你认为比较重要而文档中没有提及的?你曾踩过哪些关于参数配置的“坑”?欢迎提出来与我和大家一起讨论。

欢迎你写下自己的思考或疑问,我们一起讨论。如果你觉得有所收获,也欢迎把文章分享给你的朋友。

© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
上一篇
06 | Kafka线上集群部署方案怎么做?
下一篇
08 | 最最最重要的集群参数配置(下)
 写留言

精选留言(34)

  • 草帽路飞
    2019-06-18
    老师 advertised.listeners 这个配置能否再解释一下。感觉配置了 listeners之后就不用配置这个了呀?

    作者回复: advertised.listeners主要是为外网访问用的。如果clients在内网环境访问Kafka不需要配置这个参数。

    常见的玩法是:你的Kafka Broker机器上配置了双网卡,一块网卡用于内网访问(即我们常说的内网IP);另一个块用于外网访问。那么你可以配置listeners为内网IP,advertised.listeners为外网IP。

    2
    11
  • QQ怪
    2019-06-18
    老师帮我们讲讲这个参数吧auto.offset.reset,我有时候删除一个topic时会导致offset异常,出现重复消费问题,不知道跟这个参数有没有关系??

    作者回复: 不太懂“删除topic后还出现重复消费”是什么意思?删完了还要继续消费它吗?

    当consumer启动后它会从Kafka读取它上次消费的位移。情况1: 如果 Kafka broker端没有保存这个位移值,那么consumer会看auto.offset.reset的脸色
    情况2:consumer拿到位移值开始消费,如果后面发现它要读取消息的位移在Kafka中不存在(可能对应的消息已经被删除了),那么它也会看auto.offset.reset的脸色
    情况3:除以上这两种情况之外consumer不会再顾忌auto.offset.reset的值

    怎么看auto.offset.reset的脸色呢?简单说就是earliest从头消息;latest从当前新位移处消费。

    2
  • kaiux
    2019-06-24
    👍,相当于把Kafka里面的一些坑预先告诉了我们。
    1
  • 不了峰
    2019-06-18
    请教老师
    gg.handler.kafkahandler.Mode = tx
    gg.handler.kafkahandler.Mode = op
    这两个的差别。我们遇到时 dml 数据会丢失的情况。用的是 op 。
    谢谢

    作者回复: 搜了一下,像是Oracle GoldenGate Kafka Adapter的参数。我没有用过,从文档中看这两者的区别是:当设置成op单个数据库表的变更(插入、更新、删除)会被当成一条Kafka消息发送;当设置成tx时,数据库事务所做的所有变更统一被封装进一条Kafka消息,并在事务提交后被发送。

    显然,后者有事务性的保障,至少有原子性方面的保证,不会丢失部分CDC数据。

    1
  • 你看起来很好吃
    2019-06-18
    '如果设置成 false,那么就坚持之前的原则,坚决不能让那些落后太多的副本竞选 Leader。'想问一下老师,每个partition的副本保存的数据不是应该和leader是一模一样的吗?为什么会有丢失的?

    作者回复: 它们是异步拉取消息的,必然有一个时间窗口导致它和leader中的数据是不一致的,或者说它是落后于leader的。

    1
  • mickle
    2019-06-18
    老师,对于磁盘坏掉以后转移到其他磁盘的机制,我有点疑问,如果已经坏掉,则不可读了,那么是不是只能从副本去转移了,如果从副本转移那就有可能会丢失部分最新的数据吧?

    作者回复: 不会啊,broker会重建副本,然后走正常的同步机制:从leader处拉取数据。

    1
  • 南辕北辙
    2019-06-18
    刚用的时候大一点的消息就有问题,后来知道是message.max.bytes,不过老师是不是打错单位了,记得是900多KB。今天干货很多

    作者回复: 感谢反馈,sorry,笔误了:(

    1
  • Geek_jacky
    2019-06-18
    老师好,如果磁盘坏掉了,这些数据是什么机制读取到其他磁盘上的呢?不是都坏了吗?不应该读取其他副本中的数据了吗?这个磁盘上的数据就算是丢失了吗?

    作者回复: Broker会在好的目录上重建副本。另外Kafka也提供了工具将某块磁盘上的数据直接搬移到另一个磁盘上,毕竟磁盘坏了也不是不能修好:)

    1
  • bunny
    2019-06-18
    后面会单独讲解producer,consumer相关配置参数吧?还有这个参数delete.topic.enable,胡老师有什么建议么?

    作者回复: 后面讲到producer和consumer会有涉及,但不会专门来讲,毕竟很多人反映单纯讲配置参数太枯燥了,还是结合具体的使用场景来讲比较好。另外建议delete.topic.enable保持默认值true就好,毕竟不能删除topic总显得不太方便。只是要注意权限设置即可,不可能 让任何人都能有删除topic的权限。

    1
  • Geek_986289
    2019-06-23
    老师,这里的log.retention.hour 和log.retention.bytes指的是单个log吧,感觉如果是所有log 的大小似乎还能理解,但是所有log 的hour 似乎有点说不通

    作者回复: 这些都是全局参数,针对broker上所有log而言的

  • ban
    2019-06-22
    kafka保存偏移量好像是在zookeeper,不是在kafka

    作者回复: 嗯嗯,这是老版本consumer的设计。目前老版本已经废弃了

  • ban
    2019-06-22
    请问老师,租户 语义化来讲的话是表示什么意思呢

    作者回复: 抱歉,没太懂“租户 语义化”。搜了一下全文,貌似没有这个词。。。

  • 风中花
    2019-06-21
    打卡,来来回回,反反复复 ,8篇文章看来好几次! 总结+复习 ! 希望有效果! 感觉缺少实践! 老师咱后续有带点实践吗?自己玩还是没有头绪! 所以期待后续的课

    作者回复: 嗯嗯,每个人对于实践的理解不一样。尽量还是找一个真实的项目去着手学习,否则很难深入进去:)

  • 明翼
    2019-06-21
    谢谢
  • 2019-06-20
    老师您好,通过ssl方式加密传输,如果ssl得证书过期了,会影响数据传输么?

    作者回复: 应该不会。可以试验一下~~

  • Geek_edc612
    2019-06-19
    胡老师您好,我对这两个参数有些疑问:
    (1)auto.leader.rebalance.enable 这个值设置为true,那么您说的定期重新选举,应该有个触发的条件吧?我刚才跟同事沟通过,他说是跟每台broker的leader数量有关,如果leader分布不均衡就会触发重新选举leader,但是感觉说的还是不够具体,您能给解答下吗,感谢
    (2)log.retention.bytes这个参数,您说的对于总磁盘容量来说,那我这样理解您看正确不(极端情况)---这个值我设置为100G,我机器有3个磁盘,每个磁盘大小1T,每个磁盘有不同topic的partition且,如果一个租户恶意写数据到自己的topic,造成某块磁盘的partition大小为100G,那么这台broker是不是所有topic都无法继续写入数据了?劳烦您解答下,感谢

    作者回复: 1. 的确是有个比例,要超过这个比例才会触发preferred leader选举。这个比例由broker端参数leader.imbalance.per.broker.percentage控制,默认是10%。举个例子,如果一个broker上有10个分区,有2个分区的leader不是preferred leader,那么就会触发

    2. 没太明白为什么写到100GB,broker就不能继续写入了?

    2
  • 李 P
    2019-06-19
    和本节无关,消息队列重复消费问题有什么太好的办法吗?我们现在的做法是把offset和消费后的计算结果一并保存在业务系统中,有没有更好的做法

    作者回复: 可以试试Kafka 0.11引入的事务

  • 风中花
    2019-06-19
    继续打卡,继续努力,不懂不装懂,不要脸的问老师。老师我觉得这个参数这里我个人感觉稍微有点跳跃,怎么说呢,也许是我不懂,不熟悉,我觉得参数本身的作用我总是觉得看到的少,不够了解,然后就是他的场景介绍。所以感到跳跃,是我的初学的原因吗,我看了好几次,也许我学完后面的,回头看,就不是这么一回事了。

    作者回复: 嗯嗯,最好把Kafka的quick start跑通了并熟悉里面的流程:)

  • henry
    2019-06-19
    老师,最近别人问我一个问题,假如现有集群已经有3个分区,动态添加两个分区, 原有的分区会迁移数据到新增的分区吗?

    作者回复: 不会。已有数据将一直“躺在”原有分区中。

  • Liam
    2019-06-19
    请问老师,坏掉的数据是怎么自动转移到其他磁盘上的呢?

    作者回复: 可能有点没说清楚。

    1. Broker自动在好的路径上重建副本,然后从leader同步;
    2. Kafka支持工具能够将某个路径上的数据拷贝到其他路径上