View a markdown version of this page

Développez les consommateurs avec KCL en Java - Amazon Kinesis Data Streams

Les traductions sont fournies par des outils de traduction automatique. En cas de conflit entre le contenu d'une traduction et celui de la version originale en anglais, la version anglaise prévaudra.

Développez les consommateurs avec KCL en Java

Conditions préalables

Avant de commencer à utiliser KCL 3.x, assurez-vous que vous disposez des éléments suivants :

  • Kit de développement Java (JDK) 8 ou version ultérieure

  • AWS SDK pour Java 2. x

  • Maven ou Gradle pour la gestion des dépendances

KCL collecte des mesures d'utilisation du processeur, telles que l'utilisation du processeur, auprès de l'hôte de calcul sur lequel les travailleurs s'exécutent afin d'équilibrer la charge et d'atteindre un niveau d'utilisation des ressources uniforme entre les travailleurs. Pour permettre à KCL de collecter des mesures d'utilisation du processeur auprès des travailleurs, vous devez remplir les conditions préalables suivantes :

Amazon Elastic Compute Cloud(Amazon EC2)

  • Votre système d'exploitation doit être un système d'exploitation Linux.

  • Vous devez activer IMDSv2 dans votre instance EC2.

Amazon Elastic Container Service (Amazon ECS) sur Amazon EC2

  • Votre système d'exploitation doit être un système d'exploitation Linux.

  • Vous devez activer la version 4 du point de terminaison des métadonnées des tâches ECS.

  • La version de votre agent de conteneur Amazon ECS doit être 1.39.0 ou ultérieure.

Amazon ECS sur AWS Fargate

  • Vous devez activer la version 4 du point de terminaison des métadonnées des tâches Fargate. Si vous utilisez la version 1.4.0 ou ultérieure de la plateforme Fargate, cette option est activée par défaut.

  • Plateforme Fargate version 1.4.0 ou ultérieure.

Amazon Elastic Kubernetes Service (Amazon EKS) sur Amazon EC2

  • Votre système d'exploitation doit être un système d'exploitation Linux.

Amazon EKS sur AWS Fargate

  • Plateforme Fargate 1.3.0 ou version ultérieure.

Important

Si KCL ne peut pas collecter les mesures d'utilisation du processeur auprès des employés, KCL utilisera à nouveau le débit par travailleur pour attribuer des contrats de location et équilibrer la charge entre les employés de la flotte. Pour de plus amples informations, veuillez consulter Comment KCL attribue des baux aux travailleurs et équilibre la charge.

Installation et ajout de dépendances

Si vous utilisez Maven, ajoutez la dépendance suivante à votre pom.xml fichier. Assurez-vous d'avoir remplacé 3.x.x par la dernière version de KCL.

<dependency> <groupId>software.amazon.kinesis</groupId> <artifactId>amazon-kinesis-client</artifactId> <version>3.x.x</version> <!-- Use the latest version --> </dependency>

Si vous utilisez Gradle, ajoutez ce qui suit à votre build.gradle fichier. Assurez-vous d'avoir remplacé 3.x.x par la dernière version de KCL.

implementation 'software.amazon.kinesis:amazon-kinesis-client:3.x.x'

Vous pouvez rechercher la dernière version de la KCL sur le référentiel central de Maven.

Mettre en œuvre le consommateur

Une application grand public KCL comprend les éléments clés suivants :

RecordProcessor

RecordProcessor est le composant central où réside votre logique métier pour le traitement des enregistrements de flux de données Kinesis. Il définit la manière dont votre application traite les données qu'elle reçoit du flux Kinesis.

Principales responsabilités :

  • Initialiser le traitement d'un fragment

  • Traitez des lots d'enregistrements à partir du flux Kinesis

  • Arrêter le traitement d'un fragment (par exemple, lorsque le fragment est scindé ou fusionné, ou que le bail est transféré à un autre hôte)

  • Gérez les points de contrôle pour suivre les progrès

Voici un exemple de mise en œuvre :

