1选择操作系统
kafka是一个java应用程序,可以运行在很多系统上Windows, MacOS, Linux, 等
一般都是Linux
2安装java环境
3安装zk
zk存储的是metadata
架构图如下
Kafka已经用稳定的zk的3.4.6版本进行了广泛的测试,它可以从apache.org的http://bit.ly/2sDWSgJ上下载。
单独的服务
tar -zxf zookeeper-3.4.6.tar.gz
mv zookeeper-3.4.6 /usr/local/zookeeper
mkdir -p /var/lib/zookeeper
cat > /usr/local/zookeeper/conf/zoo.cfg << EOF
tickTime=2000
dataDir=/var/lib/zookeeper
clientPort=2181
EOF
export JAVA_HOME=/usr/java/jdk1.8.0_51
/usr/local/zookeeper/bin/zkServer.sh start
JMX enabled by default
Using config: /usr/local/zookeeper/bin/…/conf/zoo.cfg
Starting zookeeper … STARTED
检测是否启动成功
telnet localhost 2181
Zookeeper cluster
集群部署一般选择奇数节点
它们必须有一个公共配置,列出所有服务器,并且每个服务器都需要在服务器的数据目录中指定ID号的myid文件。如果集成中服务器的主机名为zoo1.example.com、zoo2.example.com和zoo3.example.com,则配置文件可能如下所示:
tickTime=2000
dataDir=/var/lib/zookeeper
clientPort=2181
initLimit=20
syncLimit=5
server.1=zoo1.example.com:2888:3888
server.2=zoo2.example.com:2888:3888
server.3=zoo3.example.com:2888:3888
在此配置中,初始限制是允许追随者与领导者进行连接的时间量。同步限制值限制了追随者与引线的不同步程度。这两个值都是一个计时单位,这使得初始限制20 * 2000 ms,或40秒。该配置还列出了集成中的每个服务器。服务器在格式服务器中指定
server.X=hostname:peerPort:leaderPort
X服务器的ID号。这必须是一个整数,但它不需要是基于零的或顺序的。
peerPort
集成中的服务器之间相互通信的TCP端口。
leaderPort
选举主节点的端口
除了共享配置文件外,每个服务器还必须在数据Dir目录中有一个名为myid的文件。此文件必须包含服务器的ID号,它必须与配置文件相匹配。一旦这些步骤完成,服务器将启动并在一个集成中相互通信。
安装 Broker
tar -zxf kafka_2.11-0.9.0.1.tgz
mv kafka_2.11-0.9.0.1 /usr/local/kafka
mkdir /tmp/kafka-logs
export JAVA_HOME=/usr/java/jdk1.8.0_51
/usr/local/kafka/bin/kafka-server-start.sh -daemon
/usr/local/kafka/config/server.properties
Broker 配置
broker.id
每个Kafka代理都必须有一个整数标识符,该标识符是使用代理.id配置设置的。默认情况下,此整数被设置为0,但它可以是任何值。最重要的是,这个整数在一个卡夫卡集群中必须是唯一的。这个数字的选择是任意的,如果维护任务需要,它可以在代理之间移动。一个很好的指导原则是将此值设置为主机的内部内容,这样在执行维护时,将代理ID号映射到主机就不会很麻烦。例如,如果主机名包含唯一编号(如host1.example.com、host2.example.com等),这对经纪人来说是一个很好的选择。id值。
zookeeper.connect
案例
zookeeper.connect=hostname1:2181,hostname2:2181,hostname2:2181
log.dirs=/data01/kafka/log,/data02/kafka/log,/data03/kafka/log
如何选择分区数
您期望实现的针对该主题的吞吐量是多少?例如,您是期望每秒写100 KB还是每秒写1GB?
•当从单个分区进行消费时,您期望实现的最大吞吐量是什么?你会有,最多一个消费者阅读从一个分区,所以如果你知道你的慢消费者数据写入数据库和这个数据库从不处理超过50 MB每秒从每个线程写入,那么你知道你仅限于60MB吞吐量时消耗从一个分区。
•您可以通过同样的练习来估计单个分区的每个生产者的最大吞吐量,但由于生产者通常比消费者快得多,所以跳过这个方法通常是安全的。
•如果您是基于键向分区发送消息,那么以后添加分区可能非常具有挑战性,因此要根据您预期的未来使用情况来计算吞吐量,而不是根据最低租金使用率来计算吞吐量。
•考虑将在每个代理上放置的分区数量以及每个代理的可用磁盘空间和网络带宽。
•避免高估,因为每个分区都使用代理上的内存和其他资源,并将增加领导人选举的时间
考虑到所有这些,很明显您想要很多分区,但不是太多。如果您对主题的目标吞吐量和合并吞吐量的预期吞吐量有一些估计,那么您可以将目标吞吐量除以预期的合并吞吐量,并通过这种方式推导出分区的数量。所以,如果我想能够从一个主题中编写和读取1gb/秒,并且我知道每个消费者只能处理50个MB/s,那么我知道我至少需要20个分区。这样,我就可以让20个消费者阅读这个主题,并达到1GB/秒。如果您没有这些详细的信息,我们的经验表明,将磁盘上的分区的大小限制在每天保留时间的6 GB以下,通常会得到令人满意的结果。
log.retention.ms
卡夫卡保留消息的时间的最常见配置是按时间排列。在配置文件中使用log.retention.hours参数指定默认值,并将其设置为168小时或一周。然而,还允许使用其他两个参数,log.retention.minutes和log.retention.ms。这三个都指定了相同的配置——删除消息的时间——但建议使用的参数是log.retention.ms,因为如果指定了多个,较小的单元大小将优先。这将确保为log.retention.ms设置的值总是被使用的值。如果指定了多个,则较小的单位大小将优先。
log.retention.bytes
另一种使消息过期的方法是基于保留的消息的总字节数。此值使用log.retention.bytes参数进行设置,并在每个分区中进行应用。这意味着,如果您有一个包含8个分区的主题,并且log.retention.bytes被设置为1 GB,那么为该主题保留的数据量最多将为8 GB。请注意,所有的保留都是为单个分区执行的,而不是为主题执行的。这意味着,如果扩展了主题的分区数量,如果使用log.retention.bytes,保留率也会增加。
log.segment.bytes
前面提到的日志保留设置操作于日志段,而不是个别消息。当消息生成到Kafka代理时,它们被附加到分区的当前日志段。一旦日志段达到由log.segment.bytes参数指定的大小,默认为1 GB,日志段将被关闭,并打开一个新的日志段。关闭日志段后,可以考虑将其过期。较小的日志段大小意味着必须更频繁地关闭和分配文件,这降低了磁盘写入的总体效率。如果主题的产生率较低,那么调整日志段的大小可能很重要。例如,如果一个主题每天只接收100兆字节的消息,并且log.segment.bytes被设置为默认值,则需要10天来填充一个段。由于消息在关闭日志段之前就不能过期,所以如果将log.retention.ms设置为604800000(1周),那么在关闭的日志段过期之前,实际上最多将保留17天的消息。这是因为一旦日志段以当前10天的消息关闭,该日志段必须在根据时间策略过期之前保留7天(因为在段中的最后一条消息过期之前不能删除该段)。
log.segment.ms
另一种控制关闭日志段时间的方法是使用log.segment.ms参数,该参数指定关闭日志段的时间。与log.retention.bytes和log.retention.ms参数一样,log.segment.bytes和log.segment.ms并不是相互排斥的属性。Kafka将在达到大小限制或达到时间限制时关闭一个日志段,以先出现者为准。默认情况下,没有针对log.seg.ms的设置,这导致只按大小关闭日志段。
message.max.bytes
Kafka代理限制了可以生成的消息的最大大小,由message.max.bytes参数配置,默认为1000000,或1 MB。试图发送大于此值的消息的生产者将从代理收到一个错误,并且将不会接受该消息。与在代理上指定的所有字节大小一样,此配置处理压缩的消息大小,这意味着生产者可以发送比未压缩的此值大得多的消息,前提是它们压缩到配置的message.max.bytes大小下。增加允许的消息大小会对性能产生明显的性能影响。更大的消息将意味着处理处理网络连接和请求的代理线程在每个请求上工作时间更长。更大的内存大小也会增加磁盘写入的大小,这将影响I/O吞吐量。
云中的卡夫卡
Kafka的一个常见安装是在云计算环境中,比如亚马逊Web服务(AWS)。AWS提供了许多计算实例,每个实例都有不同的CPU、内存和磁盘组合,因此必须优先考虑Kafka的各种性能特性,以便选择要使用的正确实例配置。一个很好的起点是获得所需的数据保留量,然后是生产者所需的性能。如果需要非常低的延迟,则可能需要具有本地SSD存储的I/O优化实例。否则,短暂存储(如AWS弹性块存储)将足够了。一旦做出了这些决定,可用的CPU和内存选项将适合于性能。实际上,这意味着对于AWS,m4或r3实例类型都是一个常见的选择。m4实例将允许更大的保留期,但到磁盘的吞吐量将更少,因为它是在弹性块存储上。r3实例对于本地SSD驱动器将具有更好的吞吐量,但这些驱动器将限制可以保留的数据量。对于这两种情况,有必要升级到i2或d2实例类型,这些类型要贵得多
kafka集群
Brokers 数量
Kafka集群的适当大小是由几个因素决定的。首先要考虑的常见因素是保留消息需要多少磁盘容量,以及在单个代理上有多少存储可用。如果集群需要保留10 TB的数据,并且单个代理可以存储2 TB,那么最小的集群大小是5个代理。此外,使用复制将使存储需求至少增加100%的存储需求,这取决于所选择的复制系数(参见第6章)。这意味着配置了复制的同一集群现在需要包含至少10个兄弟成员。
需要考虑的因素是集群处理请求的能力。例如,网络接口的容量是多少,如果数据有多个使用者,或者在数据保留期间流量不一致(例如,高峰时段的流量突发),它们能否处理客户端流量。如果单个代理上的网络接口在峰值时被使用到80%的容量,并且有两个使用该数据的消费者,那么消费者将无法跟上峰值跟踪,除非有两个代理。如果在集群中使用复制,则这是必须考虑的数据的额外使用者。它还可以要求扩展到集群中的更多的代理,以处理由较低的磁盘吞吐量或可用的系统内存造成的性能问题。
Broker 配置
在代理配置中,只有两个要求,zookeeper.connect 配置必须相同
第二个要求是,集群中的所有代理程序都必须具有 broker.id参数的唯一值。
操作系统调优
虽然大多数Linux发行版都有一个针对内核调优参数的开箱即用配置,这对大多数应用程序都相当有效,但对于Kafka代理,也有一些更改可以提高性能。这些问题主要围绕着虚拟内存和网络子系统,以及用于存储日志段的磁盘装入点的具体问题。这些参数通常在/etc/sysctl.conf文件中配置,但是有关如何调整内核配置的具体详细信息,请参考Linux发行版的文档。
虚拟内存
虚拟内存通常,Linux虚拟内存系统会根据系统的工作负载自动调整。我们可以对交换空间的处理方式以及脏内存页面进行一些调整,以根据卡夫卡的工作负载调整它。与大多数应用程序一样——特别是涉及吞吐量的应用程序——最好避免(几乎)所有成本进行交换。将内存页面交换到磁盘所产生的成本将会对卡夫卡的内存运行的各个方面产生显著的影响。此外,Kafka大量使用系统页面缓存,如果虚拟机系统正在交换到磁盘,则没有为页面缓存分配足够的内存。
避免交换的一种方法是根本不配置任何交换空间。交换不是要求的,但如果系统发生了灾难性的事故,它确实提供了一个安全网。有交换可以防止操作系统由于内存不足而突然终止进程。因此,建议将vm.swappiness参数设置为一个非常低的值,例如1。该参数是虚拟机子系统使用交换空间而不是从页面缓存中删除页面的可能性的每个比例。最好是减少页面缓存的大小,而不是交换。
为什么不将切换状态设置为零呢?
以前,建议vm.swappiness总是将其设置为0。这个值过去的含义是“除非出现内存不足的情况,否则不要交换”。然而,随着Linux内核3.5-rc1版本的出现,这个值的含义发生了变化,并且这种变化被反向移植到许多发行版中,包括版本2.6.32-303版本中的红帽企业Linux内核。这将值0的含义改为“在任何情况下都不要交换”。因此,现在建议使用一个值为1。
调整内核处理必须刷新到磁盘的脏页的方式,还有一个好处。Kafka依赖于磁盘I/O性能来为生产者提供良好的响应时间。这也是日志段通常被放在快速磁盘上的原因,无论是具有快速响应时间的单个磁盘(例如SSD),还是具有用于缓存的显著NVRAM的磁盘子系统(例如RAID)。其结果是,在刷新后台进程开始将脏页写入磁盘之前,允许的脏页数量可以减少。这是通过将=vm.dirty_background_ratio值低于默认值10来实现的。该值是系统内存总量的百分比,在许多情况下,将此值设置为5是近似的。但是,此设置不应该设置为零,因为这将导致内核不断地刷新页面这将消除Kaffa内核缓冲磁盘写以对抗底层设备性能中的临时峰值的能力。在内核强制同步操作将它们刷新到磁盘之前允许的脏页总数也可以通过更改vm.dirty_ratio的值来增加,增加到默认的20以上(也占系统内存总数的百分比)。这个设置有很多可能的值范围,但在60到80之间是一个合理的数字。此设置确实引入了少量的风险,包括未刷新的磁盘活动的数量,以及如果强制同步刷新,可能会出现长时间的I/O暂停。如果选择了更高的vm.dirty_ratio设置,则强烈建议在Kaffa集群中使用复制,以防止系统故障。在为这些参数选择值时,明智的做法是查看Kafka集群在负载下运行时,无论是在生产中还是在模拟中。当前的脏页数可以通过检查/proc/vmstat文件来确定:
cat /proc/vmstat | egrep “dirty|writeback”
nr_dirty 3875
nr_writeback 29
nr_writeback_temp 0
磁盘
除了选择磁盘设备硬件以及使用RAID的配置之外,用于此磁盘的文件系统的选择可能会对性能产生第二大的影响。有许多不同的文件系统可用,但是本地文件系统的最主要选择是EXT4(第四个扩展文件系统)或扩展文件系统(XFS)。最近,XFS已经成为许多Linux发行版的默认文件系统,这是有充分理由的——它在大多数工作负载中优于EXT4,所需的调优小于EXT4。EXT4可以表现良好,但它需要使用被认为不太安全的调优参数。这包括将手术时间间隔设置为比默认的时间5更长,以减少冲洗的次数。EXT4还引入了块的延迟分配 在系统故障的情况下,数据丢失和文件系统损坏的可能性更大。XFS文件系统也使用了延迟分配算法,但它通常比EXT4使用的算法更安全。XFS对于Kafka的工作负载也有更好的性能,而不需要在文件系统执行的自动调优之外进行调优。在批处理磁盘写入时,它也更有效,所有这些结合在一起可以提供更好的整体I/O吞吐量。
无论为保存日志段的装载选择了哪个文件系统,都建议为装载点设置节点装载选项。文件元数据包含三个时间戳创建时间(ctime)、最后一次修改的时间(mtime)和最后一次访问时间(时间)。默认情况下,每次读取文件时都会更新自动模式。这将产生大量的磁盘写操作。atime属性通常被认为没有什么用处,除非应用程序需要知道一个文件在上次修改后是否已经被访问过(在这种情况下可以使用实时选项)。卡夫卡根本不使用它,所以禁用它是安全的。在挂载上设置噪声将防止这些时间戳更新发生,但不会影响ctime和mtime属性的正确处理。
网络
对于任何产生大量网络流量的应用程序,调整Linux网络堆栈的默认调优是常见的,因为内核对于大型高速数据传输没有默认调优。事实上,为Kaffa建议的更改与为大多数web服务器和其他网络应用程序建议的更改相同。第一个调整是更改为每个套接字的发送和接收缓冲区分配的默认内存量和最大内存量。这将显著提高大型传输的性能。每个套接字的发送和接收缓冲区默认大小的相关参数为net.core.wmem_default和net.core.rmem_default,这些参数的合理设置为131072,或128 KiB。发送和接收缓冲区的最大大小参数为net.core.wmem_max和net.core.rmem_max,合理的设置为2097152,或2 MiB。请记住,最大大小并不表示每个套接字都有这么多的缓冲空间;它只在需要的时候允许这么多。
除了套接字设置外,TCP套接字的发送和接收缓冲区大小也必须分别使用net.ipv4.tcp_wmem和net.ipv4.tcp_rmem参数进行设置。它们使用三个空格分隔的整数进行设置,分别指定最小值、默认值和最大大小。最大大小不能大于使用net.core.wmem_max和net.core.rmem_max为所有套接字指定的值。这些参数的一个示例设置是“4096 65536 2048000”,这是一个4 KiB最小值,64 KiB默认值和2 MiB最大缓冲区。基于Kafka代理的实际工作负载,您可能希望增加最大大小,以允许网络连接的缓冲。
还有其他几个有用的网络调优参数。通过将net.ipv4.tcp_window_scaling设置为1来启用TCP窗口缩放,将允许客户端更有效地传输数据,并允许在代理端缓冲这些数据。将net.ipv4.tcp_max_syn_backlog的值增加到默认值1024以上,将允许接受更多的同时连接。将net.core.netdev_max_backlog的值增加到大于默认值1000可以帮助处理网络流量的爆发,特别是在使用多千兆网络连接速度时,通过允许更多的数据包排队等待内核来处理它们。
生产问题一旦您准备好将Kafka环境从测试中转移到生产操作中,还需要考虑的一些事情将有助于建立可靠的消息传递服务。
垃圾收集器选项
为应用程序调优Java垃圾收集选项一直是一门艺术的东西,需要关于应用程序如何使用内存、大量观察、试验和错误的详细信息。值得庆幸的是,随着Java 7和垃圾优先(或G1)垃圾收集器的引入,这种情况发生了改变。G1被设计为自动调整不同的工作负载,并在应用程序的生命周期内为垃圾收集提供连续的暂停时间。它还通过将堆分割为较小的区域,而不在每次暂停中收集整个堆,轻松地处理大的堆大小。
G1在正常操作中以最小的配置完成所有这些。G1有两个配置选项,用于调整其性能:
MaxGCPauseMillis
这个选项指定了每个垃圾收集周期的首选暂停时间。它不是一个固定的最大值-如果需要,g1可以并且将超过这个时间。此值默认为200毫秒。这意味着G1将尝试安排GC周期的频率,以及在每个周期中收集的区域的数量,这样每个周期将需要大约200 ms。
InitiatingHeapOccupancyPercent
初始化堆占用百分比此选项指定在G1将开始收集周期之前可能使用的总堆的百分比。默认值为45。这意味着G1只有在45%的堆被使用之后才会开始一个收集周期。这包括新(伊甸园)和旧区域的使用。
Kafka代理利用堆内存和创建垃圾对象的方式相当有效,因此可以将这些选项设置得更低。本节中提供的GC调优选项适用于具有64 GB内存的服务器,并在5GB堆中运行Kafka。对于Maxgcp ms,此代理可以配置为20 ms。“初始化堆占用率百分比”的值被设置为35,这将导致垃圾收集的运行时间略早于使用默认值。
Kafka的开始脚本不使用G1收集器,而是默认使用并行的新标记和并发标记和扫描垃圾收集。通过环境变量进行更改。使用本章前面的开始命令,对其进行如下修改
export JAVA_HOME=/usr/java/jdk1.8.0_51
export KAFKA_JVM_PERFORMANCE_OPTS="-server -XX:+UseG1GC
-XX:MaxGCPauseMillis=20 -XX:InitiatingHeapOccupancyPercent=35
-XX:+DisableExplicitGC -Djava.awt.headless=true"
/usr/local/kafka/bin/kafka-server-start.sh -daemon
/usr/local/kafka/config/server.properties
数据配置
对于开发系统,数据中心中的Kafka代理的物理位置并不那么重要,因为如果集群在短时间内部分或完全不可用,就不会产生那么严重的影响。然而,在服务生产流量时,停机意味着美元损失,无论是由于用户失去服务还是对用户正在做什么的遥测损失。这是在Kafka集群中配置复制变得关键时,这也是考虑数据中心机架中代理的物理位置也很重要的时候。如果在部署Kafka之前没有解决,那么可能需要昂贵的维护来移动服务器。
Kafka代理在向代理分配新的分区时没有机架意识。这意味着它不能考虑两个代理可能位于同一物理机架中,或者位于同一可用性区域(如果运行在AWS等云服务中运行),因此可以很容易地将分区的所有副本分配给共享相同机架中相同电源和网络连接的代理。如果该机架出现故障,这些分区将脱机,客户端无法访问。此外,由于不干净的领导人选举,它可能导致额外的恢复数据丢失
最佳实践是将集群中的每个Kafka代理安装在不同的机架上,或者至少不共享电力和网络等基础设施服务的单点故障点。这通常意味着至少部署将运行具有双电源连接(到两个不同的电路)和双网络交换机(通过服务器本身的连接接口进行无缝故障切换)的代理的服务器。即使有双重连接,让经纪人坐在完全便宜的货架上也有好处。有时需要对机柜或机柜进行物理维护(例如移动服务器,或重新布线电源连接)。