Search in sources :

Example 1 with TaskAssignor

use of org.apache.kafka.streams.processor.internals.assignment.TaskAssignor in project kafka by apache.

the class StreamsPartitionAssignor method assignTasksToClients.

/**
 * Assigns a set of tasks to each client (Streams instance) using the configured task assignor, and also
 * populate the stateful tasks that have been assigned to the clients
 * @return true if a probing rebalance should be triggered
 */
private boolean assignTasksToClients(final Cluster fullMetadata, final Set<String> allSourceTopics, final Map<Subtopology, TopicsInfo> topicGroups, final Map<UUID, ClientMetadata> clientMetadataMap, final Map<TaskId, Set<TopicPartition>> partitionsForTask, final Set<TaskId> statefulTasks) {
    if (!statefulTasks.isEmpty()) {
        throw new TaskAssignmentException("The stateful tasks should not be populated before assigning tasks to clients");
    }
    final Map<TopicPartition, TaskId> taskForPartition = new HashMap<>();
    final Map<Subtopology, Set<TaskId>> tasksForTopicGroup = new HashMap<>();
    populateTasksForMaps(taskForPartition, tasksForTopicGroup, allSourceTopics, partitionsForTask, fullMetadata);
    final ChangelogTopics changelogTopics = new ChangelogTopics(internalTopicManager, topicGroups, tasksForTopicGroup, logPrefix);
    changelogTopics.setup();
    final Map<UUID, ClientState> clientStates = new HashMap<>();
    final boolean lagComputationSuccessful = populateClientStatesMap(clientStates, clientMetadataMap, taskForPartition, changelogTopics);
    log.info("All members participating in this rebalance: \n{}.", clientStates.entrySet().stream().map(entry -> entry.getKey() + ": " + entry.getValue().consumers()).collect(Collectors.joining(Utils.NL)));
    final Set<TaskId> allTasks = partitionsForTask.keySet();
    statefulTasks.addAll(changelogTopics.statefulTaskIds());
    log.debug("Assigning tasks {} including stateful {} to clients {} with number of replicas {}", allTasks, statefulTasks, clientStates, numStandbyReplicas());
    final TaskAssignor taskAssignor = createTaskAssignor(lagComputationSuccessful);
    final boolean probingRebalanceNeeded = taskAssignor.assign(clientStates, allTasks, statefulTasks, assignmentConfigs);
    log.info("Assigned tasks {} including stateful {} to clients as: \n{}.", allTasks, statefulTasks, clientStates.entrySet().stream().map(entry -> entry.getKey() + "=" + entry.getValue().currentAssignment()).collect(Collectors.joining(Utils.NL)));
    return probingRebalanceNeeded;
}
Also used : TaskAssignmentException(org.apache.kafka.streams.errors.TaskAssignmentException) ClientState(org.apache.kafka.streams.processor.internals.assignment.ClientState) TaskId(org.apache.kafka.streams.processor.TaskId) SortedSet(java.util.SortedSet) Set(java.util.Set) TreeSet(java.util.TreeSet) HashSet(java.util.HashSet) HashMap(java.util.HashMap) FallbackPriorTaskAssignor(org.apache.kafka.streams.processor.internals.assignment.FallbackPriorTaskAssignor) StickyTaskAssignor(org.apache.kafka.streams.processor.internals.assignment.StickyTaskAssignor) TaskAssignor(org.apache.kafka.streams.processor.internals.assignment.TaskAssignor) TopicPartition(org.apache.kafka.common.TopicPartition) UUID(java.util.UUID) UUID.randomUUID(java.util.UUID.randomUUID) Subtopology(org.apache.kafka.streams.processor.internals.TopologyMetadata.Subtopology)

Example 2 with TaskAssignor

use of org.apache.kafka.streams.processor.internals.assignment.TaskAssignor in project kafka by apache.

the class TaskAssignorIntegrationTest method shouldProperlyConfigureTheAssignor.

