Apache Flink sur K8s et Kafka : PyFlink, Go, opérations et tarification gérée

Streaming avec état, points de contrôle, K8s, PyFlink, Go.

Sommaire

Apache Flink est un cadre pour les calculs à état sur des flux de données bornés et non bornés.

Les équipes l’adoptent pour un streaming correct et à faible latence avec une sémantique de temps d’événement (repères d’eau), une tolérance aux pannes (points de contrôle), des mises à niveau contrôlées (points de sauvegarde) et des surfaces opérationnelles (métriques et REST).

Traitement de flux Apache Flink

Ce guide s’adresse aux équipes DevOps et aux développeurs Go/Python. Il compare les modèles de déploiement (autogérés vs gérés), explique l’architecture de base, couvre les configurations Kubernetes (Helm et Opérateur) et autonomes, oppose Flink à Spark, Kafka Streams, Beam et aux bases de données de streaming, et présente des modèles d’intégration PyFlink et Go, y compris les pipelines orientés LLM et IA.

Pour un contexte plus large sur les modèles d’infrastructure de données, incluant le stockage d’objets, les bases de données et la messagerie, consultez Infrastructure de données pour les systèmes d’IA : Stockage d’objets, Bases de données, Recherche & Architecture de données IA.

Apache Flink est explicitement positionné comme un moteur de traitement de flux à état : vous modélisez votre logique sous forme de pipeline d’opérateurs et Flink l’exécute comme un flux de données distribué avec un état géré et une sémantique temporelle. Dans la documentation moderne de Flink, le projet se décrit comme un cadre et un moteur de traitement distribué pour des calculs à état sur des flux de données bornés et non bornés.

D’un point de vue pratique DevOps/ingénierie logicielle, Flink est un bon choix lorsque vous avez besoin d’au moins l’une de ces propriétés :

Si vous avez besoin de jointures/agrégats/enrichissements à faible latence avec des garanties de correction, vous utilisez généralement le traitement de temps d’événement de Flink, où le « temps » correspond au moment où l’événement s’est produit (et non à son arrivée), et les repères d’eau communiquent la progression du temps d’événement dans le pipeline.

Si vous avez besoin de calculs à état à grande échelle (compteurs roulants, sessions, règles de fraude, ingénierie de caractéristiques), Flink traite l’état comme une partie de premier plan du modèle de programmation et le rend tolérant aux pannes via le pointage de contrôle (checkpointing).

Si vous avez besoin d’un streaming opérationnellement robuste (pannes, mises à niveau progressives, redémarrages), Flink pointe l’état et les positions de flux afin que le job puisse récupérer et continuer avec la même sémantique « comme une exécution sans défaillance ».

Cas d’utilisation typiques pour les équipes DevOps, Go, Python et IA

Flink est largement utilisé pour les « pipelines de données & ETL », l’« analyse en streaming » et les « applications pilotées par des événements » (les catégories utilisées par la documentation de Flink).

Pour une pile DevOps + Go/Python, les modèles typiques ressemblent à ceci :

Un service Go produit des événements vers Kafka ; Flink consomme ces événements, effectue un traitement à état (par exemple, déduplication, agrégation fenêtrée, enrichissement), puis écrit des faits dérivés vers Kafka ou une base de données. Les mécanismes d’opérateurs et de pointage de contrôle de Flink existent pour rendre ces pipelines à état sûrs pour la production.

Pour les équipes ML/LLM, PyFlink cite explicitement des scénarios comme la « prédiction d’apprentissage automatique » et le chargement de modèles d’apprentissage automatique dans des UDF Python comme motivation de gestion des dépendances, ce qui constitue un soutien direct aux modèles de « job Flink comme runtime d’inférence en ligne / ingénierie de caractéristiques ».

Le runtime de Flink comprend deux types de processus : JobManager et TaskManagers. La documentation insiste sur le fait que les clients soumettent le flux de données au JobManager ; le client peut ensuite se déconnecter (mode détaché) ou rester connecté (mode attaché).

Le JobManager coordonne l’exécution distribuée : planification, réaction à la finalisation/échec des tâches, coordination des points de contrôle et coordination de la récupération. En interne, il comprend : ResourceManager (slots/ressources), Dispatcher (REST + Interface Web + création de JobMaster par job) et JobMaster (gère un job).

Les TaskManagers exécutent les opérateurs/tâches et échangent/tamponnent les flux de données. L’unité de planification la plus petite est le slot de tâche ; plusieurs opérateurs peuvent s’exécuter dans un seul slot (le chaînage d’opérateurs et le partage de slots affectent ceci).

Chaînage d’opérateurs et slots de tâches pour le contrôle des performances et des coûts

Flink enchaîne les sous-tâches d’opérateurs en tâches, où chaque tâche est exécutée par un seul thread. Cela est décrit comme une optimisation de performance qui réduit la surcharge de transfert de thread et de tamponnage, augmentant le débit et diminuant la latence.

