| theme | default | |
|---|---|---|
| class | text-center | |
| highlighter | shiki | |
| lineNumbers | false | |
| info | ## Architecture Streaming-First Techtalk PMU - De l'échange de fichiers quotidiens au streaming temps réel | |
| drawings |
|
|
| transition | slide-up | |
| title | Architecture Streaming-First | |
| mdc | true | |
| css | unocss | |
| layout | pmu-cover |
::title:: Meetup PMU Tech
::subtitle:: 13 Novembre 2025
::talk:: Architecture Streaming-First
::speaker:: Laurent Valdes
::title::
::contents::
Notre architecture actuelle repose sur un système de passerelles de fichiers Cette architecture a été transcrite sur AWS :
- Stockage des fichiers sur S3
- Traitement via Lambda (serverless)
- Maintien du paradigme batch dans le cloud
Aujourd'hui, nous menons une réflexion de fond sur comment dynamiser les échanges :
- Passer d'une logique de cycles de traitement à une logique de fraîcheur de données
- Transformer notre approche pour répondre aux besoins temps réel
- Moderniser notre architecture tout en capitalisant sur l'existant
::title::
::contents::
Batch ≠ Simplicité - Les architectures batch cachent une complexité opérationnelle massive derrière une apparente simplicité.
- 🎯 Streaming-First est plus simple à opérer avec les bons outils
- 📊 La fraîcheur des données est un critère qualitatif fondamental
- ⚡ Le temps réel est une nécessité métier, pas un luxe
::title::
::contents::
- 📦 Architectures à base de fichiers quotidiens
⚠️ Problématiques métier induites- 🚀 Architecture Streaming-First
- 📊 Comparaison Batch vs Streaming
- 🏗️ Architecture type & Démo
::title::
::subtitle::
Rappel des caractéristiques des architectures batch traditionnelles
::title::
::contents::
graph LR
A[Système A] -->|CSV J+1| B[FTP]
C[Système B] -->|XML J+1| B
D[Système C] -->|JSON J+1| B
B -->|Batch| E[ETL]
E --> F[DW]
F -->|J+1| G[Apps]
style A color:#FFFFFF,stroke:#000
style C color:#FFFFFF,stroke:#000
style D color:#FFFFFF,stroke:#000
style E color:#FFFFFF,stroke:#000
style G color:#FFFFFF,stroke:#000
style B fill:#ff6b6b,color:#FFFFFF,stroke:#000
style E fill:#ff6b6b,color:#FFFFFF,stroke:#000
style F fill:#ffd93d,color:#000000,stroke:#000
linkStyle 0 stroke-width:2px,fill:none,stroke:black,color:white;
linkStyle 1 stroke-width:2px,fill:none,stroke:black,color:white;
linkStyle 2 stroke-width:2px,fill:none,stroke:black,color:white;
linkStyle 3 stroke-width:2px,fill:none,stroke:black,color:white;
linkStyle 4 stroke-width:2px,fill:none,stroke:black,color:white;
linkStyle 5 stroke-width:2px,fill:none,stroke:black,color:white;
- Passerelles de fichiers via FTP, SFTP, partages réseau
- Schémas hétérogènes : CSV, XML, JSON, formats propriétaires
- Transformations multiples : nettoyage, normalisation, enrichissement
::title::
::contents::
| Critère | Impact |
|---|---|
| Fraîcheur des données | ❌ J+1 minimum, souvent J+7 |
| Qualité | |
| Traçabilité | 📋 Complexe avec transformations multiples |
| Coût opérationnel | 💰 Élevé : stockage, transferts, monitoring |
| Time-to-insight | 🐌 24h+ minimum |
::title::
::subtitle::
Les impacts concrets sur le business
::title::
::contents::
%%{init: {'themeVariables': {'primaryColor':'#ffffff', 'primaryBorderColor':'#000000', 'primaryTextColor':'#000000', 'secondBkgColor':'#ffffff', 'secondBorderColor':'#000000', 'secondTextColor':'#000000', 'tertiaryColor':'#ffffff', 'tertiaryBorderColor':'#000000', 'tertiaryTextColor':'#000000', 'noteBkgColor':'#ffffcc', 'noteBorderColor':'#000000', 'lineColor':'#000000', 'signalTextDirMargin':'10px'}, 'sequence': {'mirrorActors': true, 'messageAlign': 'center', 'actorFontFamily': 'Arial', 'actorFontSize': '14px', 'messageFontFamily': 'Arial', 'noteFontFamily': 'Arial'}}, 'flowchart': {'useMaxWidth': false}}%%
sequenceDiagram
participant C as Client
participant A as App
participant B as Batch
participant D as Data
C->>A: Action 23h45
A->>B: Enregistrement
Note over B: Batch nocturne
B->>D: Traitement 02h
D->>A: Dispo 08h
A->>C: Confirmation J+1
Note over C: 8h d'attente !
Impact : Expérience client dégradée et perte de confiance
::title::
::contents::
- Campagne email lundi matin basée sur données du vendredi
- => clients déjà convertis reçoivent encore des offres.
- 📉 Taux de conversion réduit
- 💸 Budget marketing gaspillé
- 😠 Irritation client
- 📉 -30% de pertinence des campagnes
- 💸 15-20% du budget marketing gaspillé
layout: pmu-slide transition: slide-left
::title::
::contents::
- 📦 Stocks : vente de produits indisponibles
- 💰 Pricing : tarifs non actualisés
- 🎯 Opportunités : leads qualifiés traités trop tard
- 📅 Vendredi 18h : lead qualifié arrive.
- ⏸️ Weekend : aucun traitement.
- 📞 Lundi 10h : lead enfin disponible pour le commercial.
🫏 Résultat : le concurrent a déjà contacté le prospect.
::title::
::contents::
graph TB
A1[Backend A<br/>J-1]
B1[Backend B<br/>J-7]
C1[Backend C<br/>J-3]
D[Frontend]
D --> A1
D --> B1
D --> C1
style D fill:#ffe66d,color:#000000
style A1 fill:#ffe66d,color:#000000
style B1 fill:#ff6b6b,color:#000000
style C1 fill:#ffa94d,color:#000000
linkStyle 0 stroke-width:3px,fill:none,stroke:black,color:white;
linkStyle 1 stroke-width:3px,fill:none,stroke:black,color:white;
linkStyle 2 stroke-width:3px,fill:none,stroke:black,color:white;
Conséquence : incohérences applicatives, bugs et perte de confiance utilisateur
::title::
::contents::
| Dimension Qualité | Impact Batch |
|---|---|
| Exactitude | |
| Complétude | ❌ Données manquantes jusqu'au batch |
| Cohérence | ❌ Versions multiples en circulation |
| Actualité | ❌ Délai minimum 24h |
| Fiabilité |
- Les 6 dimensions de qualité des données incluent l'actualité (Timeliness) comme critère critique.
- => Des données exactes mais périmées sont inutilisables.
::title::
::subtitle::
Le paradigme du temps réel
::title::
::contents::
- Faire les choses d'abord en streaming
- Ne pas faire en streaming uniquement si impossible
- 📄 Un fichier est un stream de données
- 📦 Un groupe de fichiers est un stream de streams
- 🌊 Dans une architecture streaming-first : un stream est juste un stream
On parle de flux de données avant de parler de fichiers ou de messages. On optimise la fraîcheur avant de parler du middleware.
::title::
::contents::
graph LR
F[Fichiers] --> FC[File<br/>Connector]
API[APIs] --> HC[HTTP<br/>Source]
DB[(DB)] --> CDC[CDC<br/>Debezium]
IOT[IoT] --> MQTT[MQTT<br/>Connector]
FC --> K[Kafka<br/>Broker]
HC --> K
CDC --> K
MQTT --> K
K -.-> SR[Schema<br/>Registry]
K --> SP[Stream<br/>Processing]
SP --> T[Transform]
SP --> J[Join]
SP --> A[Aggregate]
SP --> W[Window]
style K fill:#4ecdc4,color:#000000
style SP fill:#95e1d3,color:#000000
style F color:#FFFFFF
style API color:#FFFFFF
style DB color:#FFFFFF
style FC color:#FFFFFF
style CDC color:#FFFFFF
style MQTT color:#FFFFFF
style IOT color:#FFFFFF
style HC color:#FFFFFF
style K color:#000000
style SR color:#FFFFFF
style SP color:#000000
style T color:#FFFFFF
style J color:#FFFFFF
style A color:#FFFFFF
style W color:#FFFFFF
linkStyle 0 stroke-width:3px,fill:none,stroke:black,color:white;
linkStyle 1 stroke-width:3px,fill:none,stroke:black,color:white;
linkStyle 2 stroke-width:3px,fill:none,stroke:black,color:white;
linkStyle 3 stroke-width:3px,fill:none,stroke:black,color:white;
linkStyle 4 stroke-width:3px,fill:none,stroke:black,color:white;
linkStyle 5 stroke-width:3px,fill:none,stroke:black,color:white;
linkStyle 6 stroke-width:3px,fill:none,stroke:black,color:white;
linkStyle 7 stroke-width:3px,fill:none,stroke:black,color:white;
linkStyle 8 stroke-width:3px,fill:none,stroke:black,color:white;
linkStyle 9 stroke-width:3px,fill:none,stroke:black,color:white;
linkStyle 10 stroke-width:3px,fill:none,stroke:black,color:white;
linkStyle 11 stroke-width:3px,fill:none,stroke:black,color:white;
linkStyle 12 stroke-width:3px,fill:none,stroke:black,color:white;
linkStyle 13 stroke-width:3px,fill:none,stroke:black,color:white;
::title::
::contents::
%%{init: {'flowchart': {'rankSpacing': 110, 'nodeSpacing': 25, 'diagramMarginX': 100, 'diagramMarginY': 50, 'useMaxWidth': true}}}%%
graph LR
subgraph Processing["⚙️ Processing"]
SP[Flink/Streams]
end
subgraph Storage["💾 Stockage"]
DW[(ClickHouse<br/>OLAP)]
TS[(TimescaleDB<br/>Time Series)]
ES[(Elasticsearch<br/>Search)]
end
subgraph Consumption["📊 Consommation"]
BI[Superset<br/>BI/OLAP]
RT[Apps<br/>Temps Réel]
DASH[Dashboards]
ML[ML/Analytics]
end
SP --> DW
SP --> TS
SP --> ES
DW --> BI
DW --> ML
TS --> DASH
ES --> RT
style SP fill:#95e1d3,color:#000000
style DW fill:#f38181,color:#000000
style TS fill:#f38181,color:#000000
style ES fill:#f38181,color:#000000
style BI fill:#aa96da,color:#000000
style RT color:#FFFFFF
style DASH color:#FFFFFF
style ML color:#FFFFFF
linkStyle 0 stroke-width:3px,fill:none,stroke:black,color:white;
linkStyle 1 stroke-width:3px,fill:none,stroke:black,color:white;
linkStyle 2 stroke-width:3px,fill:none,stroke:black,color:white;
linkStyle 3 stroke-width:3px,fill:none,stroke:black,color:white;
linkStyle 4 stroke-width:3px,fill:none,stroke:black,color:white;
linkStyle 5 stroke-width:3px,fill:none,stroke:black,color:white;
linkStyle 6 stroke-width:3px,fill:none,stroke:black,color:white;
::title::
::contents::
- Apache Kafka : standard industrie, écosystème riche
- Apache Pulsar ou NATS Jetstream : multi-tenancy, geo-replication native OU léger, performant, simple
- Apache Flink ou Kafka Streams : état de l'art, exactly-once, stateful
- ClickHouse : OLAP temps réel, ingestion streaming native
- Apache Druid : analytics temps réel, sub-second queries
- Apache Superset OU Looker : BI moderne, OLAP, exploration de données
::title::
::contents::
-- ClickHouse Kafka Engine with AVRO Format
CREATE TABLE sales_stream (
timestamp DateTime64(3),
product_id String,
amount Decimal(10,2)
) ENGINE = Kafka()
SETTINGS
kafka_broker_list = 'kafka:29092',
kafka_topic_list = 'sales',
kafka_format = 'AvroConfluent',
[...]- Requêtes ad-hoc directes sur ClickHouse, drill-down hiérarchique
- Applications custom via WebSocket depuis Kafka pour le temps réel.
::title::
::subtitle::
Batch vs Streaming-First
::title::
::contents::
| Critère | Architecture Batch | Architecture Streaming-First |
|---|---|---|
| Latence | 24h - 7 jours | Millisecondes - Secondes |
| Fraîcheur données | ❌ J+1 minimum | ✅ Temps réel |
| Scalabilité | ✅ Horizontale illimitée | |
| Monitoring | 📊 Batch (post-mortem) | 📈 Continu (proactif) |
| Coût infrastructure | 💰 Pics nocturnes | 💰 Lissé 24/7 |
| Gestion erreurs | ❌ Détection tardive | ✅ Détection immédiate |
| Time-to-market | 🐌 Lent (dépendances batch) | 🚀 Rapide (découplage) |
::title::
::contents::
| Critère | Architecture Batch | Architecture Streaming-First |
|---|---|---|
| Cohérence données | ✅ Source unique de vérité | |
| Gouvernance | 📋 Complexe (multiples copies) | ✅ Simplifiée (event log) |
| Réactivité métier | 🐌 Lendemain | ⚡ Immédiate |
| Debugging | 🔍 Difficile (logs dispersés) | 🔍 Facilité (replay events) |
| Évolutivité | ✅ Ajout de consumers | |
| Cas d'usage | Reporting historique | Temps réel + Historique |
::title::
::subtitle::
Mise en pratique avec Docker
::title::
::contents::
graph LR
subgraph "Production de Données"
FG[File Generator<br/>Python + Faker]
FG -->|CSV/JSON| INPUT[/data/input/]
end
subgraph "Ingestion Avro"
INPUT -->|Lecture| CSV2K[CSV-to-Kafka<br/>Producer]
CSV2K -->|Avro| KAFKA
SP[Streaming<br/>Producer<br/>Python] -->|Avro<br/>Temps Réel| KAFKA
end
subgraph "Kafka Ecosystem"
ZK[Zookeeper]
KAFKA[Kafka Broker<br/>Port 9092]
SR[Schema Registry<br/>Port 8081]
ZK -.->|Coordination| KAFKA
KAFKA <-->|Schémas Avro| SR
end
subgraph "Consommation"
KAFKA -->|Topic: bets<br/>Format: AvroConfluent| CH
KAFKA -->|Topic: customers<br/>Format: AvroConfluent| CH
CH[(ClickHouse<br/>OLAP Engine<br/>Port 8123)]
CH -->|Kafka Engine| CHTABLES[Tables MergeTree<br/>+ Vues Matérialisées]
end
subgraph "Visualisation"
CHTABLES -->|SQL| SUPERSET[Superset<br/>BI Analytics]
CHTABLES -->|HTTP API| SLIDEV[Slidev<br/>Stats Temps Réel]
end
subgraph "Monitoring"
KAFKA -.->|Monitoring| KAFKAUI[Kafka UI<br/>Port 8080]
end
style KAFKA fill:#FFFFFF,color:black,stroke:#000,stroke-width:3px
style SR fill:#FFFFFF,color:black,stroke:#000,stroke-width:3px
style CH fill:#FFFFFF,color:black,stroke:#000,stroke-width:3px
style SUPERSET fill:#FFFFFF,color:black,stroke:#000,stroke-width:3px
style SLIDEV fill:#FFFFFF,color:black,stroke:#000,stroke-width:3px
style CSV2K fill:#FFFFFF,color:black,stroke:#000,stroke-width:3px
style SP fill:#FFFFFF,color:black,stroke:#000,stroke-width:3px
style CHTABLES fill:#FFFFFF,color:black,stroke:#000,stroke-width:3px
linkStyle 0 stroke-width:3px,fill:none,stroke:black,color:black;
linkStyle 1 stroke-width:3px,fill:none,stroke:black,color:black;
linkStyle 2 stroke-width:3px,fill:none,stroke:black,color:black;
linkStyle 3 stroke-width:3px,fill:none,stroke:black,color:black;
linkStyle 4 stroke-width:3px,fill:none,stroke:black,color:black;
linkStyle 5 stroke-width:3px,fill:none,stroke:black,color:black;
linkStyle 6 stroke-width:3px,fill:none,stroke:black,color:black;
linkStyle 7 stroke-width:3px,fill:none,stroke:black,color:black;
linkStyle 8 stroke-width:3px,fill:none,stroke:black,color:black;
linkStyle 9 stroke-width:3px,fill:none,stroke:black,color:black;
linkStyle 10 stroke-width:3px,fill:none,stroke:black,color:black;
linkStyle 11 stroke-width:3px,fill:none,stroke:black,color:black;
::contents::
Lançons l'architecture streaming-first
::title::
::contents::
::title::
::subtitle::
Des questions ? Ouvrez ce QR code pour participer !