@SuppressWarnings("unchecked")
@Test
public void shouldProperlyConfigureTheAssignor() throws NoSuchFieldException, IllegalAccessException {
    // This test uses reflection to check and make sure that all the expected configurations really
    // make it all the way to configure the task assignor. There's no other use case for being able
    // to extract all these fields, so reflection is a good choice until we find that the maintenance
    // burden is too high.
    // 
    // Also note that this is an integration test because so many components have to come together to
    // ensure these configurations wind up where they belong, and any number of future code changes
    // could break this change.
    final String testId = safeUniqueTestName(getClass(), testName);
    final String appId = "appId_" + testId;
    final String inputTopic = "input" + testId;
    IntegrationTestUtils.cleanStateBeforeTest(CLUSTER, inputTopic);
    // Maybe I'm paranoid, but I don't want the compiler deciding that my lambdas are equal to the identity
    // function and defeating my identity check
    final AtomicInteger compilerDefeatingReference = new AtomicInteger(0);
    // the implementation doesn't matter, we're just going to verify the reference.
    final AssignmentListener configuredAssignmentListener = stable -> compilerDefeatingReference.incrementAndGet();
    final Properties properties = mkObjectProperties(mkMap(mkEntry(StreamsConfig.BOOTSTRAP_SERVERS_CONFIG, CLUSTER.bootstrapServers()), mkEntry(StreamsConfig.APPLICATION_ID_CONFIG, appId), mkEntry(StreamsConfig.STATE_DIR_CONFIG, TestUtils.tempDirectory().getPath()), mkEntry(StreamsConfig.NUM_STANDBY_REPLICAS_CONFIG, "5"), mkEntry(StreamsConfig.ACCEPTABLE_RECOVERY_LAG_CONFIG, "6"), mkEntry(StreamsConfig.MAX_WARMUP_REPLICAS_CONFIG, "7"), mkEntry(StreamsConfig.PROBING_REBALANCE_INTERVAL_MS_CONFIG, "480000"), mkEntry(StreamsConfig.InternalConfig.ASSIGNMENT_LISTENER, configuredAssignmentListener), mkEntry(StreamsConfig.InternalConfig.INTERNAL_TASK_ASSIGNOR_CLASS, MyTaskAssignor.class.getName())));
    final StreamsBuilder builder = new StreamsBuilder();
    builder.stream(inputTopic);
    try (final KafkaStreams kafkaStreams = new KafkaStreams(builder.build(), properties)) {
        kafkaStreams.start();
        final Field threads = KafkaStreams.class.getDeclaredField("threads");
        threads.setAccessible(true);
        final List<StreamThread> streamThreads = (List<StreamThread>) threads.get(kafkaStreams);
        final StreamThread streamThread = streamThreads.get(0);
        final Field mainConsumer = StreamThread.class.getDeclaredField("mainConsumer");
        mainConsumer.setAccessible(true);
        final KafkaConsumer<?, ?> consumer = (KafkaConsumer<?, ?>) mainConsumer.get(streamThread);
        final Field assignors = KafkaConsumer.class.getDeclaredField("assignors");
        assignors.setAccessible(true);
        final List<ConsumerPartitionAssignor> consumerPartitionAssignors = (List<ConsumerPartitionAssignor>) assignors.get(consumer);
        final StreamsPartitionAssignor streamsPartitionAssignor = (StreamsPartitionAssignor) consumerPartitionAssignors.get(0);
        final Field assignmentConfigs = StreamsPartitionAssignor.class.getDeclaredField("assignmentConfigs");
        assignmentConfigs.setAccessible(true);
        final AssignorConfiguration.AssignmentConfigs configs = (AssignorConfiguration.AssignmentConfigs) assignmentConfigs.get(streamsPartitionAssignor);
        final Field assignmentListenerField = StreamsPartitionAssignor.class.getDeclaredField("assignmentListener");
        assignmentListenerField.setAccessible(true);
        final AssignmentListener actualAssignmentListener = (AssignmentListener) assignmentListenerField.get(streamsPartitionAssignor);
        final Field taskAssignorSupplierField = StreamsPartitionAssignor.class.getDeclaredField("taskAssignorSupplier");
        taskAssignorSupplierField.setAccessible(true);
        final Supplier<TaskAssignor> taskAssignorSupplier = (Supplier<TaskAssignor>) taskAssignorSupplierField.get(streamsPartitionAssignor);
        final TaskAssignor taskAssignor = taskAssignorSupplier.get();
        assertThat(configs.numStandbyReplicas, is(5));
        assertThat(configs.acceptableRecoveryLag, is(6L));
        assertThat(configs.maxWarmupReplicas, is(7));
        assertThat(configs.probingRebalanceIntervalMs, is(480000L));
        assertThat(actualAssignmentListener, sameInstance(configuredAssignmentListener));
        assertThat(taskAssignor, instanceOf(MyTaskAssignor.class));
    }
}
Also used : StreamsConfig(org.apache.kafka.streams.StreamsConfig) BeforeClass(org.junit.BeforeClass) StreamsPartitionAssignor(org.apache.kafka.streams.processor.internals.StreamsPartitionAssignor) IntegrationTest(org.apache.kafka.test.IntegrationTest) AssignmentListener(org.apache.kafka.streams.processor.internals.assignment.AssignorConfiguration.AssignmentListener) Supplier(java.util.function.Supplier) Utils.mkMap(org.apache.kafka.common.utils.Utils.mkMap) IntegrationTestUtils.safeUniqueTestName(org.apache.kafka.streams.integration.utils.IntegrationTestUtils.safeUniqueTestName) EmbeddedKafkaCluster(org.apache.kafka.streams.integration.utils.EmbeddedKafkaCluster) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) TestName(org.junit.rules.TestName) MatcherAssert.assertThat(org.hamcrest.MatcherAssert.assertThat) HighAvailabilityTaskAssignor(org.apache.kafka.streams.processor.internals.assignment.HighAvailabilityTaskAssignor) ConsumerPartitionAssignor(org.apache.kafka.clients.consumer.ConsumerPartitionAssignor) StreamsBuilder(org.apache.kafka.streams.StreamsBuilder) AfterClass(org.junit.AfterClass) Properties(java.util.Properties) StreamThread(org.apache.kafka.streams.processor.internals.StreamThread) TestUtils(org.apache.kafka.test.TestUtils) Utils.mkObjectProperties(org.apache.kafka.common.utils.Utils.mkObjectProperties) Test(org.junit.Test) IOException(java.io.IOException) Category(org.junit.experimental.categories.Category) Field(java.lang.reflect.Field) AssignorConfiguration(org.apache.kafka.streams.processor.internals.assignment.AssignorConfiguration) Matchers.instanceOf(org.hamcrest.Matchers.instanceOf) IntegrationTestUtils(org.apache.kafka.streams.integration.utils.IntegrationTestUtils) List(java.util.List) Rule(org.junit.Rule) Utils.mkEntry(org.apache.kafka.common.utils.Utils.mkEntry) Matchers.sameInstance(org.hamcrest.Matchers.sameInstance) TaskAssignor(org.apache.kafka.streams.processor.internals.assignment.TaskAssignor) Matchers.is(org.hamcrest.Matchers.is) KafkaStreams(org.apache.kafka.streams.KafkaStreams) KafkaConsumer(org.apache.kafka.clients.consumer.KafkaConsumer) KafkaStreams(org.apache.kafka.streams.KafkaStreams) StreamThread(org.apache.kafka.streams.processor.internals.StreamThread) StreamsPartitionAssignor(org.apache.kafka.streams.processor.internals.StreamsPartitionAssignor) KafkaConsumer(org.apache.kafka.clients.consumer.KafkaConsumer) AssignmentListener(org.apache.kafka.streams.processor.internals.assignment.AssignorConfiguration.AssignmentListener) Properties(java.util.Properties) Utils.mkObjectProperties(org.apache.kafka.common.utils.Utils.mkObjectProperties) AssignorConfiguration(org.apache.kafka.streams.processor.internals.assignment.AssignorConfiguration) HighAvailabilityTaskAssignor(org.apache.kafka.streams.processor.internals.assignment.HighAvailabilityTaskAssignor) TaskAssignor(org.apache.kafka.streams.processor.internals.assignment.TaskAssignor) StreamsBuilder(org.apache.kafka.streams.StreamsBuilder) Field(java.lang.reflect.Field) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) List(java.util.List) Supplier(java.util.function.Supplier) ConsumerPartitionAssignor(org.apache.kafka.clients.consumer.ConsumerPartitionAssignor) IntegrationTest(org.apache.kafka.test.IntegrationTest) Test(org.junit.Test)

Aggregations

TaskAssignor (org.apache.kafka.streams.processor.internals.assignment.TaskAssignor)2 IOException (java.io.IOException)1 Field (java.lang.reflect.Field)1 HashMap (java.util.HashMap)1 HashSet (java.util.HashSet)1 List (java.util.List)1 Properties (java.util.Properties)1 Set (java.util.Set)1 SortedSet (java.util.SortedSet)1 TreeSet (java.util.TreeSet)1 UUID (java.util.UUID)1 UUID.randomUUID (java.util.UUID.randomUUID)1 AtomicInteger (java.util.concurrent.atomic.AtomicInteger)1 Supplier (java.util.function.Supplier)1 ConsumerPartitionAssignor (org.apache.kafka.clients.consumer.ConsumerPartitionAssignor)1 KafkaConsumer (org.apache.kafka.clients.consumer.KafkaConsumer)1 TopicPartition (org.apache.kafka.common.TopicPartition)1 Utils.mkEntry (org.apache.kafka.common.utils.Utils.mkEntry)1 Utils.mkMap (org.apache.kafka.common.utils.Utils.mkMap)1 Utils.mkObjectProperties (org.apache.kafka.common.utils.Utils.mkObjectProperties)1