Les slots sont importants opérationnellement car ils sont l’unité de planification/isolation des ressources. Flink note que chaque TaskManager peut avoir un ou plusieurs slots de tâche ; l’allocation réserve une mémoire gérée par slot, mais n’isole pas le CPU.

Traitement du temps d’événement, repères d’eau et données en retard

Flink prend en charge plusieurs notions de temps — temps d’événement, temps d’ingestion, temps de traitement — et utilise des repères d’eau pour modéliser la progression dans le temps d’événement.

Pour travailler avec le temps d’événement, Flink a besoin de timestamps attribués aux événements et de repères d’eau générés ; la documentation officielle « Génération de repères d’eau » explique l’attribution de timestamps et la génération de repères d’eau comme les blocs de construction principaux, avec WatermarkStrategy étant la méthode standard pour configurer des stratégies courantes.

Tolérance aux pannes : points de contrôle versus points de sauvegarde dans les systèmes réels

Le pointage de contrôle existe car « chaque fonction et opérateur dans Flink peut être à état » ; l’état doit être pointé pour devenir tolérant aux pannes. Les points de contrôle permettent la récupération de l’état et des positions de flux afin que l’exécution puisse reprendre avec une sémantique sans défaillance.

Flink est très explicite sur le fait que les points de sauvegarde (savepoints) sont « une image cohérente de l’état d’exécution d’un job de streaming, créée via le mécanisme de pointage de contrôle de Flink », utilisée pour arrêter/reprendre, fourcher ou mettre à jour des jobs. Les points de sauvegarde vivent sur un stockage stable (par exemple, HDFS, S3).

La page officielle « Points de contrôle vs Points de sauvegarde » présente la différence comme des sauvegardes vs journaux de récupération : les points de contrôle sont fréquents, légers, gérés par Flink pour la récupération après défaillance ; les points de sauvegarde sont gérés par l’utilisateur et utilisés pour des opérations contrôlées comme les mises à niveau.

Le runtime Flink open-source est « gratuit » au sens de la licence, mais en production, vous payez pour l’infrastructure et l’effort opérationnel.

Flink est conçu pour s’intégrer avec des gestionnaires de ressources courants (par exemple, YARN et Kubernetes) et peut également fonctionner comme un cluster autonome ou comme une bibliothèque.

Les coûts de calcul et de mémoire sont pilotés par le JobManager et les TaskManagers, ainsi que par votre disposition de parallélisme/slots. La documentation de configuration de Flink cite explicitement jobmanager.memory.process.size, taskmanager.memory.process.size, taskmanager.numberOfTaskSlots et parallelism.default comme les paramètres clés pour les configurations distribuées.

Le disque local est un coût caché fréquent pour les jobs à état. Flink note que io.tmp.dirs stocke des données locales incluant les fichiers RocksDB, les résultats intermédiaires déversés et les JARs mis en cache ; si ces données sont supprimées, cela peut forcer « une opération de récupération lourde », il doit donc vivre sur un stockage qui n’est pas purgé périodiquement.

Le coût du stockage d’objets/fichiers durable est piloté par les répertoires de points de contrôle/points de sauvegarde. Dans la configuration Flink 2.x, les points de contrôle et les points de sauvegarde sont configurés via execution.checkpointing.dir et execution.checkpointing.savepoint-dir et acceptent des URI comme s3://… ou hdfs://….

Les services gérés réduisent le coût opérationnel mais ajoutent des frais de plateforme et des contraintes. Les spécificités dépendent du fournisseur.

Amazon Managed Service for Apache Flink facture par KPU (1 vCPU + 4 Go de mémoire par KPU) et facture par durée et nombre de KPU par incréments d’une seconde. AWS facture également une KPU supplémentaire « d’orchestration » par application et des frais de stockage/sauvegarde séparés.

Confluent Cloud for Apache Flink est basé sur l’utilisation et serverless : vous créez une pool de calcul, et vous êtes facturé pour les CFU consommés par minute pendant que les déclarations s’exécutent. La page de facturation inclut un exemple de prix de CFU de 0,21 $ par CFU-heure (selon la région) et insiste sur le fait que vous pouvez limiter les dépenses via des maximums de pool de calcul.

Aiven et Alibaba Cloud sont des fournisseurs de Flink gérés notables sur le marché, mais leurs détails de prix et de facturation publics varient selon le plan/région et peuvent nécessiter des calculateurs ou un contact commercial ; considérez les coûts exacts comme non spécifiés sauf si vous citez une région+plan de leurs documents actuels.

