kafka运维

来源:互联网 发布:找出数组中重复的元素 编辑:程序博客网 时间:2024/06/10 05:42

Kafka 运维手册

 

 

 

 

 

 

 

 

编制

架构设计部 伍超

审核

 

批准

 


 

1.编写说明

以下是LinkedIn在生产中使用kafka集群的一些经验和信息,基于kafka0.9.0版本官方文档翻译。;

2.基本运维

这个章节将说明在运维kafka集群时最常见的操作,所提到的工具都位于kafka安装路径下的bin/目录,每个工具会打印详细使用信息如果没有指定参数。

2.1新增/删除topics

你可以手动新增或利用程序自动创建不存在的topics,如果是自动创建,你可以在broker配置文件server.properties里调整topic的相关默认参数。

通过工具新增或修改topics:

>bin/kafka-topics.sh --zookeeper zkhost:port --create --topic topicname --partitions 6 --replication-factor 3 --config x=y

参数replication-factor控制写入的信息会复制到多少个broker中。如果该参数设置为3,在可以正常访问数据的前提下将允许最多2个broker挂掉。通常建议使用2或3副本,这样可以提高系统的可用性。

参数partitions控制topic可以划分为多少个分区,每个分区只对应一个broker,分区的个数也影响着可以同时进行消费的消费者个数,每个分区只能被同一个消费者组内的其中一个消费者消费,但可以被不同消费者组内的消费者同时消费。

工具指定的配置参数在运行时会覆盖配置文件里对应的配置参数。

2.2修改topics

你可以通过工具修改一个topic的配置或分区数量。

新增分区数量:

>bin/kafka-topics.sh –zookeeper zkhost:port –alter –topic topicname –partitions 6

注意partition作用之一是划分数据,新增partitions不会改变集群中已经存在的数据的原有分区。也就是如果数据以hash(key)%number-of-partitions的方式分配,那新收到的数据可能会被分配到新的分区,但kafka不会自动重新分配已存在的数据。

新增配置

>bin/kafka-topics.sh –zookeeper zkhost:port –alter –topic topicname –config x=y

移除配置

>bin/kafka-topics.sh –zookeeper zkhost:port –alter –topic topicname –delete-config x

最后删除topic

>bin/kafka-topics.sh –zookeeper zkhost:port –delete –topic topicname

Topic删除选项默认是关闭的,通过设置broker配置参数delete.topic.enable=true来开启

Kafka目前还不支持削减topic的partitions的数目。

2.3优雅的关闭

Kafka集群会自动检测是否有broker宕机或服务挂了,并为相关的partitions选取新的leader。Kafka支持一种更优雅的关闭服务机制而不是强制杀死它。当服务优雅的关闭时会有两个好处:

1.       首先,它会同步所有的数据到磁盘而不需要再重启的时候去恢复数据,数据恢复会耗费更多的时间;

2.       其次,他会在服务关闭前将leader partitions迁移到其他副本。这样使leader partitions选取的更快从而减小了partition不可用的时间。

当服务停止而不是强制杀死服务的时候,自动同步数据到磁盘会自动进行,但是leader的迁移需要broker做如下配置:controlled.shutdown.enable=true。

注意,优雅关闭的前提是每个partition在其他broker上有存活的副本,也就是说副本数要大于1并最少有1个副本是存活的。

2.4均衡leader

当一个broker停止或异常挂了,都会导致该broker上的leaderpartition迁移到其他的副本上。这意味着当该broker重启后,它的partitions会全部成为follwer,意味着它不会被客户端读写,从而造成每个broker负载不均衡。

避免这种不均衡情况,kafka有个preferred 副本概念,如果一个partition的副本列表为{1,5,9},那么1将成为leader,意味它是副本列表的第一个。服务停止的broker在恢复之后,你可以使该broker原来的partition重新成为leader,通过以下命令可以实现:

>bin/kafka-preferred-replica-election.sh –zookeeper zkhost:port

如果你不想每次通过命令来做这种均衡,你可以通过配置kafka来自动完成这个过程,配置如下:auto.leader.rebalance.enable=true。由后台线程定期触发这种leader均衡操作。

2.5集群之间的数据复制

这里指的是不同集群之间的数据复制,而不是单个集群之间节点之间的数据复制,Kafka提供了这样一个工具来完成这种功能。这个工具从源集群读取数据并写入到目标集群当中,如下所示:


