Kafka高级特性解析
文章目录
2.3 主题
2.3.1 管理
使用kafka-topics.sh脚本:
主题中可以使用的参数定义:
2.3.1.1 创建主题
[root@linux01 ~]# kafka-topics.sh --zookeeper linux01:2181/mykafka --create --topic topic_x --partitions 1 --replication-factor 1
[root@linux01 ~]# kafka-topics.sh --zookeeper linux01:2181/mykafka --create --topic topic_test_02 --partitions 3 --replication-factor 1 --config max.message.bytes=1048576 --config segment.bytes=10485760
2.3.1.2 查看主题
[root@linux01 ~]# kafka-topics.sh --zookeeper linux01:2181/mykafka --list
[root@linux01 ~]# kafka-topics.sh --zookeeper linux01:2181/mykafka --describe --topic topic_x
[root@linux01 ~]# kafka-topics.sh --zookeeper linux01:2181/mykafka --topics-with-overrides --describe
2.3.1.3 修改主题
[root@linux01 ~]# kafka-topics.sh --zookeeper linux01:2181/mykafka --create --topic topic_test_01 --partitions 2 --replication-factor 1
[root@linux01 ~]# kafka-topics.sh --zookeeper linux01:2181/mykafka --alter --topic topic_test_01 --config max.message.bytes=1048576
[root@linux01 ~]# kafka-topics.sh --zookeeper linux01:2181/mykafka --describe --topic topic_test_01
[root@linux01 ~]# kafka-topics.sh --zookeeper linux01:2181/mykafka --alter --topic topic_test_01 --config segment.bytes=10485760
[root@linux01 ~]# kafka-topics.sh --zookeeper linux01:2181/mykafka --alter --delete-config max.message.bytes --topic topic_test_01
2.3.1.4 删除主题
[root@linux01 ~]# kafka-topics.sh --zookeeper linux01:2181/mykafka --delete --topic topic_test_02
[root@linux01 ~]# cd /var/lagou/kafka/kafka-logs/
如上,给主题添加删除的标记:
topic_test_02-0.5f680b9bc37a4b669b906009155d886a-delete
要过一段时间删除。
2.3.2 增加分区
通过命令行工具操作,主题的分区只能增加,不能减少。否则报错:
通过–alter修改主题的分区数,增加分区。
kafka-topics.sh --zookeeper linux01/mykafka --alter --topic topic_test_01 --partitions 3
2.3.3 分区副本的分配-了解
副本分配的三个目标:
- 均衡地将副本分散于各个broker上
- 对于某个broker上分配的分区,它的其他副本在其他broker上
- 如果所有的broker都有机架信息,尽量将分区的各个副本分配到不同机架上的broker。
在不考虑机架信息的情况下:
- 第一个副本分区通过轮询的方式挑选一个broker,进行分配。该轮询从broker列表的随机位
置进行轮询。 - 其余副本通过增加偏移进行分配。
2.3.4 必要参数配置
kafka-topics.sh --config xx=xx --config yy=yy
配置给主题的参数。
2.3.5 KafkaAdminClient应用
说明
除了使用Kafka的bin目录下的脚本工具来管理Kafka,还可以使用管理Kafka的API将某些管理查看的功能集成到系统中。在Kafka0.11.0.0版本之前,可以通过kafka-core包(Kafka的服务端,采用Scala
编写)中的AdminClient和AdminUtils来实现部分的集群管理操作。Kafka0.11.0.0之后,又多了一个AdminClient,在kafka-client包下,一个抽象类,具体的实现是org.apache.kafka.clients.admin.KafkaAdminClient。
功能与原理介绍
Kafka官网:The AdminClient API supports managing and inspecting topics, brokers, acls, and other Kafka objects。
KafkaAdminClient包含了一下几种功能(以Kafka1.0.2版本为准):
- 创建主题:
createTopics(final Collection newTopics, final CreateTopicsOptions options) - 删除主题:
deleteTopics(final Collection topicNames,DeleteTopicsOptions options) - 列出所有主题:
listTopics(final ListTopicsOptions options) - 查询主题:
describeTopics(final Collection topicNames, DescribeTopics Options options) - 查询集群信息:
describeCluster(DescribeClusterOptions options) - 查询配置信息:
describeConfigs(Collection configResources, final
DescribeConfigsOptions options) - 修改配置信息:
alterConfigs(Map<ConfigResource, Config> configs, final AlterConfigsOptions options) - 修改副本的日志目录:
alterReplicaLogDirs(Map<TopicPartitionReplica, String> replicaAssignment,final AlterReplicaLogDirsOptions options) - 查询节点的日志目录信息:
describeLogDirs(Collection brokers,DescribeLogDirsOptions options) - 查询副本的日志目录信息:
describeReplicaLogDirs(Collection replicas,
DescribeReplicaLogDirsOptions options) - 增加分区:
createPartitions(Map<String, NewPartitions> newPartitions, final
CreatePartitionsOptions options)
其内部原理是使用Kafka自定义的一套二进制协议来实现,详细可以参见Kafka协议。
用到的参数:
主要操作步骤:
客户端根据方法的调用创建相应的协议请求,比如创建Topic的createTopics方法,其内部就是发送CreateTopicRequest请求。
客户端发送请求至Kafka Broker。
Kafka Broker处理相应的请求并回执,比如与CreateTopicRequest对应的是CreateTopicResponse。 客户端接收相应的回执并进行解析处理。
和协议有关的请求和回执的类基本都在org.apache.kafka.common.requests包中,AbstractRequest和AbstractResponse是这些请求和响应类的两个父类。
综上,如果要自定义实现一个功能,只需要三个步骤:
- 自定义XXXOptions;
- 自定义XXXResult返回值;
- 自定义Call,然后挑选合适的XXXRequest和XXXResponse来实现Call类中的3个抽象方法。
具体实现:
pom.xml
<dependencies>
<dependency>
<groupId>org.apache.kafka</groupId>
<artifactId>kafka-clients</artifactId>
<version>1.0.2</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.1</version>
<scope>compile</scope>
</dependency>
</dependencies>
实现类:MyAdminClient
查看主题
package com.lagou.kafka;
import org.apache.kafka.clients.admin.*;
import org.apache.kafka.common.KafkaFuture;
import org.apache.kafka.common.Node;
import org.apache.kafka.common.TopicPartition;
import org.apache.kafka.common.TopicPartitionInfo;
import org.apache.kafka.common.config.ConfigResource;
import org.apache.kafka.common.requests.DescribeLogDirsResponse;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
public class MyAdminClient {
private KafkaAdminClient client;
@Before
public void before() {
Map<String, Object> configs = new HashMap<>();
configs.put("bootstrap.servers", "linux01:9092");
configs.put("client.id", "admin_001");
client = (KafkaAdminClient) KafkaAdminClient.create(configs);
}
@After
public void after() {
// 关闭admin客户端
client.close();
}
@Test
public void testListTopics1() throws ExecutionException, InterruptedException {
ListTopicsResult listTopicsResult = client.listTopics();
// 1.1 将请求变成同步的请求,直接获取结果======================================
KafkaFuture<Collection<TopicListing>> listings = listTopicsResult.listings();
Collection<TopicListing> topicListings = listings.get();
topicListings.forEach(new Consumer<TopicListing>() {
@Override
public void accept(TopicListing topicListing) {
// 该主题是否是内部主题
boolean internal = topicListing.isInternal();
// 打印主题名字
String name = topicListing.name();
// 直接打印全部信息
String s = topicListing.toString();
System.out.println(s + "\t" + name + "\t" + internal);
}
});
}
}
异步方法列出主题
@Test
public void testListTopics1() throws ExecutionException, InterruptedException {
ListTopicsResult listTopicsResult = client.listTopics();
// 1.2, 异步方法列出主题======================================
KafkaFuture<Set<String>> names = listTopicsResult.names();
Set<String> strings = names.get();
strings.forEach(name -> {
System.out.println(name);
});
KafkaFuture<Map<String, TopicListing>> mapKafkaFuture = listTopicsResult.namesToListings();
Map<String, TopicListing> stringTopicListingMap = mapKafkaFuture.get();
stringTopicListingMap.forEach((k, v) -> {
System.out.println(k + "\t" + v);
});
}
设置请求属性
@Test
public void testListTopics1() throws ExecutionException, InterruptedException {
//另一种方法, 可以设置请求的属性
ListTopicsOptions options = new ListTopicsOptions();
// 列出内部主题
options.listInternal(true);
// 设置超时时间
options.timeoutMs(900);
ListTopicsResult listTopicsResult1 = client.listTopics(options);
Map<String, TopicListing> stringTopicListingMap1 = listTopicsResult1.namesToListings().get();
stringTopicListingMap1.forEach((k, v) -> {
System.out.println(k + "\t" + v);
});
// 关闭管理客户端
client.close();
}
创建主题
// 创建主题
@Test
public void testCreateTopic() throws ExecutionException, InterruptedException {
Map<String, String> configs = new HashMap<>();
configs.put("max.message.bytes", "1048576");
configs.put("segment.bytes", "1048576000");
NewTopic newTopic = new NewTopic("adm_tp_01", 2, (short) 1);
newTopic.configs(configs);
CreateTopicsResult topics = client.createTopics(Collections.singleton(newTopic));
KafkaFuture<Void> all = topics.all();
Void aVoid = all.get();
System.out.println(aVoid);
}
删除主题
@Test
public