Ververica offre à la fois des options de déploiement autogérés et gérés autour de Flink ; les pages publiques mettent l’accent sur les choix de déploiement et le positionnement du service géré, tandis que la tarification exacte est généralement traitée via des flux « contact/détails de prix » (donc les chiffres spécifiques sont souvent non spécifiés publiquement).

Option de déploiement Idéal pour Complexité opérationnelle Avantages clés Risques / compromis clés
Cluster autonome (VMs/métal nu) Petites équipes, capacité fixe Moyenne–Élevée Contrôle total ; modèle mental le plus simple HA, autoscaling, mises à niveau sont DIY (plus de travail manuel)
Kubernetes avec l’Opérateur Kubernetes Flink La plupart des équipes de plateforme modernes Moyenne Déploiements déclaratifs ; gestion du cycle de vie via boucle de contrôle ; l’opérateur prend en charge les déploiements Application/Session/Job Expertise Kubernetes + opérateur requise
Kubernetes natif (sans opérateur) Équipes K8s souhaitant une intégration directe Moyenne–Élevée Intégration directe des ressources ; allocation/désallocation dynamique de TaskManager décrite dans les docs Flink-on-K8s Automatisation plus sur mesure que l’opérateur
YARN Plateformes centrées sur Hadoop Moyenne Intégration avec la gestion de ressources YARN Complexité de la stack Hadoop
AWS Managed Service for Apache Flink Stacks de données natives AWS Basse–Moyenne Orchestration gérée + options de mise à l’échelle ; unité de facturation prévisible (KPU) Couplage à la plateforme ; frais KPU supplémentaires par app + frais de stockage
Confluent Cloud for Apache Flink Shops premiers Kafka, apps de streaming SQL-first Basse Facturation d’utilisation serverless ; comptabilité CFU-minute ; pools de calcul pour plafonner les dépenses Coûts CFU + coûts de réseau Kafka ; APIs spécifiques au service
Offres gérées Ververica Entreprises nécessitant une expertise Flink opérationnelle Basse–Moyenne Positionnement de service géré « experts Flink » Tarification souvent non transparente (non spécifiée)

Tableau des fournisseurs gérés et des coûts

Les prix changent selon la région et le temps ; si vous avez besoin de chiffres exacts pour votre région, considérez ceci comme un point de départ et vérifiez auprès des pages de prix actuelles du fournisseur (les régions non citées sont non spécifiées).

Fournisseur Forme de « Plan » Unité de facturation Exemple de prix de calcul Facteurs de coût supplémentaires notables
Amazon Managed Service for Apache Flink Runtime géré KPU (1 vCPU + 4 Go) Exemple affiché : 0,11 $ par KPU-heure (US Est Virginie du Nord) +1 KPU d’orchestration par app ; stockage en cours d’exécution ; sauvegardes durables optionnelles
Confluent Cloud for Apache Flink SQL/traitements serverless CFU-minute/CFU-heure Exemple affiché : 0,21 $ par CFU-heure (la région varie) Les taux de réseau Kafka s’appliquent toujours ; max de pool de calcul pour plafonner les dépenses
Ververica (géré) « Unified Streaming Data Platform » géré Non spécifié (pages publiques) Non spécifié Fonctionnalités de plateforme/SLA ; tarification généralement via ventes (non spécifiée)
Aiven for Apache Flink Service géré Modèle de facturation à l’heure (plateforme globale) Non spécifié sans plan/région Niveau de plan + région cloud + add-ons (non spécifiés)
Alibaba Cloud Realtime Compute for Apache Flink Géré/serverless Facturation hybride (pay-as-you-go + mix d’abonnement) Non spécifié sans détails de région/workspace Limites basées sur CU et modèle de workspace (détails varient ; non spécifiés ici)

Flink se situe dans un écosystème animé. Le « meilleur » choix dépend de la latence, de l’état, des préférences opérationnelles et du modèle d’auteur.