常见的使用场景比如将数据复制到另一个数据中心。你可以同时运行多个镜像实例来增加吞吐和提升容错能力(如果一个实例挂了,其它的实例会分担这份额外的负载)。

数据会从源集群的topics读取并写入到目的集群中同名的topic,事实上mirror maker就像kafka的消费者和生产者的结合。源集群和目的集群是完全独立的实体:它们有不同的partitions数目,并且offsets也不尽相同。因此,镜像集群不是一种容错机制。

这个例子展示怎么在两个集群之间复制一个topic:

>bin/kafka-mirror-maker.sh –consumer.conf consumer-1.properties –consumer.config consumer-2.properties –producer.conf producer.properties –whitelist topicname

       注意,我们通过--whitelist选项指定要复制topics列表,也可以通过--blacklist选项排除不想复制的topics,这两个选项都支持正则表达式。

       配置auto.create.topics.enable=true可以使复制集群能够自动创建topics并从源集群复制数据。


2.6查看消费者消费进度

有时,查看消费者的消费进度很有必要。Kafka提供了一个工具来完成这一工作:

>bin/kafka-consumer-offset-checker.sh –zookeeper zkhost:port –group groupname


2.7集群节点扩容

向kafka集群新增节点很容易,只要分配一个唯一brokerID并启动服务即可。但是这些新增的节点并不会自动被分配任何partitions,所以除非partitions被移动到节点上,否则它们不会处理任何工作直到有新的topics被创建。所以,通常在新增了节点到集群之中以后,我们会希望把已存在的数据迁移到这些节点上。

数据的迁移过程需要手动触发但自动完成,kafka会将新增的节点上的partitions作为follwer,follwer partitions会从leader partitions自动拉取数据,当新增节点上的partitions充分复制所有数据后会加入到ISR列表中。

Partition分配工具能够在brokers之间移动partitions。理想的partition分配是保证所有的broker拥有相同的partition数目和数据负载,这个partition分配工具不会自动分配partitions以使各broker负载均衡,使用者需要指出哪些topics或partitions需要移动。

Partition迁移工具能够以3种不同模式运行:

l  --generate:这种模式下,提供topics列表和brokers列表,会生成将指定的topics上的partitions分配到新的broker上的分配方案。这个选项仅仅生成一个参考的分配方案。

l  --execute:这种模式下,会执行指定的方案完成分配任务,通过--reassignment-json-file选项指定,可以自定义分配方案或通过--generate生成。

l  --verify:这种模式下,会检验执行—execute之后的分配状况

下面的例子,会将topicsfoo1,foo2上所有的paritions移动到新的broker5和6中,最终foo1和foo2上所有的partitions只存在于brokers5,6上。该工具需要编辑json文件来输入topics信息,例如:

>cat topic-to-move.json

{“topics”:[{“topic”: ”foo1”},

{“topic”: ”foo2”}],

 “version”:1

}

如果json文件已编辑好,可以先生成推荐分配方案:

>bin/kafka-reassign-partitions.sh –zookeeper zkhost:port –topics-to-move-json-file topics-to-move.json –broker-list “5,6” –generate

执行该命令之后会生成推荐分配策略,到目前为止,partition还没有开始迁移,仅仅只是告诉我们推荐的分配方案。最好将该分配方案保存下来,如果后面想回滚可以有依据。比如新的分配方案保存的json文件为expand-cluster-reassignment.json,执行该方案如下所示:

>bin/kafka-reassign-partitions.sh –zookeeper zkhost:port –reassignment-json-file expand-cluster-reassignment.json --execute

最后,--verify选项可以检测partition分配状态:

>bin/kafka-reassign-partitions.sh –zookeeper zkhost:port –reassignment-json-file expand-cluster-reassignment.json --verify

通常我们需要自定义分配策略,这就需要我们自己编辑json文件了。比如,我们想把foo1这个topic上的partition 0移动到broker5和6,把foo2的partition 1移动到broker2和3,自定义的分配方案可以如下编辑:

>cat custom-reassignment.json

{

“version”:1,

“partitions”:[{“topic”:”foo1”,”partition”:0,”replicas”:[5,6]},

 {“topic”:”foo2”,”partition”:1,“replicas”:[2,3]}]

}


2.8集群节点缩容

集群缩容同样也是使用kafka-reassign-partitions.sh工具进行。比如将broker1从集群移除:

首先,编辑分配方案,将broker1上的parition迁移分配到其他broker上;然后通过工具执行方案完成分配;分配确认成功后,再将broker1下线完成集群缩容。

