OS
1、IO调优: (只执行 关闭 swap)
2、socket buffer size(暂时使用默认)
cat /proc/sys/net/core/wmem_max
cat /proc/sys/net/core/rmem_max
/proc/sys/net/ipv4/tcp_rmem
/proc/sys/net/ipv4/tcp_wmem
3、增加 ulimit
为避免Kafka报 Too many open files 错误,需要增加最大文件打开数:
cd /etc/security/limits.d/
vim kafka.conf
# 编辑
* hard nofile 100000
* soft nofile 100000
# 保存
为了提高Kafka的性能,/etc/sysctl.conf文件需增加以下配置(暂时不做配置):
vm.swappiness=1//物理内存使用率超过99%时,使用swap分区,这样避免使用swap分区,否则影响性能。
vm.dirty_background_ratio=5//脏页达到系统内存5%时,后台刷新页面
vm.dirty_ratio=70//脏页占到系统内存70%时,刷新进磁盘
vm.max_map_count=262144//允许一个进程在虚拟内存区域的最大数量
net.core.wmen_default=131072//socket写缓冲区
net.core.rmem_default=131072//socket读缓冲区
net.core.wmen_max=2097152//socket最大写缓冲区
net.core.rmem_max=2097152//socket最大读缓冲区
zookeeper
只需要修改 clientPort、dataDir 和 dataLogDir 即可。
tickTime=2000 最小时间单元,单位毫秒
initLimit=10 Follower启动,与Leader同步的时间倍数
syncLimit=5 Leader与Follower之间进行心跳检测的最大延时时间倍数
dataDir=$dir1/zookeeper 快照文件存储路径
dataLogDir=$dir2/zookeeper 事务日志文件存储路径
maxClientCnxns=60 单个IP与zk的最大连接数
clientPort=12999
JVM
一般kafka自身的jvm堆内存,分配个10G左右就够了,剩下的内存全部都留给os cache
cd /usr/local/kafka_2.13-2.7.0/bin
vim kafka-server-start.sh
# KAFKA_HEAP_OPTS,默认都是 1G
if [ "x$KAFKA_HEAP_OPTS" = "x" ]; then
export KAFKA_HEAP_OPTS="-Xmx8G -Xms8G"
fi
cd /usr/local/kafka_2.13-2.7.0/bin
vim kafka-server-start.sh
# Generic jvm settings you want to add
if [ -z "$KAFKA_OPTS" ]; then
KAFKA_OPTS="-Xmx8g -Xms8g -XX:MetaspaceSize=128m -XX:+UseG1GC -XX:MaxGCPauseMillis=20 -XX:InitiatingHeapOccupancyPercent=35 -XX:G1HeapRegionSize=16M -XX:MinMetaspaceFreeRatio=50
-XX:MaxMetaspaceFreeRatio=85"
fi
Broker
num.network,threads=9
num.io.threads=32
log.retention.hours=168
delete.topic.enable=true
message.max.bytes=7340032
zookeeper.connection.timeout.ms=18000
auto.create.topics.enable=false
一个 consumer group 中的consumer数与Partition 数一样,一个 consumer group 可以订阅一个或多个 topic。
Producer
buffer.memory 67108864
batch.size 10485760
max.request.size=6291456
linger.ms 100
max.request.size
Compression.type
acks 1
retries 10
retry.backoff.ms 500 (重试间隔)
batch.size:该值设置越大,吞吐越大,但延迟也会越大;
linger.ms:表示 batch 的超时时间,该值越大,吞吐越大、但延迟也会越大;
Consumer
组内所有消费者协调一起订阅一个主题的所有分区。每个分区只能由一个消费者组内的一个消费者实例消费。
理想情况下,消费者实例应该等于该消费者组订阅的主题分区总数。一般不推荐设置大于总分区数的消费者实例。
消费组的重平衡,主要发生于以下情景:
组成员发生变更,如新的消费者实例加入,或者离开
订阅主题数发生变更,如消费者组使用正则方式订阅主题,当新增一个符合条件的主题时。
订阅主题分区发生变更。
消费组的重平衡时会阻塞所有消费者。目前 无法解决这个重平衡机制问题,但是有一些优化途径,尽量避免此类情况发生。
session.timeout.ms = 10s
heartbeat.interval.ms = 3s
max.poll.records 默认 500,一次 poll 的数量
max.poll.interval.ms 默认是 5 分钟。如果5分钟内无法消费完 poll 方法返回的消息,那么消费者会自动离组。
fetch.message.max.bytes 8388608
max.partition.fetch.bytes 8388608
针对大消息的设置策略
Producer 每次发送的消息封装成 ProducerRecord,然后利用消息累加器 RecordAccumulator 添加到 ProducerBatch 中,由于每次创建 ProducerBatch 都需要分配一个 batch.size 大小的内存空间,频繁创建和关闭会导致性能极大开销,所以 RecordAccumulator 内部有个 BufferPool,它实现了缓存的复用,只不过只针对 batch.size 大小的 BufferByte 进行复用,如果大于 batch.size 的 ProducerBatch,它并不会加入 BufferPool 中,也就不会复用。
kafka 常见问题
Too many open files
日志报错
ERROR Error while accepting connection (kafka.network.Acceptor)
java.io.IOException: Too many open files
解决办法
netstart -unltpa|grep 9096
ulimit -n
kafka 常用命令
python 操作 kafka
pykafka 2.3.1、kafka-python 1.1.1和confluent-kafka-python 0.9.1
以三者的producer为例,confluent-kafka-python >> pykafka(librdkafka backend) >> pykafka > kafka-python;以三者的consumer为例,confluent-kafka-python >> pykafka(librdkafka backend) >> kafka-python > pykafka。
kafka-python
2、consumer
常规消费
from kafka import KafkaConsumer,TopicPartition
consumer = KafkaConsumer(
'tbl_stream',
group_id="eztest",
bootstrap_servers=['192.168.1.1:9092']
)
print("连接成功...")
res = consumer.poll(100)
consumer.seek_to_beginning()
for msg in consumer:
print(msg)
指定位置消费
consumer = KafkaConsumer(
group_id="eztest",
bootstrap_servers=['192.168.1.1:9092']
)
print("连接成功...")
partition = TopicPartition('tbl_stream_17765',5)
consumer.assign([partition])
consumer.seek(partition, start)
for msg in consumer:
print(msg)
print(msg.partition,msg.offset)
根据时间戳查询每个分区的位置
from kafka import KafkaConsumer,TopicPartition
import time
consumer = KafkaConsumer(
group_id="eztest",
bootstrap_servers=['192.168.1.1:9092']
)
print("连接成功...")
topic = "tbl_stream_8694"
begin_time = 1623081600000
begin_search = {}
for partition in [0,1,2,3,4,5]:
tp = TopicPartition(topic, partition)
begin_search[tp] = begin_time
begin_offset = consumer.offsets_for_times(begin_search)
print(begin_offset)
pykafka
from pykafka import KafkaClient
client = KafkaClient(hosts='120.133.1.1:9096,120.133.1.2:9096,120.133.1.3:9096')
print(client.topics)
topic = client.topics['tbl_stream_2098']
# 获取消费者
# consumer = topic.get_simple_consumer('abcd', auto_commit_enable=True, auto_commit_interval_ms=1)
consumer = topic.get_simple_consumer()
print(consumer)
suc = 0
for message in consumer:
suc += 1
print(suc,message.partition,message.offset)
print(message.value.decode())