mirror of
https://github.com/cheetahlou/CategoryResourceRepost.git
synced 2025-11-15 13:43:49 +08:00
mod
This commit is contained in:
91
极客时间专栏/Kafka核心技术与实战/Kafka的基本使用/06 | Kafka线上集群部署方案怎么做?.md
Normal file
91
极客时间专栏/Kafka核心技术与实战/Kafka的基本使用/06 | Kafka线上集群部署方案怎么做?.md
Normal file
@@ -0,0 +1,91 @@
|
||||
<audio id="audio" title="06 | Kafka线上集群部署方案怎么做?" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/1e/30/1e9f93f27a7f4dad4dd34fdcb1ae7830.mp3"></audio>
|
||||
|
||||
专栏前面几期内容,我分别从Kafka的定位、版本的变迁以及功能的演进等几个方面循序渐进地梳理了Apache Kafka的发展脉络。通过这些内容,我希望你能清晰地了解Kafka是用来做什么的,以及在实际生产环境中该如何选择Kafka版本,更快地帮助你入门Kafka。
|
||||
|
||||
现在我们就来看看在生产环境中的Kafka集群方案该怎么做。既然是集群,那必然就要有多个Kafka节点机器,因为只有单台机器构成的Kafka伪集群只能用于日常测试之用,根本无法满足实际的线上生产需求。而真正的线上环境需要仔细地考量各种因素,结合自身的业务需求而制定。下面我就分别从操作系统、磁盘、磁盘容量和带宽等方面来讨论一下。
|
||||
|
||||
## 操作系统
|
||||
|
||||
首先我们先看看要把Kafka安装到什么操作系统上。说起操作系统,可能你会问Kafka不是JVM系的大数据框架吗?Java又是跨平台的语言,把Kafka安装到不同的操作系统上会有什么区别吗?其实区别相当大!
|
||||
|
||||
的确,如你所知,Kafka由Scala语言和Java语言编写而成,编译之后的源代码就是普通的“.class”文件。本来部署到哪个操作系统应该都是一样的,但是不同操作系统的差异还是给Kafka集群带来了相当大的影响。目前常见的操作系统有3种:Linux、Windows和macOS。应该说部署在Linux上的生产环境是最多的,也有一些Kafka集群部署在Windows服务器上。Mac虽然也有macOS Server,但是我怀疑是否有人(特别是国内用户)真的把生产环境部署在Mac服务器上。
|
||||
|
||||
如果考虑操作系统与Kafka的适配性,Linux系统显然要比其他两个特别是Windows系统更加适合部署Kafka。虽然这个结论可能你不感到意外,但其中具体的原因你也一定要了解。主要是在下面这三个方面上,Linux的表现更胜一筹。
|
||||
|
||||
- I/O模型的使用
|
||||
- 数据网络传输效率
|
||||
- 社区支持度
|
||||
|
||||
我分别来解释一下,首先来看I/O模型。什么是I/O模型呢?你可以近似地认为I/O模型就是操作系统执行I/O指令的方法。
|
||||
|
||||
主流的I/O模型通常有5种类型:阻塞式I/O、非阻塞式I/O、I/O多路复用、信号驱动I/O和异步I/O。每种I/O模型都有各自典型的使用场景,比如Java中Socket对象的阻塞模式和非阻塞模式就对应于前两种模型;而Linux中的系统调用select函数就属于I/O多路复用模型;大名鼎鼎的epoll系统调用则介于第三种和第四种模型之间;至于第五种模型,其实很少有Linux系统支持,反而是Windows系统提供了一个叫IOCP线程模型属于这一种。
|
||||
|
||||
你不必详细了解每一种模型的实现细节,通常情况下我们认为后一种模型会比前一种模型要高级,比如epoll就比select要好,了解到这一程度应该足以应付我们下面的内容了。
|
||||
|
||||
说了这么多,I/O模型与Kafka的关系又是什么呢?实际上Kafka客户端底层使用了Java的selector,selector在Linux上的实现机制是epoll,而在Windows平台上的实现机制是select。**因此在这一点上将Kafka部署在Linux上是有优势的,因为能够获得更高效的I/O性能。**
|
||||
|
||||
其次是网络传输效率的差别。你知道的,Kafka生产和消费的消息都是通过网络传输的,而消息保存在哪里呢?肯定是磁盘。故Kafka需要在磁盘和网络间进行大量数据传输。如果你熟悉Linux,你肯定听过零拷贝(Zero Copy)技术,就是当数据在磁盘和网络进行传输时避免昂贵的内核态数据拷贝从而实现快速的数据传输。Linux平台实现了这样的零拷贝机制,但有些令人遗憾的是在Windows平台上必须要等到Java 8的60更新版本才能“享受”到这个福利。**一句话总结一下,在Linux部署Kafka能够享受到零拷贝技术所带来的快速数据传输特性。**
|
||||
|
||||
最后是社区的支持度。这一点虽然不是什么明显的差别,但如果不了解的话可能比前两个因素对你的影响更大。简单来说就是,社区目前对Windows平台上发现的Kafka Bug不做任何承诺。虽然口头上依然保证尽力去解决,但根据我的经验,Windows上的Bug一般是不会修复的。**因此,Windows平台上部署Kafka只适合于个人测试或用于功能验证,千万不要应用于生产环境。**
|
||||
|
||||
## 磁盘
|
||||
|
||||
如果问哪种资源对Kafka性能最重要,磁盘无疑是要排名靠前的。在对Kafka集群进行磁盘规划时经常面对的问题是,我应该选择普通的机械磁盘还是固态硬盘?前者成本低且容量大,但易损坏;后者性能优势大,不过单价高。我给出的建议是使用普通机械硬盘即可。
|
||||
|
||||
Kafka大量使用磁盘不假,可它使用的方式多是顺序读写操作,一定程度上规避了机械磁盘最大的劣势,即随机读写操作慢。从这一点上来说,使用SSD似乎并没有太大的性能优势,毕竟从性价比上来说,机械磁盘物美价廉,而它因易损坏而造成的可靠性差等缺陷,又由Kafka在软件层面提供机制来保证,故使用普通机械磁盘是很划算的。
|
||||
|
||||
关于磁盘选择另一个经常讨论的话题就是到底是否应该使用磁盘阵列(RAID)。使用RAID的两个主要优势在于:
|
||||
|
||||
- 提供冗余的磁盘存储空间
|
||||
- 提供负载均衡
|
||||
|
||||
以上两个优势对于任何一个分布式系统都很有吸引力。不过就Kafka而言,一方面Kafka自己实现了冗余机制来提供高可靠性;另一方面通过分区的概念,Kafka也能在软件层面自行实现负载均衡。如此说来RAID的优势就没有那么明显了。当然,我并不是说RAID不好,实际上依然有很多大厂确实是把Kafka底层的存储交由RAID的,只是目前Kafka在存储这方面提供了越来越便捷的高可靠性方案,因此在线上环境使用RAID似乎变得不是那么重要了。综合以上的考量,我给出的建议是:
|
||||
|
||||
- 追求性价比的公司可以不搭建RAID,使用普通磁盘组成存储空间即可。
|
||||
- 使用机械磁盘完全能够胜任Kafka线上环境。
|
||||
|
||||
## 磁盘容量
|
||||
|
||||
Kafka集群到底需要多大的存储空间?这是一个非常经典的规划问题。Kafka需要将消息保存在底层的磁盘上,这些消息默认会被保存一段时间然后自动被删除。虽然这段时间是可以配置的,但你应该如何结合自身业务场景和存储需求来规划Kafka集群的存储容量呢?
|
||||
|
||||
我举一个简单的例子来说明该如何思考这个问题。假设你所在公司有个业务每天需要向Kafka集群发送1亿条消息,每条消息保存两份以防止数据丢失,另外消息默认保存两周时间。现在假设消息的平均大小是1KB,那么你能说出你的Kafka集群需要为这个业务预留多少磁盘空间吗?
|
||||
|
||||
我们来计算一下:每天1亿条1KB大小的消息,保存两份且留存两周的时间,那么总的空间大小就等于1亿 * 1KB * 2 / 1000 / 1000 = 200GB。一般情况下Kafka集群除了消息数据还有其他类型的数据,比如索引数据等,故我们再为这些数据预留出10%的磁盘空间,因此总的存储容量就是220GB。既然要保存两周,那么整体容量即为220GB * 14,大约3TB左右。Kafka支持数据的压缩,假设压缩比是0.75,那么最后你需要规划的存储空间就是0.75 * 3 = 2.25TB。
|
||||
|
||||
总之在规划磁盘容量时你需要考虑下面这几个元素:
|
||||
|
||||
- 新增消息数
|
||||
- 消息留存时间
|
||||
- 平均消息大小
|
||||
- 备份数
|
||||
- 是否启用压缩
|
||||
|
||||
## 带宽
|
||||
|
||||
对于Kafka这种通过网络大量进行数据传输的框架而言,带宽特别容易成为瓶颈。事实上,在我接触的真实案例当中,带宽资源不足导致Kafka出现性能问题的比例至少占60%以上。如果你的环境中还涉及跨机房传输,那么情况可能就更糟了。
|
||||
|
||||
如果你不是超级土豪的话,我会认为你和我平时使用的都是普通的以太网络,带宽也主要有两种:1Gbps的千兆网络和10Gbps的万兆网络,特别是千兆网络应该是一般公司网络的标准配置了。下面我就以千兆网络举一个实际的例子,来说明一下如何进行带宽资源的规划。
|
||||
|
||||
与其说是带宽资源的规划,其实真正要规划的是所需的Kafka服务器的数量。假设你公司的机房环境是千兆网络,即1Gbps,现在你有个业务,其业务目标或SLA是在1小时内处理1TB的业务数据。那么问题来了,你到底需要多少台Kafka服务器来完成这个业务呢?
|
||||
|
||||
让我们来计算一下,由于带宽是1Gbps,即每秒处理1Gb的数据,假设每台Kafka服务器都是安装在专属的机器上,也就是说每台Kafka机器上没有混布其他服务,毕竟真实环境中不建议这么做。通常情况下你只能假设Kafka会用到70%的带宽资源,因为总要为其他应用或进程留一些资源。
|
||||
|
||||
根据实际使用经验,超过70%的阈值就有网络丢包的可能性了,故70%的设定是一个比较合理的值,也就是说单台Kafka服务器最多也就能使用大约700Mb的带宽资源。
|
||||
|
||||
稍等,这只是它能使用的最大带宽资源,你不能让Kafka服务器常规性使用这么多资源,故通常要再额外预留出2/3的资源,即单台服务器使用带宽700Mb / 3 ≈ 240Mbps。需要提示的是,这里的2/3其实是相当保守的,你可以结合你自己机器的使用情况酌情减少此值。
|
||||
|
||||
好了,有了240Mbps,我们就可以计算1小时内处理1TB数据所需的服务器数量了。根据这个目标,我们每秒需要处理2336Mb的数据,除以240,约等于10台服务器。如果消息还需要额外复制两份,那么总的服务器台数还要乘以3,即30台。
|
||||
|
||||
怎么样,还是很简单的吧。用这种方法评估线上环境的服务器台数是比较合理的,而且这个方法能够随着你业务需求的变化而动态调整。
|
||||
|
||||
## 小结
|
||||
|
||||
所谓“兵马未动,粮草先行”。与其盲目上马一套Kafka环境然后事后费力调整,不如在一开始就思考好实际场景下业务所需的集群环境。在考量部署方案时需要通盘考虑,不能仅从单个维度上进行评估。相信今天我们聊完之后,你对如何规划Kafka生产环境一定有了一个清晰的认识。现在我来总结一下今天的重点:
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/ba/04/bacf5700e4b145328f4d977575f28904.jpg" alt="">
|
||||
|
||||
## 开放讨论
|
||||
|
||||
对于今天我所讲的这套评估方法,你有什么问题吗?你还能想出什么改进的方法吗?
|
||||
|
||||
欢迎你写下自己的思考或疑问,我们一起讨论 。如果你觉得有所收获,也欢迎把文章分享给你的朋友。
|
||||
95
极客时间专栏/Kafka核心技术与实战/Kafka的基本使用/07 | 最最最重要的集群参数配置(上).md
Normal file
95
极客时间专栏/Kafka核心技术与实战/Kafka的基本使用/07 | 最最最重要的集群参数配置(上).md
Normal file
@@ -0,0 +1,95 @@
|
||||
<audio id="audio" title="07 | 最最最重要的集群参数配置(上)" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/d4/75/d42153c0ec57dc83f2dd10561d29f975.mp3"></audio>
|
||||
|
||||
你好,我是胡夕。今天我想和你聊聊最最最重要的Kafka集群配置。我这里用了3个“最”字并非哗众取宠,而是因为有些配置的重要性并未体现在官方文档中,并且从实际表现看,很多参数对系统的影响要比从文档上看更加明显,因此很有必要集中讨论一下。
|
||||
|
||||
我希望通过两期内容把这些重要的配置讲清楚。严格来说这些配置并不单单指Kafka服务器端的配置,其中既有Broker端参数,也有主题(后面我用我们更熟悉的Topic表示)级别的参数、JVM端参数和操作系统级别的参数。
|
||||
|
||||
需要你注意的是,这里所说的Broker端参数也被称为静态参数(Static Configs)。我会在专栏后面介绍与静态参数相对应的动态参数。所谓静态参数,是指你必须在Kafka的配置文件server.properties中进行设置的参数,不管你是新增、修改还是删除。同时,你必须重启Broker进程才能令它们生效。而主题级别参数的设置则有所不同,Kafka提供了专门的kafka-configs命令来修改它们。至于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/kafka1`和`zk1: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.{hours|minutes|ms}`:这是个“三兄弟”,都是控制一条消息数据被保存多长时间。从优先级上来说ms设置最高、minutes次之、hours最低。
|
||||
- `log.retention.bytes`:这是指定Broker为消息保存的总磁盘容量大小。
|
||||
- `message.max.bytes`:控制Broker能够接收的最大消息大小。
|
||||
|
||||
先说这个“三兄弟”,虽然ms设置有最高的优先级,但是通常情况下我们还是设置hours级别的多一些,比如`log.retention.hours=168`表示默认保存7天的数据,自动删除7天前的数据。很多公司把Kafka当作存储来使用,那么这个值就要相应地调大。
|
||||
|
||||
其次是这个`log.retention.bytes`。这个值默认是-1,表明你想在这台Broker上保存多少数据都可以,至少在容量方面Broker绝对为你开绿灯,不会做任何阻拦。这个参数真正发挥作用的场景其实是在云上构建多租户的Kafka集群:设想你要做一个云上的Kafka服务,每个租户只能使用100GB的磁盘空间,为了避免有个“恶意”租户使用过多的磁盘空间,设置这个参数就显得至关重要了。
|
||||
|
||||
最后说说`message.max.bytes`。实际上今天我和你说的重要参数都是指那些不能使用默认值的参数,这个参数也是一样,默认的1000012太少了,还不到1MB。实际场景中突破1MB的消息都是屡见不鲜的,因此在线上环境中设置一个比较大的值还是比较保险的做法。毕竟它只是一个标尺而已,仅仅衡量Broker能够处理的最大消息大小,即使设置大一点也不会耗费什么磁盘空间的。
|
||||
|
||||
## 小结
|
||||
|
||||
再次强调一下,今天我和你分享的所有参数都是那些要修改默认值的参数,因为它们的默认值不适合一般的生产环境。当然,我并不是说其他100多个参数就不重要。事实上,在专栏的后面我们还会陆续提到其他的一些参数,特别是那些和性能息息相关的参数。所以今天我提到的所有参数,我希望作为一个最佳实践给到你,可以有的放矢地帮助你规划和调整你的Kafka生产环境。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/d5/e7/d5248ba158a2283c095324a265d9f7e7.jpg" alt="">
|
||||
|
||||
## 开放讨论
|
||||
|
||||
除了今天我分享的这些参数,还有哪些参数是你认为比较重要而文档中没有提及的?你曾踩过哪些关于参数配置的“坑”?欢迎提出来与我和大家一起讨论。
|
||||
|
||||
欢迎你写下自己的思考或疑问,我们一起讨论。如果你觉得有所收获,也欢迎把文章分享给你的朋友。
|
||||
99
极客时间专栏/Kafka核心技术与实战/Kafka的基本使用/08 | 最最最重要的集群参数配置(下).md
Normal file
99
极客时间专栏/Kafka核心技术与实战/Kafka的基本使用/08 | 最最最重要的集群参数配置(下).md
Normal file
@@ -0,0 +1,99 @@
|
||||
<audio id="audio" title="08 | 最最最重要的集群参数配置(下)" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/3d/14/3d87d1ae291fe6be125304baaa3be014.mp3"></audio>
|
||||
|
||||
今天我们继续来聊那些重要的Kafka集群配置,下半部分主要是Topic级别参数、JVM参数以及操作系统参数的设置。
|
||||
|
||||
在上一期中,我们讨论了Broker端参数设置的一些法则,但其实Kafka也支持为不同的Topic设置不同的参数值。当前最新的2.2版本总共提供了大约25个Topic级别的参数,当然我们也不必全部了解它们的作用,这里我挑出了一些最关键的参数,你一定要把它们掌握清楚。除了Topic级别的参数,我今天还会给出一些重要的JVM参数和操作系统参数,正确设置这些参数是搭建高性能Kafka集群的关键因素。
|
||||
|
||||
## Topic级别参数
|
||||
|
||||
说起Topic级别的参数,你可能会有这样的疑问:如果同时设置了Topic级别参数和全局Broker参数,到底听谁的呢?哪个说了算呢?答案就是Topic级别参数会覆盖全局Broker参数的值,而每个Topic都能设置自己的参数值,这就是所谓的Topic级别参数。
|
||||
|
||||
举个例子说明一下,上一期我提到了消息数据的留存时间参数,在实际生产环境中,如果为所有Topic的数据都保存相当长的时间,这样做既不高效也无必要。更适当的做法是允许不同部门的Topic根据自身业务需要,设置自己的留存时间。如果只能设置全局Broker参数,那么势必要提取所有业务留存时间的最大值作为全局参数值,此时设置Topic级别参数把它覆盖,就是一个不错的选择。
|
||||
|
||||
下面我们依然按照用途分组的方式引出重要的Topic级别参数。从保存消息方面来考量的话,下面这组参数是非常重要的:
|
||||
|
||||
- `retention.ms`:规定了该Topic消息被保存的时长。默认是7天,即该Topic只保存最近7天的消息。一旦设置了这个值,它会覆盖掉Broker端的全局参数值。
|
||||
- `retention.bytes`:规定了要为该Topic预留多大的磁盘空间。和全局参数作用相似,这个值通常在多租户的Kafka集群中会有用武之地。当前默认值是-1,表示可以无限使用磁盘空间。
|
||||
|
||||
上面这些是从保存消息的维度来说的。如果从能处理的消息大小这个角度来看的话,有一个参数是必须要设置的,即`max.message.bytes`。它决定了Kafka Broker能够正常接收该Topic的最大消息大小。我知道目前在很多公司都把Kafka作为一个基础架构组件来运行,上面跑了很多的业务数据。如果在全局层面上,我们不好给出一个合适的最大消息值,那么不同业务部门能够自行设定这个Topic级别参数就显得非常必要了。在实际场景中,这种用法也确实是非常常见的。
|
||||
|
||||
好了,你要掌握的Topic级别的参数就这么几个。下面我来说说怎么设置Topic级别参数吧。其实说到这个事情,我是有点个人看法的:我本人不太赞同那种做一件事情开放给你很多种选择的设计方式,看上去好似给用户多种选择,但实际上只会增加用户的学习成本。特别是系统配置,如果你告诉我只能用一种办法来做,我会很努力地把它学会;反之,如果你告诉我说有两种方法甚至是多种方法都可以实现,那么我可能连学习任何一种方法的兴趣都没有了。Topic级别参数的设置就是这种情况,我们有两种方式可以设置:
|
||||
|
||||
- 创建Topic时进行设置
|
||||
- 修改Topic时设置
|
||||
|
||||
我们先来看看如何在创建Topic时设置这些参数。我用上面提到的`retention.ms`和`max.message.bytes`举例。设想你的部门需要将交易数据发送到Kafka进行处理,需要保存最近半年的交易数据,同时这些数据很大,通常都有几MB,但一般不会超过5MB。现在让我们用以下命令来创建Topic:
|
||||
|
||||
```
|
||||
bin/kafka-topics.sh --bootstrap-server localhost:9092 --create --topic transaction --partitions 1 --replication-factor 1 --config retention.ms=15552000000 --config max.message.bytes=5242880
|
||||
|
||||
```
|
||||
|
||||
我们只需要知道Kafka开放了`kafka-topics`命令供我们来创建Topic即可。对于上面这样一条命令,请注意结尾处的`--config`设置,我们就是在config后面指定了想要设置的Topic级别参数。
|
||||
|
||||
下面看看使用另一个自带的命令`kafka-configs`来修改Topic级别参数。假设我们现在要发送最大值是10MB的消息,该如何修改呢?命令如下:
|
||||
|
||||
```
|
||||
bin/kafka-configs.sh --zookeeper localhost:2181 --entity-type topics --entity-name transaction --alter --add-config max.message.bytes=10485760
|
||||
|
||||
```
|
||||
|
||||
总体来说,你只能使用这么两种方式来设置Topic级别参数。我个人的建议是,你最好始终坚持使用第二种方式来设置,并且在未来,Kafka社区很有可能统一使用`kafka-configs`脚本来调整Topic级别参数。
|
||||
|
||||
## JVM参数
|
||||
|
||||
我在专栏前面提到过,Kafka服务器端代码是用Scala语言编写的,但终归还是编译成Class文件在JVM上运行,因此JVM参数设置对于Kafka集群的重要性不言而喻。
|
||||
|
||||
首先我先说说Java版本,我个人极其不推荐将Kafka运行在Java 6或7的环境上。Java 6实在是太过陈旧了,没有理由不升级到更新版本。另外Kafka自2.0.0版本开始,已经正式摒弃对Java 7的支持了,所以有条件的话至少使用Java 8吧。
|
||||
|
||||
说到JVM端设置,堆大小这个参数至关重要。虽然在后面我们还会讨论如何调优Kafka性能的问题,但现在我想无脑给出一个通用的建议:将你的JVM堆大小设置成6GB吧,这是目前业界比较公认的一个合理值。我见过很多人就是使用默认的Heap Size来跑Kafka,说实话默认的1GB有点小,毕竟Kafka Broker在与客户端进行交互时会在JVM堆上创建大量的ByteBuffer实例,Heap Size不能太小。
|
||||
|
||||
JVM端配置的另一个重要参数就是垃圾回收器的设置,也就是平时常说的GC设置。如果你依然在使用Java 7,那么可以根据以下法则选择合适的垃圾回收器:
|
||||
|
||||
- 如果Broker所在机器的CPU资源非常充裕,建议使用CMS收集器。启用方法是指定`-XX:+UseCurrentMarkSweepGC`。
|
||||
- 否则,使用吞吐量收集器。开启方法是指定`-XX:+UseParallelGC`。
|
||||
|
||||
当然了,如果你在使用Java 8,那么可以手动设置使用G1收集器。在没有任何调优的情况下,G1表现得要比CMS出色,主要体现在更少的Full GC,需要调整的参数更少等,所以使用G1就好了。
|
||||
|
||||
现在我们确定好了要设置的JVM参数,我们该如何为Kafka进行设置呢?有些奇怪的是,这个问题居然在Kafka官网没有被提及。其实设置的方法也很简单,你只需要设置下面这两个环境变量即可:
|
||||
|
||||
- `KAFKA_HEAP_OPTS`:指定堆大小。
|
||||
- `KAFKA_JVM_PERFORMANCE_OPTS`:指定GC参数。
|
||||
|
||||
比如你可以这样启动Kafka Broker,即在启动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
|
||||
|
||||
```
|
||||
|
||||
## 操作系统参数
|
||||
|
||||
最后我们来聊聊Kafka集群通常都需要设置哪些操作系统参数。通常情况下,Kafka并不需要设置太多的OS参数,但有些因素最好还是关注一下,比如下面这几个:
|
||||
|
||||
- 文件描述符限制
|
||||
- 文件系统类型
|
||||
- Swappiness
|
||||
- 提交时间
|
||||
|
||||
首先是`ulimit -n`。我觉得任何一个Java项目最好都调整下这个值。实际上,文件描述符系统资源并不像我们想象的那样昂贵,你不用太担心调大此值会有什么不利的影响。通常情况下将它设置成一个超大的值是合理的做法,比如`ulimit -n 1000000`。还记得电影《让子弹飞》里的对话吗:“你和钱,谁对我更重要?都不重要,没有你对我很重要!”。这个参数也有点这么个意思。其实设置这个参数一点都不重要,但不设置的话后果很严重,比如你会经常看到“Too many open files”的错误。
|
||||
|
||||
其次是文件系统类型的选择。这里所说的文件系统指的是如ext3、ext4或XFS这样的日志型文件系统。根据官网的测试报告,XFS的性能要强于ext4,所以生产环境最好还是使用XFS。对了,最近有个Kafka使用ZFS的[数据报告](https://www.confluent.io/kafka-summit-sf18/kafka-on-zfs),貌似性能更加强劲,有条件的话不妨一试。
|
||||
|
||||
第三是swap的调优。网上很多文章都提到设置其为0,将swap完全禁掉以防止Kafka进程使用swap空间。我个人反倒觉得还是不要设置成0比较好,我们可以设置成一个较小的值。为什么呢?因为一旦设置成0,当物理内存耗尽时,操作系统会触发OOM killer这个组件,它会随机挑选一个进程然后kill掉,即根本不给用户任何的预警。但如果设置成一个比较小的值,当开始使用swap空间时,你至少能够观测到Broker性能开始出现急剧下降,从而给你进一步调优和诊断问题的时间。基于这个考虑,我个人建议将swappniess配置成一个接近0但不为0的值,比如1。
|
||||
|
||||
最后是提交时间或者说是Flush落盘时间。向Kafka发送数据并不是真要等数据被写入磁盘才会认为成功,而是只要数据被写入到操作系统的页缓存(Page Cache)上就可以了,随后操作系统根据LRU算法会定期将页缓存上的“脏”数据落盘到物理磁盘上。这个定期就是由提交时间来确定的,默认是5秒。一般情况下我们会认为这个时间太频繁了,可以适当地增加提交间隔来降低物理磁盘的写操作。当然你可能会有这样的疑问:如果在页缓存中的数据在写入到磁盘前机器宕机了,那岂不是数据就丢失了。的确,这种情况数据确实就丢失了,但鉴于Kafka在软件层面已经提供了多副本的冗余机制,因此这里稍微拉大提交间隔去换取性能还是一个合理的做法。
|
||||
|
||||
## 小结
|
||||
|
||||
今天我和你分享了关于Kafka集群设置的各类配置,包括Topic级别参数、JVM参数以及操作系统参数,连同上一篇一起构成了完整的Kafka参数配置列表。我希望这些最佳实践能够在你搭建Kafka集群时助你一臂之力,但切记配置因环境而异,一定要结合自身业务需要以及具体的测试来验证它们的有效性。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/da/87/da521c645594bcf0e4670a3d20937b87.jpg" alt="">
|
||||
|
||||
## 开放讨论
|
||||
|
||||
很多人争论Kafka不需要为Broker设置太大的堆内存,而应该尽可能地把内存留给页缓存使用。对此你是怎么看的?在你的实际使用中有哪些好的法则来评估Kafka对内存的使用呢?
|
||||
|
||||
欢迎写下你的思考和答案,我们一起讨论。如果你觉得有所收获,也欢迎把文章分享给你的朋友。
|
||||
Reference in New Issue
Block a user