Outil Ce que c’est Modèle d’exécution de streaming Histoire de l’état et exactement-une-fois Où il brille Points de douleur typiques
Apache Flink Moteur de traitement de flux distribué pour des calculs à état Streaming continu + temps d’événement via repères d’eau Tolérance aux pannes basée sur les points de contrôle ; points de sauvegarde pour mises à niveau contrôlées Pipelines à état à faible latence ; logique de temps d’événement complexe Opérer l’état, les points de contrôle et les mises à niveau correctement demande de la discipline
Apache Spark Structured Streaming Moteur de streaming de Spark construit autour des DataFrames/Datasets Modèle micro-lot par défaut (avec un mode continu discuté séparément) Fort pour les pipelines analytiques ; l’état existe mais souvent à latence plus élevée API unifiées lot+stream ; écosystème Spark Latence micro-lot et modèle mental « streaming comme lots incrémentaux »
Kafka Streams Bibliothèque pour créer des apps de traitement de flux sur Kafka Traitement enregistrement-par-enregistrement Prend en charge la sémantique de traitement exactement-une-fois (EOS) Apps natives Kafka simples ; intégré dans un service JVM JVM-only ; moins flexible pour les modèles de calcul distribué à grande échelle
Apache Beam Modèle de programmation unifié + SDKs ; exécuté via runners (Flink, Spark, Dataflow, etc.) Dépend du runner ; les pipelines Beam se traduisent en jobs de runner La sémantique dépend de la matrice de capacité du runner (spécifique au runner) Portabilité, pipelines multi-langages ; éviter le verrouillage d’engine L’ajustement opérationnel finit par être spécifique au runner
Materialize « Couche de données en direct » / DB SQL de streaming ; met à jour les résultats de manière incrémentielle à mesure que les données arrivent Maintenance continue de vues incrémentielles Revendications de forte cohérence dans les docs produit (détails spécifiques au produit) Servir des vues dérivées fraîches aux apps/agents IA Modèle opérationnel différent des jobs Flink ; pas un runtime d’API d’opérateur général
RisingWave Base de données de streaming où le traitement de flux s’exprime comme des vues matérialisées Maintenance continue de vues matérialisées SQL-first ; sémantique spécifique au moteur Apps de streaming centrées SQL sans construire des jobs Flink Moins flexible pour les pipelines lourds de code arbitraires

Une heuristique utile : si vous voulez un runtime pour des jobs de streaming à état complexes avec un contrôle approfondi du temps d’événement, de la logique d’opérateur et des déploiements, Flink est un candidat principal. Si vous voulez des vues incrémentielles SQL-first pour la prestation, les bases de données de streaming peuvent être des alternatives. Si vous voulez une bibliothèque intégrée dans un service, Kafka Streams est compétitif. Si vous voulez une définition de pipeline portable à travers les engines, Beam est convaincant.

Pour les architectures événementielles natives cloud utilisant AWS, Construire des microservices événementiels avec AWS Kinesis couvre les modèles Kinesis Data Streams pour le traitement en temps réel et le découplage de services.

Cette section est intentionnellement pratique : configuration, déploiement et comment vos services Go/Python interagissent généralement avec Flink.

Services Go + Kafka + Flink + couche de service

Flink est souvent le « milieu à état » qui transforme des événements de haut volume en signaux durables (compteurs, sessions, anomalies, enregistrements enrichis). Les points de contrôle et les backends d’état sont ce qui rend ce milieu fiable en production.

Note importante de version : à partir de Flink 2.0, le fichier de configuration pris en charge est conf/config.yaml ; l’ancien flink-conf.yaml n’est « plus supporté ».

Un conf/config.yaml minimal (illustratif) pour un petit cluster autogéré :

# conf/config.yaml (style Flink 2.x)
rest:
  address: flink-jobmanager.example.internal
  port: 8081

jobmanager:
  rpc:
    address: flink-jobmanager.example.internal
    port: 6123
  memory:
    process:
      size: 2048m

taskmanager:
  memory:
    process:
      size: 4096m
  numberOfTaskSlots: 2

parallelism:
  default: 2

# Défauts de pointage de contrôle (les jobs peuvent encore être écrasés dans le code)
state:
  backend:
    type: rocksdb
execution:
  checkpointing:
    dir: s3://my-bucket/flink/checkpoints
    savepoint-dir: s3://my-bucket/flink/savepoints
    interval: 60 s

# Évitez les répertoires tmp qui sont purgés (fichiers RocksDB, JARs mis en cache, etc.)
io:
  tmp:
    dirs: ["/var/lib/flink/tmp"]

Pourquoi ces clés : la référence de configuration de Flink documente explicitement les détails de découverte rest.* et jobmanager.rpc.*, les clés de mémoire de processus, les clés de slot/parallélisme et les paramètres de pointage de contrôle par défaut incluant state.backend.type, execution.checkpointing.dir, execution.checkpointing.savepoint-dir et execution.checkpointing.interval.

Le choix de io.tmp.dirs est opérationnellement important car Flink l’utilise pour les fichiers locaux RocksDB et les artefacts mis en cache ; sa suppression peut provoquer une récupération lourde.

Si vous êtes sur Flink 1.x (toujours courant dans certains environnements gérés), vous verrez flink-conf.yaml dans la nature. Ceci est legacy pour les utilisateurs de Flink 2.x.

# conf/flink-conf.yaml (style legacy 1.x ; NON supporté dans Flink 2.x)
jobmanager.rpc.address: flink-jobmanager
rest.port: 8081
taskmanager.numberOfTaskSlots: 2
parallelism.default: 2

# Les clés de pointage de contrôle legacy diffèrent selon la version ; considérez comme illustratif.
state.backend.type: rocksdb
state.checkpoints.dir: s3://my-bucket/flink/checkpoints
state.savepoints.dir: s3://my-bucket/flink/savepoints

