持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第1天,点击查看活动详情
一、前言
建议总结如下:
| 因素 | 考量点 | 建议 |
|---|---|---|
| 操作系统 | 操作系统 I/O 模型 | Linux 系统上: 1. epoll 2. 零拷贝 |
| 磁盘 | 磁盘 I/O 性能 | 机械磁盘,不需要搭建 RAID。 生产可以上 SSD。 |
| 磁盘容量 | 根据消息数、留存时间预估磁盘容量 | 实际使用中建议预留 20%~30% 空间 |
| 带宽 | 根据实际带宽资源和业务 SLA 预估服务器数量 | 对于千兆网络,建议每台服务器按照 700 Mbps 来计算,避免大流量下的丢包 |
下面来详细解释下。
(1)操作系统
主要从下面三个方面比较,Linux 表现更胜一筹:
I/O模型的使用- 数据网络传输效率
- 社区支持度
- 主流的 I/O 模型通常有 5 种类型:阻塞式 I/O、非阻塞式 I/O、I/O 多路复用、信号驱动 I/O 和异步 I/O。
- 实际上
Kafka客户端底层使用了Java的selector,selector在Linux上的实现机制是epoll - 在
Windows平台上的实现机制是select
- 零拷贝(
Zero Copy)技术:就是当数据在磁盘和网络进行传输时避免昂贵的内核态数据拷贝从而实现快速的数据传输。
Linux平台实现了这样的零拷贝机制,但有些令人遗憾的是在Windows平台上必须要等到 Java 8 的 60 更新版本才能“享受”到这个福利。
- 社区的支持度:
Linux上迭代快- 社区目前对
Windows平台上发现的Kafka Bug不做任何承诺
(2)磁盘
磁盘使用 RAID 的两个主要优势在于:
-
提供冗余的磁盘存储空间
-
提供负载均衡
(3)磁盘空间
问题: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。
总之在规划磁盘容量时,需要考虑下面这几个元素:
- 新增消息数
- 消息留存时间
- 平均消息大小
- 备份数
- 是否启用压缩
(4)带宽
与其说是带宽资源的规划,其实真正要规划的是所需的
Kafka服务器的数量。
带宽也主要有两种:
1Gbps的千兆网络10Gbps的万兆网络
举个栗子:假设你公司的机房环境是千兆网络,即 1Gbps,现在你有个业务,其业务目标或 SLA 是在 1 小时内处理 1TB 的业务数据。
那么问题来了,你到底需要多少台 Kafka 服务器来完成这个业务呢?
计算一下:
-
带宽是
1Gbps,即每秒处理1Gb的数据。 -
假设
Kafka会用到 70% 的带宽资源,因为总要为其他应用或进程留一些资源。根据实际使用经验,超过 70% 的阈值就有网络丢包的可能性了,故 70% 的设定是一个比较合理的值。 也就是说单台
Kafka服务器最多也就能使用大约700Mb的带宽资源。 -
700Mb是最大带宽资源,但Kafka服务器常规性使用只用 1/3,通常会额外预留出 2/3 的资源,即:单台服务器使用带宽 700Mb / 3 ≈ 240Mbps。为什么常规下要预留 2/3? 因为:为
follower拉取留一些带宽。
目前为止,我们知道 Kafka 单台服务器使用 240Mbps,计算 1 小时内处理 1TB 数据所需的服务器数量了。
-
每秒需要处理多少数据:1(TB) * 8(b) * 1024(G) / 3600(s) = 2336Mb
-
需要多少台服务器:2336Mb / 240 = 10 台
-
因为需要额外复制 2 份,那么总的服务器台数 × 3,即 30 台。
那问题来了,为什么不说 CPU? CPU 应该配几核的?
-
因为:因为通常情况下
Kafka不太占用CPU,所以没有这方面的最佳实践出来。 -
有些情况下
Kafka的broker很耗CPU:server和client使用了不同的压缩算法server和client版本不一致造成消息格式转换broker端解压缩校验
-
相比带宽资源,
CPU通常都不是瓶颈。
二、重要参数
(1)Broker 端参数
Broker 存储信息:
-
log.dirs:指定Broker需要使用的若干个文件目录路径。在生产环境一定要为
log.dirs配置多个路径,逗号分割:/home/kafka1,/home/kafka2,/home/kafka3优点:- 提升读写性能:比起单块磁盘,多块物理磁盘同时读写数据有更高的吞吐量。
- 能够实现故障转移:即
Failover。这是Kafka 1.1版本新引入的强大功能。要知道在以前,只要Kafka Broker使用的任何一块磁盘挂掉了,整个Broker进程都会关闭。但是自 1.1 开始,这种情况被修正了,坏掉的磁盘上的数据会自动地转移到其他正常的磁盘上,而且Broker还能正常工作。若没有这种Failover的话,我们只能依靠RAID来提供保障。
-
log.dir:表示单个路径,补充上一个参数用的。
ZooKeeper 相关的设置:
负责协调管理并保存
Kafka集群的所有元数据信息,比如集群都有哪些Broker在运行、创建了哪些Topic,每个Topic都有多少分区以及这些分区的Leader副本都在哪些机器上等信息。
-
zookeeper.connect:例如,zk1:2181,zk2:2181,zk3:2181如果有两套
Kafka集群使用同一套ZooKeeper集群,就可以使用chroot。 两套集群的zookeeper.connect参数可以指定:zk1:2181,zk2:2181,zk3:2181/kafka1和zk1:2181,zk2:2181,zk3:2181/kafka2
Broker 连接相关的参数:
客户端程序或其他
Broker如何与该Broker进行通信的设置。
-
listeners:监听器,用于内网,其实就是告诉外部连接者要通过什么协议访问指定主机名和端口开放的Kafka服务。 -
advertised.listeners:用于外网,advertised的含义表示宣称的、公布的,就是说这组监听器是Broker用于对外发布的。 -
host.name/port:不用在乎,忘掉。
Topic 管理的参数:
auto.create.topics.enable:是否允许自动创建Topic,默认false。
建议最好设置成
false,即不允许自动创建Topic。
unclean.leader.election.enable:是否允许Unclean Leader选举,默认false。
设置成
false,坚决不能让那些落后太多的副本竞选Leader。
-
auto.leader.rebalance.enable:是否允许定期进行Leader选举,设置为false。是否允许
Kafka定期对一些Topic分区进行Leader重选举。
数据留存的参数:
log.retention.{hours|minutes|ms}:控制一条消息数据被保存多长时间。
比如
log.retention.hours=168表示默认保存 7 天的数据,自动删除 7 天前的数据。
log.retention.bytes:指定Broker为消息保存的总磁盘容量大小。
默认是 -1,表明你想在这台
Broker上保存多少数据都可以。
-
message.max.bytes:控制Broker能够接收的最大消息大小。默认的 1000012 太少了,即
976KB,还不到1MB。
(2)Topic 级别参数
如果同时设置了 Topic 级别参数和全局 Broker 参数,到底听谁的呢?
Topic级别参数会覆盖全局Broker参数的值,而每个Topic都能设置自己的参数值,这就是所谓的Topic级别参数。
-
retention.ms:规定了该Topic消息被保存的时长。默认是 7 天,即该 Topic 只保存最近 7 天的消息。一旦设置了这个值,它会覆盖掉
Broker端的全局参数值。 -
retention.bytes:规定了要为该Topic预留多大的磁盘空间。和全局参数作用相似,这个值通常在多租户的
Kafka集群中会有用武之地。当前默认值是-1,表示可以无限使用磁盘空间。
# 创建 Topic 时设置:
# 一般不会超过 5MB
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
# 修改 Topic 参数:
# 修改参数:发送最大值是 10MB 消息
bin/kafka-configs.sh --zookeeper localhost:2181 --entity-type topics --entity-name transaction --alter --add-config max.message.bytes=10485760
(3)JVM 参数
无脑给出一个通用的建议:将你的 JVM 堆大小设置成 6GB 吧,这是目前业界比较公认的一个合理值。
-
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
如果使用 Java8,垃圾回收器设置为:G1 收集器
-
在没有任何调优的情况下,
G1表现得要比CMS出色,主要体现在更少的Full GC。 -
需要调整的参数更少。
(4)操作系统参数
- 文件描述符限制:
ulimit -n 1000000
不设置,会常看到 “Too many open files”的错误。
# Kafka 会频繁创建和修改文件
# 计算公式:分区数量 × (分区总大小 / 日志段大小) × 3
# 举个栗子:
# 一个 broker 上有 100 个分区,每个分区大概 10G 的数据,日志段大小是默认 1G
# 计算:100 × 10(分区里的日志段文件数量) × 3 = 3000 个文件
-
文件系统类型:指
ext3、ext4或XFS日志文件系统根据官网的测试报告,
XFS的性能要强于ext4,所以生产环境最好还是使用XFS。 最近有个Kafka使用ZFS的数据报告。 -
Swappiness: 建议将swappniess配置成一个接近 0 但不为 0 的值,比如 1因为一旦设置成 0,当物理内存耗尽时,操作系统会触发
OOM killer这个组件,它会随机挑选一个进程然后kill掉,即根本不给用户任何的预警。 如果设置成一个比较小的值,当开始使用swap空间时,你至少能够观测到Broker性能开始出现急剧下降,从而给你进一步调优和诊断问题的时间。 -
提交时间:
flush落盘时间,默认 5 秒。
# 如何设置呢?
$ sysctl -a | grep dirty
vm.dirty_background_bytes = 0
vm.dirty_background_ratio = 10
vm.dirty_bytes = 0
vm.dirty_expire_centisecs = 3000 # os cache 里的数据在 3s 后会被刷入磁盘
vm.dirty_ratio = 20
vm.dirty_writeback_centisecs = 500 # 每隔 5s 唤醒一次刷盘的线程
vm.dirtytime_expire_seconds = 43200
# 可以设置大一些:1分钟 ~ 2分钟
# 特别大规模的企业和公司,如果可以接受机器宕机的时候,数据适当可以丢失一些,kafka 里的数据可以适当丢失一些,但是为了提升集群的吞吐量的话。