大致图如下:(partition和replica和kafka broker的关系图)
参数 | 描述 |
---|---|
replica.lag.time.max.ms | ISR 中,如果 Follower 长时间未向 Leader 发送通信请求或同步数据,则该 Follower 将被踢出 ISR,并移动到OSR。该时间阈值,默认 30s |
auto.leader.rebalance.enable | 默认是 true。 自动 Leader Partition 平衡(再平衡)。 |
leader.imbalance.per.broker.percentage | **默认是 10%。**每个 broker 允许的不平衡的 leader的比率。如果每个 broker 超过了这个值,控制器会触发 leader的平衡。 |
leader.imbalance.check.interval.seconds | 默认值 300 秒。检查 leader 负载是否平衡的间隔时间。 |
log.segment.bytes | Kafka 中 log 日志是分成一块块存储的,此配置是指 log日志划分 成块的大小,默认值 1G。 |
log.index.interval.bytes | 默认 4kb,kafka 里面每当写入了 4kb 大小的日志(.log),然后就往 index文件里面记录一个索引 |
log.retention.hours | Kafka 中数据保存的时间,默认 7 天。 |
log.retention.minutes | Kafka 中数据保存的时间,分钟级别,默认关闭。 |
log.retention.ms | Kafka 中数据保存的时间,毫秒级别,默认关闭。 |
log.retention.check.interval.ms | 检查数据是否保存超时的间隔,默认是 5 分钟。 |
log.retention.bytes | 默认等于-1,表示无穷大。超过设置的所有日志总大小,删除最早的 segment。 |
log.cleanup.policy | 默认是 delete,表示所有数据启用删除策略;如果设置值为 compact,表示所有数据启用压缩策略。 |
num.io.threads | 默认是 8。负责写磁盘的线程数。整个参数值要占总核数的 50%。 |
num.network.threads | 默认是 3。数据传输线程数,这个参数占总核数的50%的 2/3 。 |
num.replica.fetchers | 副本拉取线程数,这个参数占总核数的 50%的 1/3 |
先只启动kafka01和kafka02机器,然后创建topic,副本数设置为2。然后再启动kafka03机器,然后让这个kafka03节点服役到集群中。
kafka-topics.sh --bootstrap-server=192.168.184.201:9092 --topic=mytopic001 --partitions=3 --replication-factor=2 --create
kafka-topics.sh --bootstrap-server=192.168.184.201:9092 --topic=mytopic001 --describe
kafka-topics.sh --bootstrap-server=192.168.184.201:9092 --topic=mytopic001 --describe
vim topics-to-move.json
内容如下:(topics下面的topic设置为想要服役的topic主题名称,其他不变)
{
"topics": [
{"topic": "mytopic001"}
],
"version": 1
}
kafka-reassign-partitions.sh --bootstrap-server kafka01:9092 --topics-to-move-json-file topics-to-move.json --broker-list "1,2,3" --generate
vim increase-replication-factor.json
内容如下:(就是刚刚复制的新的负载均衡计划)
{"version":1,"partitions":[{"topic":"mytopic001","partition":0,"replicas":[3,2],"log_dirs":["any","any"]},{"topic":"mytopic001","partition":1,"replicas":[1,3],"log_dirs":["any","any"]},{"topic":"mytopic001","partition":2,"replicas":[2,1],"log_dirs":["any","any"]}]}
kafka-reassign-partitions.sh --bootstrap-server kafka01:9092 --reassignment-json-file increase-replication-factor.json --execute
kafka-topics.sh --bootstrap-server=192.168.184.201:9092 --topic=mytopic001 --describe
kafka-topics.sh --bootstrap-server=192.168.184.201:9092 --topic=mytopic001 --describe
vim topics-to-move.json
内容如下:(topics下面的topic设置为想要退役的topic主题名称,其他不变)
{
"topics": [
{"topic": "mytopic001"}
],
"version": 1
}
kafka-reassign-partitions.sh --bootstrap-server kafka01:9092 --topics-to-move-json-file topics-to-move.json --broker-list "1,2" --generate
vim decr-replication-factor.json
内容如下:(就是刚刚复制的新的负载均衡计划)
{"version":1,"partitions":[{"topic":"mytopic001","partition":0,"replicas":[1,2],"log_dirs":["any","any"]},{"topic":"mytopic001","partition":1,"replicas":[2,1],"log_dirs":["any","any"]},{"topic":"mytopic001","partition":2,"replicas":[1,2],"log_dirs":["any","any"]}]}
kafka-reassign-partitions.sh --bootstrap-server kafka01:9092 --reassignment-json-file decr-replication-factor.json --execute
kafka-topics.sh --bootstrap-server=192.168.184.201:9092 --topic=mytopic001 --describe
replica(副本):为了防止集群中机器故障导致数据丢失,所以副本出现了。kafka的每一个topic在每一个分区都可以有多个replica副本,副本分为leader副本和follower副本。
AR:分区中的所有 Replica 统称为 AR = ISR +OSR
ISR:所有与 Leader 副本保持一定程度同步的Replica(包括 Leader 副本在内)组成 ISR
OSR:与 Leader 副本同步滞后过多的 Replica 组成了 OSR
选举规则:以ISR队列存在为前提,选举AR队列中的第一个副本为leader副本。
如果leader副本故障下线,则也会以ISR队列存在为前提,选举AR队列第一个为leader(第一个不行则第二个,一直轮询直到选出leader)。
kafka-topics.sh --bootstrap-server kafka01:9092 --create --partitions 3 --replication-factor 1 --topic mytopic002
kafka-topics.sh --bootstrap-server=192.168.184.201:9092 --topic=mytopic002 --describe
vim increase-replication-factor.json
内容如下:(修改topic和replicas)
{
"version":1,
"partitions":[
{"topic":"mytopic002","partition":0,"replicas":[1,2]},
{"topic":"mytopic002","partition":1,"replicas":[1,2]},
{"topic":"mytopic002","partition":2,"replicas":[1,2]}
]
}
kafka-reassign-partitions.sh --bootstrap-server kafka01:9092 --reassignment-json-file increase-replication-factor.json --execute
kafka-topics.sh --bootstrap-server=192.168.184.201:9092 --topic=mytopic002 --describe
一般情况下,我们的分区都是平衡散落在broker的,随着一些broker故障,会慢慢出现leader集中在某台broker上的情况,造成集群负载不均衡,这时候就需要分区平衡。
kafka-topics.sh --bootstrap-server kafka01:9092 --create --partitions 3 --replication-factor 1 --topic mytopic002
kafka-topics.sh --bootstrap-server=192.168.184.201:9092 --topic=mytopic002 --describe
vim increase-replication-factor.json
内容如下:(修改topic和replicas)
{
"version":1,
"partitions":[
{"topic":"mytopic002","partition":0,"replicas":[1,2]},
{"topic":"mytopic002","partition":1,"replicas":[1,2]},
{"topic":"mytopic002","partition":2,"replicas":[1,2]}
]
}
kafka-reassign-partitions.sh --bootstrap-server kafka01:9092 --reassignment-json-file increase-replication-factor.json --execute
kafka-topics.sh --bootstrap-server=192.168.184.201:9092 --topic=mytopic002 --describe
每一个partition分区都对应着一个log文件。Producer生产的数据会被不断追加到该log文件末端
kafka为了提高效率,把每一个log文件拆分成多个segment(每个segment大小默认是1G),可以通过log.segment.bytes
去修改。
该文件命名规则为:topic名称+分区号
当log文件写入4kb大小数据(这里可以通过log.index.interval.bytes
设置),就会写入一条索引信息到index文件中,这样的index索引文件就是一个稀疏索引,它并不会每条日志都建立索引信息。
日志清理策略有两个:
log.cleanup.policy
来进行配置kafka中默认的日志保存时间为7天,可以通过调整如下参数修改保存时间。
kafka大量使用了页缓存(PageCache),分为以下两个场景:
零拷贝并不是不需要拷贝,而是减少不必要的拷贝次数。
一个相同消费者组的消费者,它们的groupid是相同的。
一个分区只能由同一个消费者组的一个消费者所消费。
消费者组之间互不影响。
首先要选择出coordinator,如下:
后面由coordinator负责选出消费组中的Leader
参数 | 描述 |
---|---|
bootstrap.servers | Kafka集群地址列表。 |
key.deserializer 和value.deserialize | 反序列化类型。要写全类名 |
group.id | 消费者组id。标记消费者所属的消费者组 |
enable.auto.commit | 默认值为 true,消费者会自动周期性地向服务器提交偏移量 |
auto.commit.interval.ms | 如果设置了 enable.auto.commit 的值为 true, 则该值定义了消费者偏移量向 Kafka提交的频率,默认 5s。 |
auto.offset.reset | earliest:自动重置偏移量到最早的偏移量。 latest:默认,自动重置偏移量为最新的偏移量。 none:如果消费组原来的(previous)偏移量不存在,则向消费者抛异常。 anything:向消费者抛异常 |
offsets.topic.num.partitions | __consumer_offsets 的分区数,默认是 50 个分区。 |
heartbeat.interval.ms | Kafka 消费者和 coordinator 之间的心跳时间,默认 3s。该条目的值必须小于 session.timeout.ms ,也不应该高于session.timeout.ms 的 1/3 |
session.timeout.ms | Kafka 消费者和 coordinator 之间连接超时时间,默认 45s。超过该值,该消费者被移除,消费者组执行再平衡。 |
max.poll.interval.ms | 消费者处理消息的最大时长,默认是 5 分钟。超过该值,该消费者被移除,消费者组执行再平衡。 |
fetch.min.bytes | 默认 1 个字节。消费者获取服务器端一批消息最小的字节数。 |
fetch.max.wait.ms | 默认 500ms。如果没有从服务器端获取到一批数据的最小字节数。该时间到,仍然会返回数据。 |
fetch.max.bytes | 默认 Default: 52428800(50 m)。消费者获取服务器端一批 消息最大的字节数。 |
max.poll.records | 一次 poll拉取数据返回消息的最大条数,默认是 500 条 |
package com.kafka02.consumer;
import org.apache.kafka.clients.consumer.ConsumerConfig;
import org.apache.kafka.clients.consumer.ConsumerRecords;
import org.apache.kafka.clients.consumer.KafkaConsumer;
import org.apache.kafka.common.serialization.StringDeserializer;
import java.time.Duration;
import java.util.HashSet;
import java.util.Properties;
import java.util.Set;
public class MyConsumer {
public static void main(String[] args) {
Properties properties = new Properties();
//1:基本配置
properties.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG,"192.168.184.201:9092");
properties.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName());
properties.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG,StringDeserializer.class.getName());
//2:指定消费者组id。注意指定my-consumer-group01会出现无反应现象。最好别加数字。my-consumer-group
properties.put(ConsumerConfig.GROUP_ID_CONFIG,"my-consumer-group");
KafkaConsumer<String, String> kafkaConsumer = new KafkaConsumer<String, String>(properties);
// 存放需要消费的topic名称
Set<String> topicSet=new HashSet<>();
topicSet.add("java-api-test");
// 订阅这个topic集合
kafkaConsumer.subscribe(topicSet);
System.out.println("等待拉取数据------");
//循环消费消息
while (true){
//kafka消费者的消费模式就是poll。指定1s拉取一次数据
ConsumerRecords<String, String> consumerRecords =
kafkaConsumer.poll(Duration.ofSeconds(1));
//输出消息
consumerRecords.forEach(record -> {
System.out.println("--");
System.out.println(record);
});
}
}
}
package com.kafka02.consumer;
import org.apache.kafka.clients.consumer.ConsumerConfig;
import org.apache.kafka.clients.consumer.ConsumerRecords;
import org.apache.kafka.clients.consumer.KafkaConsumer;
import org.apache.kafka.common.serialization.StringDeserializer;
import java.time.Duration;
import java.util.HashSet;
import java.util.Properties;
import java.util.Set;
public class MyConsumerCommit {
public static void main(String[] args) {
Properties properties = new Properties();
//1:基本配置
properties.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG,"192.168.184.201:9092");
properties.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName());
properties.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG,StringDeserializer.class.getName());
//2:指定消费者组id。注意指定my-consumer-group01会出现无反应现象。最好别加数字。my-consumer-group
properties.put(ConsumerConfig.GROUP_ID_CONFIG,"my-consumer-group");
//3:关闭自动提交
properties.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG,false);
KafkaConsumer<String, String> kafkaConsumer = new KafkaConsumer<>(properties);
// 存放需要消费的topic名称
Set<String> topicSet=new HashSet<>();
topicSet.add("java-api-test");
// 订阅这个topic集合
kafkaConsumer.subscribe(topicSet);
System.out.println("等待拉取数据------");
//循环消费消息
while (true){
//kafka消费者的消费模式就是poll。指定1s拉取一次数据
ConsumerRecords<String, String> consumerRecords =
kafkaConsumer.poll(Duration.ofSeconds(1));
//消费消息
consumerRecords.forEach(record -> {
System.out.println("--");
System.out.println(record);
});
//消费结束后手动提交offset
kafkaConsumer.commitSync(); //同步提交
}
}
}
解决方案1:可以增加partition分区数和增加消费者组中的消费者数量,使partition分区数=消费者组中的消费者数量。
解决方案2:提高每批次拉取消息的数量(max.poll.records
),默认是500条,可以提高到1000条。