Si vous migrez, Flink fournit un script de migration (bin/migrate-config-file.sh) pour convertir flink-conf.yaml vers config.yaml.

L’Opérateur Kubernetes Flink agit comme un plan de contrôle pour la gestion du cycle de vie des applications Flink et est installé via Helm.

Selon la documentation Helm officielle de l’opérateur, vous pouvez installer soit depuis le chart de l’arbre source, soit depuis le référentiel de chart hébergé par Apache :

# installer depuis le chart inclus dans l'arbre source
helm install flink-kubernetes-operator helm/flink-kubernetes-operator

# installer depuis le référentiel Helm des téléchargements Apache (remplacer <OPERATOR-VERSION>)
helm repo add flink-operator-repo https://downloads.apache.org/flink/flink-kubernetes-operator-<OPERATOR-VERSION>/
helm install flink-kubernetes-operator flink-operator-repo/flink-kubernetes-operator

Ces commandes exactes sont montrées dans la documentation d’installation Helm de l’opérateur.

Exemple de CR FlinkDeployment (illustratif)

Ceci est un exemple simplifié pour montrer les points d’intégration que vous personnaliserez généralement (image, ressources, emplacements de pointage de contrôle, journalisation/métriques). L’opérateur réconcilie cet état désiré via sa boucle de contrôle.

apiVersion: flink.apache.org/v1beta1
kind: FlinkDeployment
metadata:
  name: realtime-sessions
  namespace: flink
spec:
  image: my-registry.example.com/flink/realtime-sessions:2026-03-06
  flinkVersion: v2_2
  serviceAccount: flink
  flinkConfiguration:
    taskmanager.numberOfTaskSlots: "2"
    state.backend.type: "rocksdb"
    execution.checkpointing.dir: "s3://my-bucket/flink/checkpoints/realtime-sessions"
    execution.checkpointing.savepoint-dir: "s3://my-bucket/flink/savepoints/realtime-sessions"
    execution.checkpointing.interval: "60 s"
    rest.port: "8081"
  jobManager:
    resource:
      cpu: 1
      memory: "2048m"
  taskManager:
    resource:
      cpu: 2
      memory: "4096m"
  job:
    jarURI: local:///opt/flink/usrlib/realtime-sessions.jar
    parallelism: 4
    upgradeMode: savepoint
    state: running

Le motif upgradeMode: savepoint est courant lorsque vous souhaitez des mises à niveau à état sûres ; les points de sauvegarde sont conçus pour des workflows d’arrêt/reprise/fork/mise à jour et pointent vers des emplacements de stockage stables.

PyFlink est l’API Python pour Apache Flink et est explicitement vendu pour des charges de travail lot/stream évolutives incluant des pipelines ML et ETL.

Lorsque vous utilisez des connecteurs JVM (Kafka, JDBC, etc.) depuis PyFlink, vous devez vous assurer que les JARs pertinents sont disponibles pour le job. La documentation Python « Gestion des dépendances » de Flink montre trois mécanismes standards :

Définir pipeline.jars (API Table), appeler add_jars() (API DataStream), ou CLI --jarfile au moment de la soumission.

Cet exemple lit des événements JSON depuis Kafka, attribue des timestamps de temps d’événement (avec un désordre borné), maintient un comptage roulant par utilisateur dans un état clé et écrit un événement enrichi vers un topic de sortie.

Notes :

  • KafkaSource est construit via KafkaSource.builder() et nécessite des serveurs bootstrap, des topics et un désérialiseur.
  • La configuration de sink Kafka exactement-une-fois dans PyFlink nécessite de définir la garantie de livraison et un préfixe d’ID transactionnel.
  • Les défauts de pointage de contrôle peuvent être configurés dans la configuration Flink (execution.checkpointing.*) et/ou dans le code ; les clés de configuration sont documentées dans la référence de configuration Flink.
import json
from typing import Any

from pyflink.common import Duration, Types
from pyflink.common.serialization import SimpleStringSchema
from pyflink.common.watermark_strategy import WatermarkStrategy, TimestampAssigner
from pyflink.common.configuration import Configuration

from pyflink.datastream import StreamExecutionEnvironment
from pyflink.datastream.functions import KeyedProcessFunction, RuntimeContext
from pyflink.datastream.state import ValueStateDescriptor

from pyflink.datastream.connectors import DeliveryGuarantee
from pyflink.datastream.connectors.kafka import (
    KafkaSource,
    KafkaOffsetsInitializer,
    KafkaSink,
    KafkaRecordSerializationSchema,
)


class EventTimeFromJson(TimestampAssigner):
    """
    Extraire event_time_ms du payload JSON.
    Attendre : {"user_id":"u1","event_time_ms":1710000000000,"event":"click",...}
    """
    def extract_timestamp(self, value: str, record_timestamp: int) -> int:
        try:
            obj = json.loads(value)
            return int(obj["event_time_ms"])
        except Exception:
            # repli : utiliser le timestamp de l'enregistrement (ingestion) si malformé
            return record_timestamp


