Cap'n Proto 1.0
(capnproto.org)- Le mode opt-in de l’annulation RPC passe de l’appel à
context.allowCancellation()à l’annotationallowCancellationdans le schéma - Les utilisateurs qui n’utilisaient pas
context.allowCancellation()n’ont besoin d’aucun changement lors de la mise à niveau vers 1.0, et l’annulation reste désactivée par défaut - La version 1.0 est une release de type support à long terme (LTS), avec un plan de backport à long terme des correctifs de bugs vers la branche 1.0
- Les améliorations de performance de Cap’n Proto RPC incluent une réduction des allocations mémoire dans l’implémentation RPC et le framework d’E/S KJ, l’omission de certains messages du protocole RPC et une amélioration du buffering des petits messages afin de réduire les appels système
- KJ utilise
kqueue()pour le traitement des E/S asynchrones sur MacOS et les systèmes de la famille BSD, en remplacement de l’ancienne approche basée surpoll(), plus lente - Les implémentations client et serveur HTTP de KJ prennent en charge la méthode
CONNECT capnp::RevocableServera été ajouté pour fournir une structure aidant à éviter les bugs de type use-after-free lors de l’export d’objets dont le wrapper ne contrôle pas la durée de vie comme wrapper RPC- Le développement de la 2.0 se poursuivra sur la nouvelle branche
v2, tandis que la branchemasterdeviendra la branche LTS 1.0 afin d’éviter que les projets existants soient interrompus par les changements - Le plan pour la 2.0 ne concerne pas des changements incompatibles de format de sérialisation ou de protocole RPC, mais des changements centrés sur l’API C++ et KJ, sans impact sur les applications écrites dans d’autres langages
- Le plan pour la 2.0 inclut l’exigence d’un compilateur C++20 ou C++23, l’utilisation des coroutines C++20, l’arrêt du support du mode sans exceptions et du mode sans RTTI, ainsi que des changements dans les API de
kj::Maybeetkj::AsyncOutputStream
3 commentaires
Oh... c'est enfin arrivé
Avis de Hacker News
Une très triste nouvelle pour les communautés Cap'n Proto et Sandstorm. Ian Denhardt (zenhack sur HN), qui était un contributeur clé de l’implémentation Go, est décédé soudainement il y a quelques semaines. Ayant beaucoup collaboré avec lui ces trois dernières années et étant devenu son ami, je ressens une grande perte.
En pratique, en tant que responsable du projet, je dois désormais combler l’immense vide laissé par Ian ; si vous pouvez contribuer au projet, votre aide serait vraiment précieuse. Si vous êtes contributeur ou mainteneur d’autres implémentations, en C++, Rust, etc., j’aimerais beaucoup que vous me contactiez. Pour poursuivre le travail d’Ian, il faudra s’entourer de personnes très brillantes.
RIP Ian, j’ai énormément appris en travaillant avec toi. Contact : https://github.com/lthibault, https://matrix.to/#/#go-capnp:matrix.org, Telegram @lthibault, gmail louist87
Sans ignorer l’avenir, j’ai appris à essayer de profiter davantage des petites choses de la vie. Ian laisse un héritage remarquable qui a touché beaucoup de gens. RIP Ian
Il est surprenant qu’en dehors de Cap'n Proto, il y ait si peu de protocoles avec du promise pipelining. Le seul autre exemple qui me vient à l’esprit est 9p, mais 9p n’est pas un protocole généraliste
https://capnproto.org/news/2013-12-13-promise-pipelining-cap...
Cela dit, c’est quand même une fonctionnalité qui mériterait probablement d’être plus largement utilisée
Par exemple, si le client Joe appelle le Service A et transmet le résultat promis au Service B, alors le Service B doit effectuer un appel distant vers le Service A pour obtenir le résultat de cette promesse
À ce moment-là, les frontières de sécurité se compliquent immédiatement. Le modèle de délégation devient déjà un problème, mais le plus grave est que la contre-pression disparaît. Si le client Joe crée des milliers d’appels vers le Service A et transmet au Service B des résultats qui n’ont pas encore été matérialisés, le Service A peut se retrouver submergé comme par un DDoS et le Service B peut expirer en timeout
Cela dit, le promise pipelining nécessite aussi une prise en charge côté client. Je me demande s’il existe des clients 9p qui, lorsqu’un utilisateur émet plusieurs walk, les envoient tous sans attendre la réponse du premier walk
Par ailleurs, 9p ne fournit du promise pipelining que pour les descripteurs de fichier. Cela permet déjà de faire beaucoup de choses, mais si l’on veut lire tous les fichiers d’un répertoire, il faudrait pouvoir émettre un read puis faire un walk sur le résultat de ce read, ce que 9p ne semble pas prendre en charge. Dans rsyscall, ma bibliothèque de protocole d’appels système distants, c’est effectivement pris en charge
Il me semble que Mark Miller a ensuite également rédigé la proposition des promesses pour JavaScript. En revanche, l’extension RPC ne s’est pas concrétisée, et à la place nous avons eu async/await, qui semble mal s’accorder avec le pipelining
Spritely Goblins et OCapN, des tentatives plus récentes de construire des systèmes distribués de capacités à la manière de E, poursuivent aussi le pipelining ; donc, sur cap-talk, on pourrait entendre parler de quelques protocoles similaires de plus, même si les cas d’usage réels restent rares
Cela dit, même si c’est une fonctionnalité élégante, le promise pipelining semble obliger à programmer avec de vraies promesses explicites, et on sait déjà à quel point cela peut devenir délicat
De l’autre côté, c’est-à-dire celui des boucles d’événements et des « objets actifs » à concurrence coopérative, une idée intéressante et moins connue est celle des causality IDs de DCOM/COM+. C’est un moyen de contrôler la réentrance ; voir CoGetCurrentLogicalThreadId dans la documentation Microsoft et la discussion de CALLTYPE_TOPLEVEL_CALLPENDING dans Effective COM. Plus tard, il me semble qu’ils ont essayé de le vendre comme une nouveauté avec l’ASTA de Win8/UWP
[1] http://erights.org/elib/distrib/captp/index.html
[2] http://erights.org/talks/thesis/index.html
[3] https://spritely.institute/goblins/
[4] https://github.com/ocapn/ocapn
[5] https://groups.google.com/g/captalk/
[6] https://learn.microsoft.com/openspecs/windows_protocols/ms-d...
[7] https://learn.microsoft.com/windows/win32/api/combaseapi/nf-...
[8] https://archive.org/details/effectivecom50wa00boxd/page/150
[9] https://devblogs.microsoft.com/oldnewthing/20210224-00/?p=10...
Le second cas semble possible d’une manière ou d’une autre, mais le premier dépend notamment du nombre de valeurs dans la liste de résultats
Félicitations pour la sortie. Après 10 ans, ça doit vraiment être enthousiasmant. Je me demande s’il y aura davantage de travail sur les implémentations dans d’autres langages
J’aime vraiment l’idée du format, mais les principaux langages de notre stack ne sont pas assez bien pris en charge pour que nous ayons envie de l’utiliser en production
Malheureusement, il m’est difficile de promettre quoi que ce soit de nouveau ici. Le travail sur Cap'n Proto est guidé par les besoins de mon projet principal, le runtime Cloudflare Workers, qui est principalement en C++. Il interagit aussi avec des services Go et Rust, et ces implémentations semblent y remplir leur rôle
Autrement dit, Cap'n Proto est un projet open source et j’espère qu’il sera utile aux gens, mais ce n’est pas un produit que j’essaie de vendre, donc je ne me concentre pas particulièrement sur le fait de pousser tout le monde à l’adopter. Comme toujours, les contributions sont les bienvenues
Un cas où il pourrait y avoir un grand changement serait si Cloudflare décidait de faire de Cap'n Proto une fonctionnalité publique de la plateforme Workers. Il y aurait alors un besoin direct de le peaufiner vraiment dans plusieurs langages. On en discute de temps en temps, mais il n’y a aucun plan pour le moment
Si tu veux tenter le coup, vas-y. Les gens seront probablement assez coopératifs. Il faut simplement savoir que c’est énormément de travail
Pour ajouter un peu de contexte, Kenton a exploité pendant des années le système proto interne de Google, puis après son départ il en a créé sa propre version open source
S’il y a chez Cloudflare quelqu’un qui a participé au choix de Cap'n Proto plutôt que d’autres solutions comme protobuf, je serais curieux de savoir quelles ont été les considérations. J’aimerais comprendre si ces raisons sont importantes pour moi aussi, ou si je peux les ignorer tant que je ne traite pas des volumes énormes
Aujourd’hui encore, le pipeline de données de Cloudflare, c’est-à-dire le système qui produit les logs et les analyses à l’edge, repose en grande partie sur la sérialisation Cap'n Proto. Je n’ai pas personnellement beaucoup participé à ce projet
Pour Cloudflare Workers, c’est moi qui ai lancé le projet, donc j’ai utilisé ce que j’avais fait. Ce n’est sans doute pas l’explication attendue
Cela dit, je pense que le protocole RPC de Cap'n Proto est bien plus expressif que les alternatives, ce qui a beaucoup aidé pour l’implémentation du sandboxing du Workers Runtime et de fonctionnalités de systèmes distribués comme Durable Objects. https://blog.cloudflare.com/introducing-workers-durable-obje...
Si l’on choisit des données d’une forme plus proche de l’enregistrement que du columnar comme Parquet, et que l’on veut un format avec un temps de parsing préalable pratiquement nul, les options deviennent assez limitées. Si l’on modifie la valeur des champs à la lecture, il peut y avoir du marshalling
https://capnproto.org/news/2014-06-17-capnproto-flatbuffers-... aborde ce compromis
Cap'n Proto a été créé à l’origine pour https://sandstorm.io/, et le travail que Kenton a sans doute fait après avoir été recruté par Cloudflare a probablement fini par mener à Cloudflare Workers
Autre élément à prendre en compte : https://github.com/google/flatbuffers/issues/2#issuecomment-...
Si j’ai bien compris, Albert Strasheim, l’ingénieur principal qui a construit tout cela, a benchmarké les options de sérialisation les plus crédibles, et Cap'n Proto s’est révélé nettement plus rapide que protobuf
Il existait une excellente implémentation C++, utilisable dans nginx. De mémoire, un peu de Lua entrait aussi en jeu. L’implémentation Go utilisée côté consommateurs avait des aspérités, mais les parties essentielles dont nous avions besoin ont pu être corrigées par l’équipe
Cloudflare a toujours accordé beaucoup d’importance à l’efficacité des coûts machine, donc au vu des exigences de performance de l’époque, c’était un choix naturel. Pendant mon passage dans l’équipe data, Cap'n Proto était plutôt agréable à utiliser, et le partage des définitions proto depuis un dépôt central de schémas fonctionnait bien
Je suis enthousiaste à l’idée que Cap'n Proto participe au travail de standardisation OCapN. Je me demande si cela fera partie du travail sur Cap'n Proto 2.0
https://github.com/ocapn/ocapn
J’aime OCapN, mais j’ai beaucoup de choses en cours en ce moment et je ne sais pas combien de temps je pourrai personnellement y consacrer. J’aimerais pouvoir donner de meilleures nouvelles, mais c’est une perte tragique pour nous tous
Je n’ai jamais utilisé Cap'n Proto, mais je remercie kentonv pour sa réponse de FAQ très instructive [1], qui explique pourquoi les champs obligatoires posent problème dans un protocole
Je la partage souvent quand des gens demandent pourquoi protobuf 3 n’a pas de champs
required[1] https://capnproto.org/faq.html#how-do-i-make-a-field-require...
Par conséquent, le mantra souvent répété « rendre les états illégaux impossibles à représenter » ne s’applique pas ici
https://github.com/stepchowfun/typical#asymmetric-fields-can...
Pour ajouter et supprimer des champs obligatoires en toute sécurité, Typical propose l’état asymmetric, intermédiaire entre champ optionnel et champ obligatoire. Un champ asymmetric d’une structure est considéré comme obligatoire côté écriture, et optionnel côté lecture. Contrairement aux champs optionnels, les champs asymmetric peuvent être promus en champs obligatoires en toute sécurité, ou revenir en arrière
J’aurais aimé qu’il existe un paramètre permettant d’activer ou de désactiver la validation obligatoire des messages, plutôt que de dépendre du code applicatif. On pourrait la désactiver à l’intérieur d’une application ou sur un bus de messages, mais en général, l’avoir activée aiderait beaucoup les développeurs
[1] https://capnproto.org/faq.html#how-do-i-make-a-field-require...
Ce que j’aime vraiment dans les interfaces de Go, c’est que je peux typer à distance uniquement ce que j’utilise et ignorer le reste. Ce n’est pas agréable qu’un service tombe à cause d’un changement de contrat qu’il n’utilise même pas, et c’est aussi difficile à diagnostiquer
C’est une excellente réussite. Pour être franc, je ne recommanderais pas Cap'n Proto. L’API C++ est très maladroite
Les avantages de l’analyse sans copie sont aussi plus faibles que prévu. Comme l’ergonomie est maladroite, il est peu probable qu’on veuille conserver les données dans des structures Cap'n Proto, et dans 99 % des cas on finit par les recopier dans ses propres structures
Le monde a largement convergé vers Protobuf pour ce genre d’implémentation binaire, donc les frictions avec les autres systèmes sont aussi plus importantes
Je ne l’ai utilisé que pour la sérialisation. La partie RPC est peut-être plus séduisante
J’aurais vraiment aimé que Thrift réussisse à la place de Protobuf/gRPC. Sa conception était bien meilleure et plus flexible que tout ce que j’ai vu avant ou après. Il a surtout dû disparaître à cause d’une documentation médiocre, et probablement aussi parce qu’il n’avait pas de grand nom derrière lui
mmap(); pour les communications réseau, cela ne change pas grand-chose à moins d’utiliser des techniques fortes comme RDMAJ’ai toujours voulu ajouter à Cap'n Proto une API alternative optionnelle pour les cas d’usage où le zéro copie n’est pas très important, qui utiliserait des « structures C ordinaires », ou quelque chose de proche, et offrirait une sérialisation avec une seule copie comme protobuf, mais je ne l’ai pas encore fait
Cela dit, personnellement, je me suis toujours beaucoup plus intéressé au protocole RPC qu’à la sérialisation. Je pense que le protocole RPC est un vrai changement de paradigme dans presque tous les cas d’usage non triviaux
Quoi qu’il en soit, les principaux problèmes de la sérialisation binaire sont la gestion des versions des schémas et des messages, ainsi que l’encodage delta. Si l’on ignore ces deux points, la sérialisation binaire plate est triviale
Aucune bibliothèque ne fournit de solution qui traite correctement ces deux aspects
J’ai toujours aimé les idées de capnp, mais au fond, ce qui me gêne, c’est qu’en tant que protocole d’encodage de messages, il ait aussi un avis sur la manière dont je devrais concevoir mon architecture serveur.
gRPC a clairement ce problème aussi, mais il est très nettement séparé de protobuf, même si protobuf comporte effectivement des fonctionnalités liées à gRPC.
À cause de cet enchevêtrement, chaque fois que je compare avec capnp, je penche plutôt vers flatbuffers ou protobuf. D’autant plus que les implémentations de fb et pb sont beaucoup plus simples, et que j’accorde beaucoup de valeur à la simplicité du point de vue de la sécurité et de la maintenance.
Le manque de bonnes implémentations tierces dans d’autres langages me semble aussi être un signe direct que ce jugement est fondé. Le bus factor et les chances de survie à long terme sont également très mauvais. La simplicité domine.
La version Rust exige elle aussi son propre mode de vie normatif. Beaucoup de ces choix ont du sens dans une vision du monde sans copie, mais cela rend tout de même plusieurs représentations difficiles, et la documentation était pénible à lire.
Rien que pour cette raison, je finis généralement par choisir flatbuffers.
Cela dit, j’espère qu’un jour se présentera une situation où cap'n'proto sera nécessaire et utile, et j’aimerais mener à bien au moins l’un des nombreux projets perso que j’ai forkés au fil des années pour essayer de l’utiliser. Il y a clairement un travail d’ingénierie de grande qualité derrière.
Ce n’est pas nouveau, mais je me demande si le nom est un hommage intentionnel à Star Trek Voyager, ou s’il y a une autre référence que j’ignore.
https://memory-alpha.fandom.com/wiki/Captain_Proton
Le nom Cap'n Proto signifiait à l’origine Capabilities and Protobufs. C’était un protocole RPC fondé sur les capacités, basé sur Protocol Buffers. Mais très tôt, j’ai eu envie d’essayer un format de sérialisation complètement différent. Comme “Proto” restait pertinent au sens de protocole, j’ai gardé le nom.
Le jeu de mots “cerealization protocol” m’a en fait été suggéré par quelqu’un d’autre, mais je l’ai aussitôt ajouté au logo.
Il semble qu’il s’agisse de la sérialisation/RPC, donc c’est probablement une faute de frappe.