Skip to content

Commit 06178e6

Browse files
author
Lincong Li
authored
Refactor and clean up (#339)
1. Add logging to the MultiClusterTopicManagementService class 2. Add a timeout to some admin client requests 3. Rename some variables with non-inclusive language
1 parent 36a93e6 commit 06178e6

File tree

6 files changed

+64
-49
lines changed

6 files changed

+64
-49
lines changed

src/main/java/com/linkedin/xinfra/monitor/XinfraMonitor.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -65,22 +65,22 @@ public XinfraMonitor(Map<String, Map> allClusterProps) throws Exception {
6565
_services = new ConcurrentHashMap<>();
6666

6767
for (Map.Entry<String, Map> clusterProperty : allClusterProps.entrySet()) {
68-
String name = clusterProperty.getKey();
68+
String clusterName = clusterProperty.getKey();
6969
Map props = clusterProperty.getValue();
7070
if (!props.containsKey(XinfraMonitorConstants.CLASS_NAME_CONFIG))
71-
throw new IllegalArgumentException(name + " is not configured with " + XinfraMonitorConstants.CLASS_NAME_CONFIG);
71+
throw new IllegalArgumentException(clusterName + " is not configured with " + XinfraMonitorConstants.CLASS_NAME_CONFIG);
7272
String className = (String) props.get(XinfraMonitorConstants.CLASS_NAME_CONFIG);
7373

7474
Class<?> aClass = Class.forName(className);
7575
if (App.class.isAssignableFrom(aClass)) {
76-
App clusterApp = (App) Class.forName(className).getConstructor(Map.class, String.class).newInstance(props, name);
77-
_apps.put(name, clusterApp);
76+
App clusterApp = (App) Class.forName(className).getConstructor(Map.class, String.class).newInstance(props, clusterName);
77+
_apps.put(clusterName, clusterApp);
7878
} else if (Service.class.isAssignableFrom(aClass)) {
7979
ServiceFactory serviceFactory = (ServiceFactory) Class.forName(className + XinfraMonitorConstants.FACTORY)
8080
.getConstructor(Map.class, String.class)
81-
.newInstance(props, name);
81+
.newInstance(props, clusterName);
8282
Service service = serviceFactory.createService();
83-
_services.put(name, service);
83+
_services.put(clusterName, service);
8484
} else {
8585
throw new IllegalArgumentException(className + " should implement either " + App.class.getSimpleName() + " or " + Service.class.getSimpleName());
8686
}

src/main/java/com/linkedin/xinfra/monitor/apps/SingleClusterMonitor.java

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -55,21 +55,22 @@ public class SingleClusterMonitor implements App {
5555

5656
private static final int SERVICES_INITIAL_CAPACITY = 4;
5757
private final TopicManagementService _topicManagementService;
58-
private final String _name;
58+
private final String _clusterName;
5959
private final List<Service> _allServices;
6060
private final boolean _isTopicManagementServiceEnabled;
6161

62-
public SingleClusterMonitor(Map<String, Object> props, String name) throws Exception {
62+
public SingleClusterMonitor(Map<String, Object> props, String clusterName) throws Exception {
6363
ConsumerFactory consumerFactory = new ConsumerFactoryImpl(props);
64-
_name = name;
64+
_clusterName = clusterName;
6565
LOG.info("SingleClusterMonitor properties: {}", prettyPrint(props));
6666
TopicManagementServiceConfig config = new TopicManagementServiceConfig(props);
6767
_isTopicManagementServiceEnabled =
6868
config.getBoolean(TopicManagementServiceConfig.TOPIC_MANAGEMENT_ENABLED_CONFIG);
6969
_allServices = new ArrayList<>(SERVICES_INITIAL_CAPACITY);
7070
CompletableFuture<Void> topicPartitionResult;
7171
if (_isTopicManagementServiceEnabled) {
72-
_topicManagementService = new TopicManagementService(props, name);
72+
String topicManagementServiceName = String.format("Topic-management-service-for-%s", clusterName);
73+
_topicManagementService = new TopicManagementService(props, topicManagementServiceName);
7374
topicPartitionResult = _topicManagementService.topicPartitionResult();
7475

7576
// block on the MultiClusterTopicManagementService to complete.
@@ -80,10 +81,9 @@ public SingleClusterMonitor(Map<String, Object> props, String name) throws Excep
8081
_topicManagementService = null;
8182
topicPartitionResult = new CompletableFuture<>();
8283
topicPartitionResult.complete(null);
83-
8484
}
85-
ProduceService produceService = new ProduceService(props, name);
86-
ConsumeService consumeService = new ConsumeService(name, topicPartitionResult, consumerFactory);
85+
ProduceService produceService = new ProduceService(props, clusterName);
86+
ConsumeService consumeService = new ConsumeService(clusterName, topicPartitionResult, consumerFactory);
8787
_allServices.add(produceService);
8888
_allServices.add(consumeService);
8989
}
@@ -126,15 +126,15 @@ public void start() throws Exception {
126126
}
127127
}
128128

129-
LOG.info(_name + "/SingleClusterMonitor started!");
129+
LOG.info(_clusterName + "/SingleClusterMonitor started!");
130130
}
131131

132132
@Override
133133
public void stop() {
134134
for (Service service : _allServices) {
135135
service.stop();
136136
}
137-
LOG.info(_name + "/SingleClusterMonitor stopped.");
137+
LOG.info(_clusterName + "/SingleClusterMonitor stopped.");
138138
}
139139

140140
@Override

src/main/java/com/linkedin/xinfra/monitor/services/ClusterTopicManipulationService.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -164,14 +164,14 @@ private void createDeleteClusterTopic() {
164164
try {
165165
int brokerCount = _adminClient.describeCluster().nodes().get().size();
166166

167-
Set<Integer> blackListedBrokers = _topicFactory.getBlackListedBrokers(_adminClient);
168167
Set<BrokerMetadata> brokers = new HashSet<>();
169168
for (Node broker : _adminClient.describeCluster().nodes().get()) {
170169
BrokerMetadata brokerMetadata = new BrokerMetadata(broker.id(), null);
171170
brokers.add(brokerMetadata);
172171
}
173-
if (!blackListedBrokers.isEmpty()) {
174-
brokers.removeIf(broker -> blackListedBrokers.contains(broker.id()));
172+
Set<Integer> excludedBrokers = _topicFactory.getExcludedBrokers(_adminClient);
173+
if (!excludedBrokers.isEmpty()) {
174+
brokers.removeIf(broker -> excludedBrokers.contains(broker.id()));
175175
}
176176

177177
// map from partition id to replica ids (i.e. broker ids).

src/main/java/com/linkedin/xinfra/monitor/services/MultiClusterTopicManagementService.java

Lines changed: 44 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import com.linkedin.xinfra.monitor.services.configs.MultiClusterTopicManagementServiceConfig;
1616
import com.linkedin.xinfra.monitor.services.configs.TopicManagementServiceConfig;
1717
import com.linkedin.xinfra.monitor.topicfactory.TopicFactory;
18+
import java.time.Duration;
1819
import java.util.ArrayList;
1920
import java.util.Collection;
2021
import java.util.Collections;
@@ -26,6 +27,7 @@
2627
import java.util.Properties;
2728
import java.util.Random;
2829
import java.util.Set;
30+
import java.util.concurrent.CancellationException;
2931
import java.util.concurrent.CompletableFuture;
3032
import java.util.concurrent.ExecutionException;
3133
import java.util.concurrent.Executors;
@@ -41,7 +43,6 @@
4143
import org.apache.kafka.clients.admin.AlterPartitionReassignmentsResult;
4244
import org.apache.kafka.clients.admin.Config;
4345
import org.apache.kafka.clients.admin.ConfigEntry;
44-
import org.apache.kafka.clients.admin.CreatePartitionsResult;
4546
import org.apache.kafka.clients.admin.ElectLeadersResult;
4647
import org.apache.kafka.clients.admin.NewPartitionReassignment;
4748
import org.apache.kafka.clients.admin.NewPartitions;
@@ -248,7 +249,7 @@ static class TopicManagementHelper {
248249
private final int _minPartitionNum;
249250
private final Properties _topicProperties;
250251
private boolean _preferredLeaderElectionRequested;
251-
private final int _requestTimeoutMs;
252+
private final Duration _requestTimeout;
252253
private final List<String> _bootstrapServers;
253254

254255
// package private for unit testing
@@ -261,6 +262,7 @@ static class TopicManagementHelper {
261262

262263
@SuppressWarnings("unchecked")
263264
TopicManagementHelper(Map<String, Object> props) throws Exception {
265+
264266
TopicManagementServiceConfig config = new TopicManagementServiceConfig(props);
265267
AdminClientConfig adminClientConfig = new AdminClientConfig(props);
266268
String topicFactoryClassName = config.getString(TopicManagementServiceConfig.TOPIC_FACTORY_CLASS_CONFIG);
@@ -273,7 +275,7 @@ static class TopicManagementHelper {
273275
_minPartitionsToBrokersRatio = config.getDouble(TopicManagementServiceConfig.PARTITIONS_TO_BROKERS_RATIO_CONFIG);
274276
_minPartitionNum = config.getInt(TopicManagementServiceConfig.MIN_PARTITION_NUM_CONFIG);
275277
_preferredLeaderElectionRequested = false;
276-
_requestTimeoutMs = adminClientConfig.getInt(AdminClientConfig.REQUEST_TIMEOUT_MS_CONFIG);
278+
_requestTimeout = Duration.ofMillis(adminClientConfig.getInt(AdminClientConfig.REQUEST_TIMEOUT_MS_CONFIG));
277279
_bootstrapServers = adminClientConfig.getList(AdminClientConfig.BOOTSTRAP_SERVERS_CONFIG);
278280
_topicProperties = new Properties();
279281
if (props.containsKey(TopicManagementServiceConfig.TOPIC_PROPS_CONFIG)) {
@@ -288,9 +290,17 @@ static class TopicManagementHelper {
288290
TopicManagementServiceConfig.TOPIC_FACTORY_PROPS_CONFIG) : new HashMap();
289291
_topicFactory =
290292
(TopicFactory) Class.forName(topicFactoryClassName).getConstructor(Map.class).newInstance(topicFactoryConfig);
291-
292293
_adminClient = constructAdminClient(props);
293294
LOGGER.info("{} configs: {}", _adminClient.getClass().getSimpleName(), props);
295+
logConfigurationValues();
296+
}
297+
298+
private void logConfigurationValues() {
299+
LOGGER.info("TopicManagementHelper for cluster with Zookeeper connect {} is configured with " +
300+
"[topic={}, topicCreationEnabled={}, topicAddPartitionEnabled={}, " +
301+
"topicReassignPartitionAndElectLeaderEnabled={}, minPartitionsToBrokersRatio={}, " +
302+
"minPartitionNum={}]", _zkConnect, _topic, _topicCreationEnabled, _topicAddPartitionEnabled,
303+
_topicReassignPartitionAndElectLeaderEnabled, _minPartitionsToBrokersRatio, _minPartitionNum);
294304
}
295305

296306
@SuppressWarnings("unchecked")
@@ -317,7 +327,8 @@ int minPartitionNum() throws InterruptedException, ExecutionException {
317327
return Math.max((int) Math.ceil(_minPartitionsToBrokersRatio * brokerCount), _minPartitionNum);
318328
}
319329

320-
void maybeAddPartitions(int minPartitionNum) throws ExecutionException, InterruptedException {
330+
void maybeAddPartitions(final int requiredMinPartitionNum)
331+
throws ExecutionException, InterruptedException, CancellationException, TimeoutException {
321332
if (!_topicAddPartitionEnabled) {
322333
LOGGER.info("Adding partition to {} topic is not enabled in a cluster with Zookeeper URL {}. " +
323334
"Refer to config: {}", _topic, _zkConnect, TopicManagementServiceConfig.TOPIC_ADD_PARTITION_ENABLED_CONFIG);
@@ -326,32 +337,36 @@ void maybeAddPartitions(int minPartitionNum) throws ExecutionException, Interrup
326337
Map<String, KafkaFuture<TopicDescription>> kafkaFutureMap =
327338
_adminClient.describeTopics(Collections.singleton(_topic)).values();
328339
KafkaFuture<TopicDescription> topicDescriptions = kafkaFutureMap.get(_topic);
329-
List<TopicPartitionInfo> partitions = topicDescriptions.get().partitions();
330-
331-
int partitionNum = partitions.size();
332-
if (partitionNum < minPartitionNum) {
333-
LOGGER.info("{} will increase partition of the topic {} in the cluster from {}" + " to {}.",
334-
this.getClass().toString(), _topic, partitionNum, minPartitionNum);
335-
Set<Integer> blackListedBrokers = _topicFactory.getBlackListedBrokers(_adminClient);
336-
Set<BrokerMetadata> brokers = new HashSet<>();
337-
for (Node broker : _adminClient.describeCluster().nodes().get()) {
338-
BrokerMetadata brokerMetadata = new BrokerMetadata(broker.id(), null);
339-
brokers.add(brokerMetadata);
340-
}
340+
List<TopicPartitionInfo> partitions = topicDescriptions.get(_requestTimeout.toMillis(), TimeUnit.MILLISECONDS).partitions();
341341

342-
if (!blackListedBrokers.isEmpty()) {
343-
brokers.removeIf(broker -> blackListedBrokers.contains(broker.id()));
344-
}
342+
final int currPartitionNum = partitions.size();
343+
if (currPartitionNum >= requiredMinPartitionNum) {
344+
LOGGER.debug("{} will not increase partition of the topic {} in the cluster. Current partition count {} and '" +
345+
"minimum required partition count is {}.", this.getClass().toString(), _topic, currPartitionNum, requiredMinPartitionNum);
346+
return;
347+
}
348+
LOGGER.info("{} will increase partition of the topic {} in the cluster from {}" + " to {}.",
349+
this.getClass().toString(), _topic, currPartitionNum, requiredMinPartitionNum);
350+
Set<BrokerMetadata> brokers = new HashSet<>();
351+
for (Node broker : _adminClient.describeCluster().nodes().get(_requestTimeout.toMillis(), TimeUnit.MILLISECONDS)) {
352+
BrokerMetadata brokerMetadata = new BrokerMetadata(broker.id(), null);
353+
brokers.add(brokerMetadata);
354+
}
355+
Set<Integer> excludedBrokers = _topicFactory.getExcludedBrokers(_adminClient);
356+
if (!excludedBrokers.isEmpty()) {
357+
brokers.removeIf(broker -> excludedBrokers.contains(broker.id()));
358+
}
345359

346-
List<List<Integer>> newPartitionAssignments =
347-
newPartitionAssignments(minPartitionNum, partitionNum, brokers, _replicationFactor);
360+
List<List<Integer>> newPartitionAssignments =
361+
newPartitionAssignments(requiredMinPartitionNum, currPartitionNum, brokers, _replicationFactor);
348362

349-
NewPartitions newPartitions = NewPartitions.increaseTo(minPartitionNum, newPartitionAssignments);
363+
NewPartitions newPartitions = NewPartitions.increaseTo(requiredMinPartitionNum, newPartitionAssignments);
350364

351-
Map<String, NewPartitions> newPartitionsMap = new HashMap<>();
352-
newPartitionsMap.put(_topic, newPartitions);
353-
CreatePartitionsResult createPartitionsResult = _adminClient.createPartitions(newPartitionsMap);
354-
}
365+
Map<String, NewPartitions> newPartitionsMap = new HashMap<>();
366+
newPartitionsMap.put(_topic, newPartitions);
367+
_adminClient.createPartitions(newPartitionsMap).all().get(_requestTimeout.toMillis(), TimeUnit.MILLISECONDS);
368+
LOGGER.info("{} finished increasing partition of the topic {} in the cluster from {} to {}",
369+
this.getClass().toString(), _topic, currPartitionNum, requiredMinPartitionNum);
355370
}
356371

357372
static List<List<Integer>> newPartitionAssignments(int minPartitionNum, int partitionNum,
@@ -427,8 +442,8 @@ int numPartitions() throws InterruptedException, ExecutionException {
427442

428443
private Set<Node> getAvailableBrokers() throws ExecutionException, InterruptedException {
429444
Set<Node> brokers = new HashSet<>(_adminClient.describeCluster().nodes().get());
430-
Set<Integer> blackListedBrokers = _topicFactory.getBlackListedBrokers(_adminClient);
431-
brokers.removeIf(broker -> blackListedBrokers.contains(broker.id()));
445+
Set<Integer> excludedBrokers = _topicFactory.getExcludedBrokers(_adminClient);
446+
brokers.removeIf(broker -> excludedBrokers.contains(broker.id()));
432447
return brokers;
433448
}
434449

src/main/java/com/linkedin/xinfra/monitor/topicfactory/DefaultTopicFactory.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ public int createTopicIfNotExist(String topic, short replicationFactor, double p
3232
}
3333

3434
@Override
35-
public Set<Integer> getBlackListedBrokers(AdminClient adminClient) {
35+
public Set<Integer> getExcludedBrokers(AdminClient adminClient) {
3636
return Collections.emptySet();
3737
}
3838
}

src/main/java/com/linkedin/xinfra/monitor/topicfactory/TopicFactory.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,6 @@ int createTopicIfNotExist(String topic, short replicationFactor, double partitio
4242
* @param adminClient AdminClient object
4343
* @return A set of brokers that don't take new partitions or reassigned partitions for topics.
4444
*/
45-
Set<Integer> getBlackListedBrokers(AdminClient adminClient);
45+
Set<Integer> getExcludedBrokers(AdminClient adminClient);
4646

4747
}

0 commit comments

Comments
 (0)