class RollingCount(KeyedProcessFunction):
    def open(self, runtime_context: RuntimeContext):
        desc = ValueStateDescriptor("rolling_count", Types.LONG())
        self.count_state = runtime_context.get_state(desc)

    def process_element(self, value: str, ctx: 'KeyedProcessFunction.Context'):
        obj = json.loads(value)
        current = self.count_state.value()
        if current is None:
            current = 0
        current += 1
        self.count_state.update(current)

        # émettre événement enrichi
        obj["rolling_count"] = current
        obj["event_time_ms"] = int(obj.get("event_time_ms", 0))
        yield json.dumps(obj)


def build_env() -> StreamExecutionEnvironment:
    # Défauts de cluster/job (peuvent aussi être définis dans config.yaml)
    cfg = Configuration()
    cfg.set_string("state.backend.type", "rocksdb")
    cfg.set_string("execution.checkpointing.dir", "s3://my-bucket/flink/checkpoints/realtime-sessions")
    cfg.set_string("execution.checkpointing.interval", "60 s")
    env = StreamExecutionEnvironment.get_execution_environment(cfg)

    # Dans PyFlink, les JARs de connecteur doivent être disponibles ; utiliser env.add_jars(...) si nécessaire.
    # env.add_jars("file:///opt/flink/lib/flink-connector-kafka-<VERSION>.jar")

    # Activer le pointage de contrôle explicitement aussi (les jobs peuvent écraser les défauts)
    env.enable_checkpointing(60_000)
    env.set_parallelism(4)
    return env


def main():
    env = build_env()

    source = (
        KafkaSource.builder()
        .set_bootstrap_servers("kafka:9092")
        .set_topics("events.raw")
        .set_group_id("realtime-sessions-v1")
        .set_value_only_deserializer(SimpleStringSchema())
        .set_starting_offsets(KafkaOffsetsInitializer.earliest())
        .build()
    )

    watermark_strategy = (
        WatermarkStrategy.for_bounded_out_of_orderness(Duration.of_seconds(10))
        .with_timestamp_assigner(EventTimeFromJson())
    )

    stream = (
        env.from_source(source, watermark_strategy=watermark_strategy, source_name="kafka-events-raw")
        .key_by(lambda s: json.loads(s)["user_id"])
        .process(RollingCount(), output_type=Types.STRING())
    )

    record_serializer = (
        KafkaRecordSerializationSchema.builder()
        .set_topic("events.enriched")
        .set_value_serialization_schema(SimpleStringSchema())
        .build()
    )

    sink = (
        KafkaSink.builder()
        .set_bootstrap_servers("kafka:9092")
        .set_record_serializer(record_serializer)
        .set_delivery_guarantee(DeliveryGuarantee.EXACTLY_ONCE)
        .set_transactional_id_prefix("realtime-sessions-txn")
        .build()
    )

    stream.sink_to(sink)

    env.execute("realtime-sessions-pyflink")


if __name__ == "__main__":
    main()

Les appels API ci-dessus s’alignent avec le motif d’utilisation du constructeur KafkaSource de PyFlink et les champs requis. Pour les garanties de livraison, la documentation KafkaSinkBuilder de PyFlink indique explicitement que pour DeliveryGuarantee.EXACTLY_ONCE vous devez définir le préfixe d’ID transactionnel. Pour le timestamping/repères d’eau, la documentation des repères d’eau de Flink explique l’attribution de timestamp et la génération de repères d’eau comme le mécanisme pour traiter le temps d’événement, et PyFlink fournit une API WatermarkStrategy qui reflète ce modèle.

Go n’a pas d’API d’auteur de job Flink native comme Java/Python, donc les systèmes Go s’intègrent généralement avec Flink via :

  • Kafka (ou autres courtiers) comme ingestion/egress.
  • L’API REST de Flink pour les actions opérationnelles (téléchargement de JARs, démarrage de jobs, interrogation de l’état du job, déclenchement de points de sauvegarde, redimensionnement).

Pour la configuration Kafka et les modèles de développement local, consultez Démarrage rapide Apache Kafka - Installer Kafka 4.2 avec CLI et exemples locaux.

Exemple de producteur/consommateur Kafka Go (kafka-go)

package main

import (
	"context"
	"log"
	"time"

	"github.com/segmentio/kafka-go"
)

