Skip to content

Commit 2a2052a

Browse files
committed
Ajout Cap'n Proto + restauration MessagePack et comparatifs
1 parent 350347d commit 2a2052a

File tree

9 files changed

+2534
-0
lines changed

9 files changed

+2534
-0
lines changed
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
🔝 Retour au [Sommaire](/SOMMAIRE.md)
2+
3+
# 25.3 Cap'n Proto : Zéro-copie sans étape d'encodage
4+
5+
## Introduction
6+
7+
Cap'n Proto est un système de sérialisation et de RPC créé par **Kenton Varda**, l'un des principaux auteurs de Protocol Buffers v2 chez Google. Son développement a démarré en 2013 avec un objectif radical : **éliminer entièrement l'étape d'encodage/décodage** qui constitue le goulot d'étranglement de Protobuf et de la quasi-totalité des formats de sérialisation.
8+
9+
L'idée fondatrice est simple à énoncer mais profonde dans ses implications : les données sont écrites directement dans un format qui est à la fois exploitable en mémoire *et* transmissible sur le réseau ou sur disque, sans transformation. Lire un message Cap'n Proto reçu par le réseau ne nécessite aucune désérialisation — on accède directement aux champs via des pointeurs dans le buffer reçu. Il n'y a pas de « parsing », pas d'allocation d'objets, pas de copie de données.
10+
11+
Ce principe de **zéro-copie** (zero-copy) distingue Cap'n Proto de manière fondamentale :
12+
13+
- **Protobuf** : encode les données dans un format wire compact (varint, length-delimited), puis les décode dans des objets C++ générés. Chaque direction (sérialisation et désérialisation) a un coût proportionnel à la taille du message.
14+
- **FlatBuffers** : permet la lecture zero-copy (pas de désérialisation), mais la construction d'un message nécessite un builder qui assemble les données dans un buffer plat. Le format wire n'est pas identique à la représentation mémoire d'une struct C.
15+
- **Cap'n Proto** : le format mémoire *est* le format wire. La construction et la lecture se font directement sur le même buffer, sans transformation dans aucune direction.
16+
17+
---
18+
19+
## Origines et motivations
20+
21+
Kenton Varda a travaillé sur Protobuf chez Google de 2007 à 2012. Son expérience directe des limitations de Protobuf a motivé la conception de Cap'n Proto. Les irritants principaux qu'il cherchait à résoudre :
22+
23+
**Le coût du parsing.** Dans les systèmes à haute performance (bases de données, proxies, pipelines de données), la sérialisation/désérialisation Protobuf peut consommer une part significative du temps CPU. Pour un proxy qui reçoit un message et le retransmet, Protobuf impose un cycle complet decode → ré-encode, même si le proxy ne modifie aucun champ.
24+
25+
**L'impossibilité du mmap.** On ne peut pas mapper un fichier Protobuf en mémoire et accéder directement aux champs — il faut parser le fichier entier d'abord. Pour une base de données qui stocke des millions d'enregistrements, cela interdit l'accès aléatoire efficace.
26+
27+
**La complexité du schéma d'évolution.** Bien que Protobuf supporte l'évolution des schémas (ajout de champs), les règles sont parfois contre-intuitives (changement required → optional, suppression de champs) et source de bugs en production.
28+
29+
Cap'n Proto a été conçu dès le départ pour adresser ces trois points, avec des garanties de compatibilité de schéma intégrées au format wire lui-même.
30+
31+
> 📝 Le nom « Cap'n Proto » est un jeu de mots sur « Captain Proto » (Protocol), avec une typographie volontairement décalée. Le projet est souvent abrégé en « capnp » dans les outils en ligne de commande.
32+
33+
---
34+
35+
## Positionnement dans l'écosystème
36+
37+
Le paysage des formats de sérialisation binaire en C++ comprend plusieurs acteurs majeurs, chacun avec ses compromis :
38+
39+
| Critère | Protobuf | FlatBuffers | Cap'n Proto | MessagePack |
40+
|---------|----------|-------------|-------------|-------------|
41+
| **Créateur** | Google | Google | Kenton Varda (ex-Google) | Sadayuki Furuhashi |
42+
| **Année** | 2008 (open source) | 2014 | 2013 | 2008 |
43+
| **Sérialisation** | Encode/Decode | Build / Zero-copy read | Zero-copy read+write | Encode/Decode |
44+
| **Schéma** | `.proto` | `.fbs` | `.capnp` | Sans schéma |
45+
| **Taille wire** | Compacte (varint) | Moyenne (alignée) | Moyenne (alignée) | Compacte |
46+
| **Vitesse de parsing** | Moyenne | Rapide (zero-copy read) | Instantanée (pas de parsing) | Moyenne |
47+
| **RPC intégré** | gRPC (séparé) | Non | Oui (natif) | Non |
48+
| **Mmap-friendly** | Non | Oui | Oui | Non |
49+
| **Adoption industrie** | Très large | Large (gaming, mobile) | Moyenne (niche perf.) | Large (web, Redis) |
50+
51+
Cap'n Proto se positionne comme le format le plus radical en termes de performance brute de sérialisation, au prix d'une adoption industrielle moins large que Protobuf et d'un écosystème de langages plus restreint.
52+
53+
---
54+
55+
## Caractéristiques clés
56+
57+
### Zéro-copie dans les deux directions
58+
59+
C'est la caractéristique déterminante. Ni la lecture ni l'écriture ne nécessitent de copie ou de transformation des données. Le buffer en mémoire est directement le message wire. Les implications pratiques :
60+
61+
- **Réception réseau** : un message reçu via `recv()` est directement exploitable. Pas d'allocation, pas de `ParseFromString()`, pas de construction d'objets.
62+
- **Envoi réseau** : le buffer construit en mémoire est directement envoyable via `send()`. Pas de `SerializeToString()`.
63+
- **Stockage disque** : un message peut être écrit sur disque et relu via `mmap` sans transformation.
64+
- **Proxy / forwarding** : un intermédiaire peut lire certains champs d'un message, le modifier partiellement, et le retransmettre sans jamais le désérialiser ni le resérialiser intégralement.
65+
66+
### RPC intégré
67+
68+
Contrairement à Protobuf qui dépend de gRPC (un projet séparé) pour le RPC, Cap'n Proto inclut un **système RPC natif** basé sur le même format wire. Ce système RPC supporte le pipelining de promesses : on peut chaîner des appels RPC sans attendre les résultats intermédiaires, réduisant drastiquement la latence des interactions multi-étapes.
69+
70+
### Évolution de schéma robuste
71+
72+
Cap'n Proto garantit la compatibilité ascendante et descendante des schémas par construction. Les champs sont identifiés par des numéros ordonnés, et le format wire encode des pointeurs explicites vers chaque champ. Un ancien lecteur ignore les champs inconnus (ajoutés après), et un nouveau lecteur voit des valeurs par défaut pour les champs absents (supprimés depuis).
73+
74+
Cette compatibilité est plus stricte que celle de Protobuf : certaines modifications dangereuses (changer le type d'un champ, réutiliser un numéro de champ supprimé) sont détectées au moment de la compilation du schéma, pas en production.
75+
76+
### Sécurité par design
77+
78+
Le format inclut des protections contre les messages malformés : limites de profondeur de traversée, limites sur le nombre de pointeurs suivis (pour éviter les structures circulaires ou exponentielles), et validation des bornes de pointeurs. Ces protections sont actives par défaut, sans surcoût significatif, et rendent Cap'n Proto plus sûr que la lecture directe de structures C.
79+
80+
---
81+
82+
## Cas d'usage privilégiés
83+
84+
Cap'n Proto excelle dans des contextes spécifiques où ses propriétés uniques apportent un avantage décisif :
85+
86+
**IPC haute performance.** Pour la communication inter-processus sur la même machine (via Unix sockets, pipes, ou shared memory), le zero-copy élimine une part significative de l'overhead. C'est l'usage d'origine du projet — Cloudflare utilise Cap'n Proto en interne pour l'IPC entre leurs workers.
87+
88+
**Stockage structuré mmap-friendly.** Les bases de données ou systèmes de fichiers structurés qui souhaitent mapper des enregistrements en mémoire et y accéder sans parsing bénéficient directement du format.
89+
90+
**Proxies et middleware.** Tout système qui reçoit un message, inspecte quelques champs (routage, authentification), et le retransmet. Avec Protobuf, cela nécessite un cycle complet parse→inspect→reserialize. Avec Cap'n Proto, l'inspection est directe et la retransmission est une simple copie du buffer original.
91+
92+
**Systèmes embarqués et temps réel.** L'absence d'allocation dynamique pendant la désérialisation est précieuse dans les environnements où les allocations sont interdites ou coûteuses (boucles temps réel, microcontrôleurs).
93+
94+
---
95+
96+
## Limites et compromis
97+
98+
Cap'n Proto n'est pas un remplacement universel de Protobuf. Ses compromis doivent être compris :
99+
100+
**Taille des messages.** Le format wire est aligné (padding pour l'alignement des champs) et utilise des pointeurs 64 bits. Les messages Cap'n Proto sont typiquement **20 à 50 % plus grands** que leurs équivalents Protobuf, qui utilisent un encodage varint compact. Si la bande passante réseau est le facteur limitant (WAN, mobile), Protobuf peut être un meilleur choix.
101+
102+
**Écosystème de langages.** Protobuf supporte officiellement une dizaine de langages avec des implémentations matures. Cap'n Proto a des implémentations de qualité en C++, Rust, Go et TypeScript, mais le support dans d'autres langages (Python, Java) est moins mature ou maintenu par la communauté.
103+
104+
**Adoption et recrutement.** Protobuf est un standard de facto dans l'industrie. La documentation, les tutoriels, les réponses sur Stack Overflow, et l'expérience des développeurs sont incomparablement plus riches pour Protobuf. Choisir Cap'n Proto impose un coût d'onboarding pour l'équipe.
105+
106+
**Complexité du modèle mémoire.** Le zero-copy impose que le message reste valide en mémoire tant qu'on accède à ses champs. On ne peut pas désérialiser dans un objet indépendant puis libérer le buffer réseau — le buffer *est* l'objet. Cela demande une gestion plus attentive des durées de vie, particulièrement en C++.
107+
108+
**Pas de compression native.** Protobuf utilise des varints qui compriment naturellement les petits entiers. Cap'n Proto stocke tous les entiers dans leur taille native (int32 = 4 octets, même pour la valeur 0). Une compression externe (zstd, lz4) peut compenser, mais ajoute une étape.
109+
110+
---
111+
112+
## Prérequis : installation sur Ubuntu
113+
114+
```bash
115+
# Depuis les paquets (version stable)
116+
sudo apt update
117+
sudo apt install capnproto libcapnp-dev
118+
119+
# Vérifier l'installation
120+
capnp --version
121+
capnpc-c++ --version
122+
```
123+
124+
Pour la dernière version depuis les sources :
125+
126+
```bash
127+
git clone https://github.com/capnproto/capnproto.git
128+
cd capnproto/c++
129+
cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=Release
130+
cmake --build build -j$(nproc)
131+
sudo cmake --install build
132+
```
133+
134+
Intégration CMake :
135+
136+
```cmake
137+
find_package(CapnProto REQUIRED)
138+
139+
capnp_generate_cpp(CAPNP_SRCS CAPNP_HDRS schema/message.capnp)
140+
141+
add_executable(my_app main.cpp ${CAPNP_SRCS})
142+
target_link_libraries(my_app PRIVATE CapnProto::capnp)
143+
# Pour le RPC :
144+
# target_link_libraries(my_app PRIVATE CapnProto::capnp-rpc)
145+
```
146+
147+
---
148+
149+
## Plan de la section
150+
151+
Les sous-sections suivantes approfondissent Cap'n Proto en trois axes :
152+
153+
- **25.3.1 — Philosophie : le format wire EST le format mémoire** : le modèle de données de Cap'n Proto, la structure interne des messages (segments, pointeurs, data sections), et la démonstration concrète du zero-copy avec des exemples compilables.
154+
155+
- **25.3.2 — Schémas, génération de code et RPC intégré** : la syntaxe des fichiers `.capnp`, la génération de code C++, la manipulation des messages (construction et lecture), et le système RPC natif avec pipelining de promesses.
156+
157+
- **25.3.3 — Cap'n Proto vs FlatBuffers vs Protobuf : compromis** : une comparaison détaillée des trois formats sur les axes performance, taille wire, facilité d'usage, évolution de schéma et écosystème, avec des benchmarks et des recommandations par cas d'usage.
158+
159+
⏭️ [Philosophie : le format wire EST le format mémoire](/25-formats-binaires/03.1-philosophie-capnproto.md)

0 commit comments

Comments
 (0)