import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.slf4j.MDC; import software.amazon.kinesis.exceptions.InvalidStateException; import software.amazon.kinesis.exceptions.ShutdownException; import software.amazon.kinesis.lifecycle.events.*; import software.amazon.kinesis.processor.ShardRecordProcessor; public class SampleRecordProcessor implements ShardRecordProcessor { private static final String SHARD_ID_MDC_KEY = "ShardId"; private static final Logger log = LoggerFactory.getLogger(SampleRecordProcessor.class); private String shardId; @Override public void initialize(InitializationInput initializationInput) { shardId = initializationInput.shardId(); MDC.put(SHARD_ID_MDC_KEY, shardId); try { log.info("Initializing @ Sequence: {}", initializationInput.extendedSequenceNumber()); } finally { MDC.remove(SHARD_ID_MDC_KEY); } } @Override public void processRecords(ProcessRecordsInput processRecordsInput) { MDC.put(SHARD_ID_MDC_KEY, shardId); try { log.info("Processing {} record(s)", processRecordsInput.records().size()); processRecordsInput.records().forEach(r -> log.info("Processing record pk: {} -- Seq: {}", r.partitionKey(), r.sequenceNumber()) ); // Checkpoint periodically processRecordsInput.checkpointer().checkpoint(); } catch (Throwable t) { log.error("Caught throwable while processing records. Aborting.", t); } finally { MDC.remove(SHARD_ID_MDC_KEY); } } @Override public void leaseLost(LeaseLostInput leaseLostInput) { MDC.put(SHARD_ID_MDC_KEY, shardId); try { log.info("Lost lease, so terminating."); } finally { MDC.remove(SHARD_ID_MDC_KEY); } } @Override public void shardEnded(ShardEndedInput shardEndedInput) { MDC.put(SHARD_ID_MDC_KEY, shardId); try { log.info("Reached shard end checkpointing."); shardEndedInput.checkpointer().checkpoint(); } catch (ShutdownException | InvalidStateException e) { log.error("Exception while checkpointing at shard end. Giving up.", e); } finally { MDC.remove(SHARD_ID_MDC_KEY); } } @Override public void shutdownRequested(ShutdownRequestedInput shutdownRequestedInput) { MDC.put(SHARD_ID_MDC_KEY, shardId); try { log.info("Scheduler is shutting down, checkpointing."); shutdownRequestedInput.checkpointer().checkpoint(); } catch (ShutdownException | InvalidStateException e) { log.error("Exception while checkpointing at requested shutdown. Giving up.", e); } finally { MDC.remove(SHARD_ID_MDC_KEY); } } }

Voici une explication détaillée de chaque méthode utilisée dans l'exemple :

initialiser (InitializationInputInitializationInput)

  • Objectif : Mettre en place toutes les ressources ou tous les états nécessaires au traitement des enregistrements.

  • Quand il est appelé : Une fois, lorsque KCL attribue une partition à ce processeur d'enregistrement.

  • Points clés :

    • initializationInput.shardId(): ID de la partition que ce processeur va gérer.

    • initializationInput.extendedSequenceNumber(): numéro de séquence à partir duquel démarrer le traitement.

ProcessRecords (ProcessRecordsInputprocessusRecordsInput)

  • Objectif : traiter les enregistrements entrants et éventuellement la progression des points de contrôle.

  • Quand il est appelé : à plusieurs reprises, tant que le processeur d'enregistrement détient le bail du fragment.

  • Points clés :

    • processRecordsInput.records(): Liste des enregistrements à traiter.

    • processRecordsInput.checkpointer(): Utilisé pour contrôler la progression.

    • Assurez-vous que vous avez géré toutes les exceptions pendant le traitement pour empêcher KCL d'échouer.

    • Cette méthode doit être idempotente, car le même enregistrement peut être traité plusieurs fois dans certains scénarios, tels que des données qui n'ont pas été vérifiées avant un arrêt ou un redémarrage inattendu d'un travailleur.

    • Videz toujours toutes les données mises en mémoire tampon avant le point de contrôle afin de garantir la cohérence des données.

LeaseLost (bail) LeaseLostInput LostInput

  • Objectif : Nettoyez toutes les ressources spécifiques au traitement de ce fragment.

  • Quand il s'appelle : Lorsqu'un autre planificateur prend en charge le bail de ce fragment.

  • Points clés :

    • Les points de contrôle ne sont pas autorisés dans cette méthode.

ShardEnded (fragment) ShardEndedInput EndedInput

  • Objectif : terminer le traitement de ce fragment et de ce point de contrôle.

  • Quand il est appelé : lorsque la partition se divise ou fusionne, cela indique que toutes les données de cette partition ont été traitées.

  • Points clés :

    • shardEndedInput.checkpointer(): Utilisé pour effectuer le dernier point de contrôle.

    • Le pointage de contrôle dans cette méthode est obligatoire pour terminer le traitement.

    • Si vous ne videz pas les données et le point de contrôle ici, vous risquez de perdre des données ou de dupliquer le traitement lors de la réouverture de la partition.

Arrêt demandé (arrêt) ShutdownRequestedInput RequestedInput

  • Objectif : Contrôlez et nettoyez les ressources lorsque KCL s'arrête.

  • Quand il est appelé : lorsque KCL s'arrête (par exemple, lorsque l'application se termine).

  • Points clés :

    • shutdownRequestedInput.checkpointer(): Utilisé pour effectuer des points de contrôle avant l'arrêt.

    • Assurez-vous d'avoir implémenté le point de contrôle dans la méthode afin que la progression soit enregistrée avant l'arrêt de l'application.

    • Le fait de ne pas vider les données et de placer le point de contrôle ici peut entraîner une perte de données ou le retraitement des enregistrements au redémarrage de l'application.

Important

KCL 3.x réduit le retraitement des données lorsque le bail est transféré d'un travailleur à un autre travailleur en effectuant un point de contrôle avant que le travailleur précédent ne soit arrêté. Si vous n'implémentez pas la logique de point de contrôle dans la shutdownRequested() méthode, vous ne bénéficierez pas de cet avantage. Assurez-vous d'avoir implémenté une logique de point de contrôle dans la shutdownRequested() méthode.

RecordProcessorFactory

RecordProcessorFactory est responsable de la création de nouvelles RecordProcessor instances. KCL utilise cette fabrique pour créer une nouvelle partition RecordProcessor pour chaque partition que l'application doit traiter.

Principales responsabilités :

  • Créez de nouvelles RecordProcessor instances à la demande

  • Assurez-vous que chacun RecordProcessor est correctement initialisé

Voici un exemple de mise en œuvre :

import software.amazon.kinesis.processor.ShardRecordProcessor; import software.amazon.kinesis.processor.ShardRecordProcessorFactory; public class SampleRecordProcessorFactory implements ShardRecordProcessorFactory { @Override public ShardRecordProcessor shardRecordProcessor() { return new SampleRecordProcessor(); } }

Dans cet exemple, l'usine en crée un nouveau SampleRecordProcessor chaque fois que shard RecordProcessor () est appelé. Vous pouvez l'étendre pour inclure toute logique d'initialisation nécessaire.

Planificateur

Le planificateur est un composant de haut niveau qui coordonne toutes les activités de l'application KCL. Il est responsable de l'orchestration globale du traitement des données.

Principales responsabilités :

  • Gérez le cycle de vie de RecordProcessors

  • Gérer la gestion des baux pour les fragments

  • Coordonner le point de contrôle

  • Équilibrez la charge de traitement des partitions entre les différents employés de votre application

  • Gérez les signaux d'arrêt et de fin d'application en douceur

Le planificateur est généralement créé et démarré dans l'application principale. Vous pouvez consulter l'exemple d'implémentation de Scheduler dans la section suivante, Application principale du consommateur.

Principale application destinée aux consommateurs

L'application principale pour les consommateurs relie tous les composants ensemble. Il est chargé de configurer le consommateur KCL, de créer les clients nécessaires, de configurer le planificateur et de gérer le cycle de vie de l'application.

Principales responsabilités :

  • Configuration des clients AWS de service (Kinesis, DynamoDB,) CloudWatch

  • Configuration de l'application KCL

  • Créez et démarrez le planificateur

  • Gérer l'arrêt de l'application

Voici un exemple de mise en œuvre :

import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.services.cloudwatch.CloudWatchAsyncClient; import software.amazon.awssdk.services.dynamodb.DynamoDbAsyncClient; import software.amazon.awssdk.services.kinesis.KinesisAsyncClient; import software.amazon.kinesis.common.ConfigsBuilder; import software.amazon.kinesis.common.KinesisClientUtil; import software.amazon.kinesis.coordinator.Scheduler; import java.util.UUID; public class SampleConsumer { private final String streamName; private final Region region; private final KinesisAsyncClient kinesisClient; public SampleConsumer(String streamName, Region region) { this.streamName = streamName; this.region = region; this.kinesisClient = KinesisClientUtil.createKinesisAsyncClient(KinesisAsyncClient.builder().region(this.region)); } public void run() { DynamoDbAsyncClient dynamoDbAsyncClient = DynamoDbAsyncClient.builder().region(region).build(); CloudWatchAsyncClient cloudWatchClient = CloudWatchAsyncClient.builder().region(region).build(); ConfigsBuilder configsBuilder = new ConfigsBuilder( streamName, streamName, kinesisClient, dynamoDbAsyncClient, cloudWatchClient, UUID.randomUUID().toString(), new SampleRecordProcessorFactory() ); Scheduler scheduler = new Scheduler( configsBuilder.checkpointConfig(), configsBuilder.coordinatorConfig(), configsBuilder.leaseManagementConfig(), configsBuilder.lifecycleConfig(), configsBuilder.metricsConfig(), configsBuilder.processorConfig(), configsBuilder.retrievalConfig() ); Thread schedulerThread = new Thread(scheduler); schedulerThread.setDaemon(true); schedulerThread.start(); } public static void main(String[] args) { String streamName = "your-stream-name"; // replace with your stream name Region region = Region.US_EAST_1; // replace with your region new SampleConsumer(streamName, region).run(); } }

KCL crée un consommateur amélioré Fan-out (EFO) avec un débit dédié par défaut. Pour plus d'informations sur Enhanced Fan-out, consultezDéveloppez des clients fans améliorés grâce à un débit dédié. Si vous avez moins de 2 consommateurs ou si vous n'avez pas besoin de délais de propagation de lecture inférieurs à 200 ms, vous devez définir la configuration suivante dans l'objet planificateur pour utiliser des consommateurs à débit partagé :

configsBuilder.retrievalConfig().retrievalSpecificConfig(new PollingConfig(streamName, kinesisClient))

Le code suivant est un exemple de création d'un objet planificateur qui utilise des consommateurs à débit partagé :

Importations  :

import software.amazon.kinesis.retrieval.polling.PollingConfig;

Code  :

Scheduler scheduler = new Scheduler( configsBuilder.checkpointConfig(), configsBuilder.coordinatorConfig(), configsBuilder.leaseManagementConfig(), configsBuilder.lifecycleConfig(), configsBuilder.metricsConfig(), configsBuilder.processorConfig(), configsBuilder.retrievalConfig().retrievalSpecificConfig(new PollingConfig(streamName, kinesisClient)) );/