func main() {
	ctx := context.Background()

	// Producteur : écrire des événements bruts
	writer := &kafka.Writer{
		Addr:         kafka.TCP("kafka:9092"),
		Topic:        "events.raw",
		RequiredAcks: kafka.RequireAll,
	}
	defer writer.Close()

	err := writer.WriteMessages(ctx, kafka.Message{
		Key:   []byte("user:u1"),
		Value: []byte(`{"user_id":"u1","event_time_ms":1710000000000,"event":"click"}`),
		Time:  time.Now(),
	})
	if err != nil {
		log.Fatal(err)
	}

	// Consommateur : lire des événements enrichis
	reader := kafka.NewReader(kafka.ReaderConfig{
		Brokers:  []string{"kafka:9092"},
		Topic:    "events.enriched",
		GroupID:  "go-debug-consumer",
		MinBytes: 1e3,
		MaxBytes: 10e6,
	})
	defer reader.Close()

	msg, err := reader.ReadMessage(ctx)
	if err != nil {
		log.Fatal(err)
	}
	log.Printf("enriched key=%s value=%s\n", string(msg.Key), string(msg.Value))
}

Ceci est du code « plomberie », mais c’est la surface d’intégration pratique la plus courante : les topics Kafka sont la frontière entre Flink et les services personnalisés.

L’API REST de Flink fait partie du serveur web JobManager et écoute sur le port 8081 par défaut (configurable via rest.port).

La spécification OpenAPI officielle du dispatcher inclut /jars/upload et déclare explicitement :

  • Le téléchargement de JAR doit être envoyé comme des données multi-part
  • assurez-vous que l’en-tête Content-Type est défini sur application/x-java-archive
  • fournit un exemple curl utilisant -F jarfile=@path/to/flink-job.jar

Un snippet Go pratique pour télécharger un JAR :

package flink

import (
	"bytes"
	"context"
	"fmt"
	"io"
	"mime/multipart"
	"net/http"
	"os"
)

func UploadJar(ctx context.Context, flinkBaseURL, jarPath string) (*http.Response, error) {
	f, err := os.Open(jarPath)
	if err != nil {
		return nil, err
	}
	defer f.Close()

	var body bytes.Buffer
	w := multipart.NewWriter(&body)

	part, err := w.CreateFormFile("jarfile", "job.jar")
	if err != nil {
		return nil, err
	}
	if _, err := io.Copy(part, f); err != nil {
		return nil, err
	}
	if err := w.Close(); err != nil {
		return nil, err
	}

	req, err := http.NewRequestWithContext(ctx, http.MethodPost, flinkBaseURL+"/jars/upload", &body)
	if err != nil {
		return nil, err
	}

	// Important : frontière multi-part
	req.Header.Set("Content-Type", w.FormDataContentType())

	// Certains clients définissent aussi "Expect:" de manière similaire à l'exemple curl dans la spécification.
	req.Header.Set("Expect", "")

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	if resp.StatusCode >= 300 {
		return resp, fmt.Errorf("upload failed: %s", resp.Status)
	}
	return resp, nil
}

Ce code est guidé par la description OpenAPI de l’API REST pour /jars/upload incluant sa exigence multi-part et la référence curl.

Pour exécuter un JAR précédemment téléchargé, Flink expose /jars/{jarid}/run et prend en charge le passage d’arguments de programme via des paramètres de requête (et/ou corps JSON).

Points de terminaison opérationnellement utiles que vous automatiserez probablement :

  • /jobs et /jobs/{jobid} pour lister et inspecter l’état du job
  • /jobs/{jobid}/savepoints pour déclencher des points de sauvegarde (déclenchement asynchrone + polling)
  • /jobs/{jobid}/rescaling pour déclencher le redimensionnement
Préoccupation PyFlink (jobs Python) Go (services autour de Flink)
Auctorisation de logique Flink Auctorisation native via les API DataStream/Table ; prend en charge l’état + minuteurs Pas d’API Flink native ; implémenter la logique dans Flink (Java/Python) et intégrer extérieurement
Connecteurs/dépendances Doit expédier les JARs de connecteur via pipeline.jars, add_jars, ou --jarfile Non applicable (vous n’êtes pas en train d’exécuter à l’intérieur de Flink), mais vous gérez les clients Kafka/DB
Ingestion/égress Constructeurs KafkaSource/KafkaSink dans PyFlink Bibliothèques producteur/consommateur Kafka ; modèles de microservices standards
Automatisation Ops Peut aussi appeler les points de terminaison REST Flink Souvent possède l’automatisation : uploader JAR, déployer, redimensionner, déclencher point de sauvegarde via REST

Flink prend en charge l’exportation de métriques en configurant des rapporteurs de métriques dans le fichier de configuration Flink ; ces rapporteurs sont instanciés sur les JobManagers et TaskManagers.

Pour Prometheus, Flink expose des métriques au format Prometheus lorsqu’il est configuré avec metrics.reporter.prom.factory.class: org.apache.flink.metrics.prometheus.PrometheusReporterFactory dans un environnement de version Flink prise en charge.