2.9增加副本数

为现有的partition增加副本数很简单,只需在自定义分配方案中指定新增的副本,然后执行方案即可。

比如,将foo的partition 0从副本数为1增加到3,在增加副本之前,该partition的副本只存在于broker5上,现在我们将新增的副本分布在broker6和7上:

>cat increase-replication-factor.json

{

“version”:1,

“partitions”:[{“topic”:”foo”, “partition”:0, “replicas”:[5,6,7]}]

}


2.10设置配额

可以通过broker的配置文件为每个client-ids设置配额。默认情况下,每个client-id配额没有限制,以下设置可以为每个生产者和消费者设置配额10MB/sec:

quota.producer.default=10485760

quota.consumer.default=10485760

也可以为每个客户端设置自定义配额:

>bin/kafka-configs.sh –zookeeper zkhost:port –alter –add-config “producer_byte_rate=1024,consumer_byte_rate=2048” –entity-name clientA –entity-type clients

可以查看指定的客户端的配额信息:

>bin/kafka-configs.sh –zookeeper zkhost:port –describe –entity-name clientA –entity-type clients


3.Kafka配置

3.1客户端重要配置

生产者最重要的配置:

l  压缩方式

l  同步vs异步

l  Batch size批量传输大小(针对异步生产者)

消费者最重要的配置是fetch size.

3.2生产环境配置

这有linkedin其中一个生产环境上的配置:

#Replication configurations

num.replica.fetchers=4

replica.fetch.max.bytes=1048576

replica.fetch.wait.max.ms=500

replica.high.watermark.checkpoint.interval.ms=5000

replica.socket.timeout.ms=30000

replica.socket.receive.buffer.bytes=65536

replica.lag.time.max.ms=10000

 

controller.socket.timeout.ms=30000

controller.message.queue.size=10

 

#Log configuration

num.partitions=8

message.max.bytes=1000000

auto.create.topics.enable=true

log.index.interval.bytes=4096

log.index.size.max.bytes=10485760

log.retention.hours=168

log.flush.interval.ms=10000

log.flush.interval.messages=20000

log.flush.scheduler.interval.ms=2000

log.roll.hours=168

log.retention.check.interval.ms=300000

log.segment.bytes=1073741824

 

#ZK configuration

zookeeper.connection.timeout.ms=6000

zookeeper.sync.time.ms=2000

 

#Socket server configuration

num.io.threads=8

num.network.threads=8

socket.request.max.bytes=104857600

socket.receive.buffer.bytes=1048576

socket.send.buffer.bytes=1048576

queued.max.requests=16

fetch.purgatory.purge.interval.requests=100

producer.purgatory.purge.interval.requests=100

3.3Java版本

为了安全起见,推荐使用最新发布的JDK1.8,LinkedIn尝试使用JDK 1.8 u21测试,但这个版本的GC实现有一些问题,LinkedIn调优如下:

-Xmx6g –Xms6g –XX:MetaspaceSize=96m –XX:+UseG1GC –XX:MaxGCPauseMillis=20 –XX:InitiatingHeapOccupancyPercent=35 –XX:G1HeapRegionSize-16M –XX:MinMetaspaceFreeRatio=50 –XX:MaxMetaspaceFreeRatio=80

作为参考,这有LinkedIn最繁忙的集群的一些数据:60broker-50kpartitions(2副本)-800k msg/s in-300MB/s inbound,1GB/s+ outbound。这个调优看起来效果非常好,但是集群内所有的brokers有90%的GC暂停时间,大约21ms,并且yong GC少于每秒1次。

G1垃圾回收期的适用场景:

l  JVM占用内存较大(至少4G)

l  应用本身频繁申请、释放内存,进而产生大量内存碎片时

l  对于GC时间较为敏感的应用

4.硬件和系统

LinkedIn使用双4核心Intel Xeon,24GB内存的机器。

Kafka需要充足的内存去缓存活跃的读写内容。可以大约估算一下需要的内存,假设需要缓存30秒,那么用write_throughput*30来计算所需的内存大小。

磁盘吞吐非常重要,LinkedIn使用8*7200 rpmSATA磁盘。通常磁盘吞吐是性能瓶颈,盘越多越好。这取决于你如何配置刷盘策略,否则也无法在昂贵的磁盘中受益。如果配置的刷盘频率越高,那么配置更高RPM的SAS磁盘会更好。

4.1操作系统

