KafkaAdminClient
- 主题管理:主题的创建、删除、查询
- 权限管理:具体权限的配置和删除
- 配置参数管理:Kafka各种资源(Broker、主题、用户、Client-Id等)的参数设置、查询
- 副本日志管理:副本底层日志路径的变更和详情查询
- 分区管理:创建额外的主题分区
- 消息删除:删除指定位移之前的分区消息
- Delegation Token管理:Delegation Token的创建、更新、过期、查询
- 消费者组管理:消费者组的查询、位移查询和删除
- Preferred领导者选举:推选指定主题分区的Preferred Broker为领导者
工作原理

- KafkaAdminClient是双线程设计
- 前端主线程:负责将用户要执行的操作转换成对应的请求,然后将请求发送到后端IO线程的队列中
- 后端IO线程:从队列中读取相应的请求,再发送到对应的Broker节点上,之后把执行结果保存起来,等待前端线程的获取
- KafkaAdminClient在内部大量使用生产者-消费者模式将请求生成和处理解耦
- 前端主线程会创建名为Call的请求对象实例,该实例有两个主要任务
- 构建对应的请求对象
- 创建主题:CreateTopicsRequest
- 查询消费者组位移:OffsetFetchRequest
- 指定响应的回调逻辑
- 比如从Broker端接收到CreateTopicsResponse之后要执行的动作
- 构建对应的请求对象
- 后端IO线程使用了3个队列来承载不同时期的请求对象,分别为新请求队列、待发送请求队列和处理中请求队列
- 原因:新请求队列的线程安全是由Java的Monitor锁来保证的
- 为了保证前端线程不会因为Monitor锁被阻塞,后端IO线程会定期地将新请求队列中的所有Call实例全部搬移到待发送请求队列中进行处理
- 待发送请求队列和处理中请求队列只由后端IO线程处理,因为无需任何锁机制来保证线程安全
- 当后端IO线程在处理某个请求时,会显式地将请求保存在处理中请求队列
- 一旦处理完毕,后端IO线程会自动调用Call对象中的回调逻辑完成最后的处理
- 最后,后端IO线程会通知前端主线程说结果已经准备完毕,这样前端主线程就能够及时获取到执行操作的结果
- KafkaAdminClient是使用了Object的wait和notify来实现通知机制
- KafkaAdminClient并没有使用Java已有的队列去实现请求队列
- 而是使用ArrayList和HashMap等简单容器,再配合Monitor锁来保证线程安全
- 后端线程名称:
kafka-admin-client-thread,可以用jstack去确认程序是否正常工作- 后端IO线程可能由于未捕获某些异常而意外挂掉
- 原因:新请求队列的线程安全是由Java的Monitor锁来保证的
创建Topic
public static void createTopic() throws ExecutionException, InterruptedException { Properties props = new Properties(); props.put(AdminClientConfig.BOOTSTRAP_SERVERS_CONFIG, "192.168.21.120:9092"); props.put("request.timeout.ms", 60000); String topicName = "my-admin-topic"; try (AdminClient adminClient = AdminClient.create(props)) { NewTopic newTopic = new NewTopic(topicName, 4, (short) 1); CreateTopicsResult topics = adminClient.createTopics(Collections.singletonList(newTopic)); log.info("{}", topics.all().get()); } }
展示topic
/** * 展示topic * * @throws ExecutionException * @throws InterruptedException */ public static void listTopicsIncludeInternal() throws ExecutionException, InterruptedException { Properties props = new Properties(); props.put(AdminClientConfig.BOOTSTRAP_SERVERS_CONFIG, "192.168.21.120:9092"); props.put("request.timeout.ms", 60000); ListTopicsOptions listTopicsOptions = new ListTopicsOptions(); listTopicsOptions.listInternal(true); try (AdminClient adminClient = AdminClient.create(props)) { ListTopicsResult listTopicsResult = adminClient.listTopics(listTopicsOptions); Collection<TopicListing> topicListings = listTopicsResult.listings().get(); log.info("{}", topicListings); } }
描述topic
public static void describeTopic() throws ExecutionException, InterruptedException { Properties props = new Properties(); props.put(AdminClientConfig.BOOTSTRAP_SERVERS_CONFIG, "192.168.21.120:9092"); props.put("request.timeout.ms", 60000); try (AdminClient adminClient = AdminClient.create(props)) { DescribeTopicsResult topicsResult = adminClient.describeTopics(Arrays.asList("my-admin-topic")); Map<String, TopicDescription> topicDescription = topicsResult.all().get(); log.info("{}", topicDescription); } }
展示配置信息
public static void describeConfig() throws ExecutionException, InterruptedException { Properties props = new Properties(); props.put(AdminClientConfig.BOOTSTRAP_SERVERS_CONFIG, "192.168.21.120:9092"); props.put("request.timeout.ms", 60000); try (AdminClient adminClient = AdminClient.create(props)) { ConfigResource configResource = new ConfigResource(ConfigResource.Type.TOPIC, "my-admin-topic"); DescribeConfigsResult describeConfigsResult = adminClient.describeConfigs(Arrays.asList(configResource)); Map<ConfigResource, Config> configResourceConfigMap = describeConfigsResult.all().get(); Set<Map.Entry<ConfigResource, Config>> entries = configResourceConfigMap.entrySet(); for (Map.Entry<ConfigResource, Config> entry : entries) { log.info("configResource:{} value:{}", entry.getKey(), entry.getValue()); } } }
修改配置信息
public static void modifyConfig() throws ExecutionException, InterruptedException { Properties props = new Properties(); props.put(AdminClientConfig.BOOTSTRAP_SERVERS_CONFIG, "192.168.21.120:9092"); props.put("request.timeout.ms", 60000); try (AdminClient adminClient = AdminClient.create(props)) { ConfigResource configResource = new ConfigResource(ConfigResource.Type.TOPIC, "my-admin-topic"); Config config = new Config(Arrays.asList(new ConfigEntry("preallocate", "true"))); Map<ConfigResource, Config> configMaps = new HashMap<>(); configMaps.put(configResource, config); AlterConfigsResult alterConfigsResult = adminClient.alterConfigs(configMaps); // AlterConfigOp alterConfigOp = new AlterConfigOp(new ConfigEntry("preallocate", "true"), AlterConfigOp.OpType.SET); // Map<ConfigResource, Collection<AlterConfigOp>> configMaps = new HashMap<>(); // configMaps.put(configResource, Arrays.asList(alterConfigOp)); // // AlterConfigsResult alterConfigsResult = adminClient.incrementalAlterConfigs(configMaps); // alterConfigsResult.all().get(); } }
立志如山 静心求实
浙公网安备 33010602011771号