Vous combinez généralement cela avec des ServiceMonitors Kubernetes (Opérateur Prometheus) ou avec votre stack de surveillance gérée.

Mise à l’échelle : parallélisme, slots et autoscaling basé sur les opérateurs

Le modèle de planification de Flink définit les ressources d’exécution via les slots de tâche, et chaque slot peut exécuter un pipeline de tâches parallèles.

Pour la mise à l’échelle manuelle, l’API REST fournit un point de terminaison de redimensionnement pour un job (/jobs/{jobid}/rescaling) comme opération asynchrone.

Si vous êtes sur Kubernetes avec l’Opérateur Kubernetes Flink, le projet opérateur annonce un « Flink Job Autoscaler » comme partie de son ensemble de fonctionnalités, ce qui vaut la peine d’être évalué si vos charges de travail varient substantiellement.

Sauvegardes et mises à niveau sûres : points de contrôle et points de sauvegarde

Les points de contrôle sont pour la récupération automatisée et sont gérés par Flink ; les points de sauvegarde sont pour les opérations de cycle de vie pilotées par l’utilisateur (arrêt/reprise/fork/mise à niveau).

D’un point de vue SRE :

  • Utilisez les points de contrôle pour « garder le pipeline en cours d’exécution malgré les défaillances ».
  • Utilisez les points de sauvegarde pour « déployer une nouvelle version sans perdre l’état ».

L’API REST de Flink prend également en charge le déclenchement asynchrone de points de sauvegarde, ce qui est utile pour les workflows « déployer → déclencher point de sauvegarde → mettre à niveau » de style GitOps.

CI/CD : GitOps + Helm + soumission de job REST

Pour Kubernetes :

  • Gardez l’installation de l’opérateur et vos CR FlinkDeployment dans Git, déployez via Argo CD/Flux et versionnez les images de conteneur par build. La documentation Helm de l’opérateur discute explicitement du « Travail avec Argo CD ».

Pour les clusters autonomes/session :

  • Utilisez les points de terminaison de téléchargement et d’exécution de JAR de l’API REST Flink pour des déploiements d’artefacts immuables.

Notez également un basculement de sécurité/ops subtil mais précieux : web.submit.enable régit les téléchargements via l’interface Web, mais la documentation note que même lorsqu’il est désactivé, les clusters de session acceptent toujours les soumissions de jobs via des requêtes REST ; ceci est pertinent lors du durcissement des surfaces UI tout en conservant l’automatisation CI/CD.

Les systèmes LLM ne sont souvent que aussi bons que leur contexte en temps réel. Flink s’intègre dans les stacks LLM/IA comme le composant qui produit des caractéristiques, des embeddings et des agrégats comportementaux « toujours frais ».

Un modèle courant est :

  • ingérer des actions/événements utilisateur,
  • agréger des sessions et préférences,
  • produire des tâches de génération d’embeddings,
  • écrire des embeddings dans un magasin de vecteurs et/ou un magasin de caractéristiques.

La documentation de gestion des dépendances de PyFlink cite explicitement la « prédiction d’apprentissage automatique » et le chargement de modèles ML dans des UDF Python (pour l’exécution sur cluster distant), ce qui correspond directement aux approches « inférence en ligne à l’intérieur des opérateurs Flink ».

Mises à jour de magasin de caractéristiques en ligne pour la recommandation et le classement

Le modèle d’état clé et de pointage de contrôle de Flink est conçu pour maintenir l’état de l’opérateur à travers les événements et le récupérer de manière fiable. C’est une correspondance naturelle pour le calcul de caractéristiques continu (taux roulants, comptes, métriques temporellement amorties) dont les recommandeurs en aval ont besoin.

Compromis latence/cohérence pratiques pour les pipelines IA

Si votre architecture nécessite une sémantique exactement-une-fois bout-en-bout (par exemple, éviter les mises à jour de caractéristiques dupliquées ou les événements de facturation dupliqués), vous structurerez les sinks et sources autour du pointage de contrôle et des garanties transactionnelles.

Dans les stacks basées sur Kafka spécifiquement :

  • Le connecteur Kafka de Flink peut fournir des garanties exactement-une-fois lorsque le pointage de contrôle est activé et que les options de garantie de livraison sont configurées.
  • Kafka Streams prend également en charge la sémantique exactement-une-fois (EOS), ce qui est pertinent si votre « pipeline de caractéristiques IA » est suffisamment petit pour vivre à l’intérieur du code de l’application plutôt que dans un cluster Flink.

Flink comme constructeur de contexte IA en temps réel

Ce diagramme s’appuie sur les primitives de base de Flink : traitement du temps d’état (repères d’eau), backends d’état (state.backend.type et état local géré par le système) et mécanismes de pointage de contrôle/points de sauvegarde pour la tolérance aux pannes et les opérations.