Kafka在任何unix系统都能运行良好,在windows上运行的情况较少并且对windows平台支持的并不是很好。

也许并不需要做太多的OS级调整,但有两个配置非常重要,有助于性能的提高:

l  调大文件描述符数量

l  调大socket缓冲区大小

4.2磁盘和文件系统

推荐使用多磁盘来获取更好的吞吐性能,使用独立的磁盘来存储kafka的数据。如果配置了多个数据目录,partitions会轮流分布到各个数据目录,每个partition对应一个数据目录。如果数据没有均匀的到各个paritions会导致每个磁盘的负责不均衡。当然,也可以考虑RAID。

4.3数据flush

Kafka总是立即将所有数据写入文件系统,并可以通过配置控制操作系统缓存中的数据写磁盘的策略。可以通过时间和消息数量来控制刷盘的频率。

Kafka必须调用fsync来确保数据被刷入磁盘,当从故障的log segment恢复数据的时候会通过CRC校验每个消息的正确性并重建索引文件。注意,kafka的持久性不要求同步数据到磁盘,因为失败的节点总会从其他副本恢复数据。

推荐使用默认刷盘设置,即完全禁用fsync,依赖OS的刷盘策略和kafka的后台刷盘策略,在性能和可用性上都具有良好的保证。通常感觉副本提供的保证更胜于fsync刷盘策略,然而偏执狂仍然青睐在应用中使用fsync策略。

使用应用级别的刷盘策略的缺点是磁盘使用模式效率较低(它给操作系统减少了重新排序写操作的余地),并且可能引入延迟,因为fsync在大多linux文件系统中阻塞写入,而后台刷盘能进行更细粒度的page级的锁定。

在linux中,数据写入文件系统都是保存在页缓存中直到被写入磁盘(应用程序层面的fsync或操作系统自己的flush策略)。数据的刷盘是由一组叫做pdflush或“flusher threads”的后台线程来执行。当脏页占系统内存的比例超过阈值时,write系统调用会唤醒pdflush回写脏页,直到低于阈值。

使用页缓存的几个好处是:

l  IO调度器会批量合并小IO,以提升吞吐

l  IO调度器会对写入排序,较少磁盘头的转动,这样可以提升吞吐

l  可以充分利用机器的所有剩余内存

4.4Ext4注意事项

       Ext4也许不是kafka最佳文件系统,也许XFS文件系统能更好的处理fsync导致的阻塞情况,LinkedIn只试过Ext4。

       以下的设置回优化kafka在Ext4文件系统的性能:

n  data=writeback:Ext4默认data=ordered,会先记录metadata的journal,然后依次是data和metadata落盘;而data=writeback不强制要求这种写入顺序,仅要求metadata journal和metadata依次落盘,不确保data比metadata先落盘;由于kafka自身具有很强的数据恢复能力,所以不要求这种强制写入顺序,从而可以减少写入延迟。

n  禁用journaling:这回导致系统reboot时间变长,但是会减少一些额外的写入操作,从而提升写入性能。

n  commit=num_secs:调整ext4提交metadata的频率。设置小的值会减少crash时数据的丢失;设置大的值会提升吞吐。

n  nobh:当我们用data=writeback模式时,这会缓存磁盘block映射信息并将pages和事务关联起来以提供一些额外的顺序保证,从而弥补不足,同时拥有良好的性能和较低的延迟。

n  delalloc:延迟分配意味着文件系统避免分配块直到有物理写入才分配。Ext4分配一个大的extent来替代小的pages,这个特性有助于提升吞吐,但貌似会增加一些延迟。

5.zookeeper

5.1稳定版本

       在LinkedIn,我们运行的是Zookeeper3.3.*。3.3.3版本在临时接待删除和session过期方面有严重问题,并在生产中踩过坑,后来LinkedIn升级到了3.3.4版本并已经稳定的运行了一年。

5.2优化zookeeper

Ø  在硬件、网络等层面做到冗余,比如不要放到同一个机架,冗余电源和网络等等。

Ø  IO隔离,比如事务日志和数据分别写入到不同的磁盘上。

Ø  应用隔离,最好将zookeeper单独部署,减少其他应用的影响。

Ø  小心使用虚拟化,这会不必要的引入虚拟化层面的影响。

Ø  Zookeeper配置和监控:确保给予足够的堆空间,因为它是java的。监控方面JMX和4字命令很管用。

Ø  集群节点不要太多,最好是3-5个节点的集群。


原创粉丝点击