7 points par GN⁺ 2023-07-29 | 3 commentaires | Partager sur WhatsApp
  • Le mode opt-in de l’annulation RPC passe de l’appel à context.allowCancellation() à l’annotation allowCancellation dans 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 sur poll(), plus lente
  • Les implémentations client et serveur HTTP de KJ prennent en charge la méthode CONNECT
  • capnp::RevocableServer a é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 branche master deviendra 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::Maybe et kj::AsyncOutputStream

3 commentaires

 
alstjr7375 2023-07-29

Oh... c'est enfin arrivé

 
GN⁺ 2023-07-29
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

    • J’ai connu plusieurs personnes parties soudainement, et c’est vraiment quelque chose qui vous brise l’âme. Chaque fois que cela arrive, cela rappelle à quel point la vie est fragile, et à quelle vitesse tout peut changer.
      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
    • Je ne savais pas, c’est un choc. J’aimais vraiment beaucoup le blog d’Ian, c’est tellement triste
    • @zenhack semble aussi avoir maintenu les bindings Haskell
    • Je ne le connaissais pas personnellement, mais j’admirais beaucoup son travail sur Tempest, un fork récent qui cherchait à faire revivre Sandstorm. Merci d’avoir partagé cette nouvelle
    • C’est une nouvelle vraiment triste. Ian a inspiré beaucoup de monde, et ce sera une grande perte pour toute la communauté
  • 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...

    • C’est une fonctionnalité sympa, mais j’ai l’impression qu’elle rend plus difficile l’optimisation du backend que l’approche consistant à regrouper explicitement les requêtes. Par exemple, un appel RPC sur mesure qui se résume à une seule requête SQL peut être préférable à plusieurs appels RPC distincts pipelinés
      Cela dit, c’est quand même une fonctionnalité qui mériterait probablement d’être plus largement utilisée
    • Le pipelining est une mauvaise idée. Comme il matérialise des instances d’objets, il rend une implémentation robuste beaucoup plus difficile. On n’est plus dans des appels sans état, mais dans une structure où l’on exécute des fonctions sur une instance d’objet précise
      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
    • Je ne savais pas que 9p avait du promise pipelining. Plus précisément, comme le client peut choisir les descripteurs de fichier, il peut envoyer une requête de lecture dès qu’il ouvre un fichier, et si l’ouverture échoue, la lecture échoue aussi avec EBADF ; c’est élégant
      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
    • Parmi les ancêtres spirituels de Cap'n Proto, il y a CapTP/VatTP, alias Pluribus, développé avec le langage E de Mark Miller. Dans le même jeu de mots, il y a aussi un dispositif appelé « unum ». Pour une généalogie plus profonde, voir sa thèse, qui mentionne aussi le promise pipelining de Barbara Liskov et des idées apparentées dans Argus, l’extension de CLU
      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...
    • Je ne sais pas exactement comment fonctionne le promise pipelining de Cap'n Proto, mais je m’inquiète des cas où l’on veut lire un répertoire puis faire un stat sur toutes les entrées qu’il contient, ou transmettre à l’appel suivant seulement l’une de deux valeurs de réponse
      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

    • C’est effectivement la plus grande faiblesse de Cap'n Proto. La seule implémentation que je maintiens correctement est celle en C++, et les autres viennent de divers contributeurs, avec des niveaux de complétude et de qualité variables
      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
    • Certaines personnes ont voulu écrire directement la couche RPC, plutôt qu’un wrapper autour de l’implémentation C++, mais cela représente vraiment beaucoup de code à réécrire par rapport au bénéfice immédiat
      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

    • C’est probablement lui qui a publié protobuf en 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

    • Il existe un billet de blog sur l’utilisation de Cap'n Proto par Cloudflare en 2014, trois ans avant mon arrivée : https://blog.cloudflare.com/introducing-lua-capnproto-better...
      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...
    • Je ne travaille pas chez Cloudflare, mais je suis leurs travaux et je traite parfois des projets sensibles aux performances. À mon avis, ils ont probablement considéré Cap'n Proto, flatbuffers, SBE, etc. comme une catégorie distincte des autres formats de données comme Avro ou protobuf
      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-...
    • Pour résumer la situation un peu plus d’un an après mon arrivée, Cloudflare était en train de mettre en place une façon d’envoyer les logs depuis l’edge vers un point central, afin de fournir des analyses aux clients et des logs aux clients enterprise
      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
    • Il est possible que le choix ait été facile parce que le lead developer de Cloudflare Workers est le créateur de Cap'n Proto
  • 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

    • Malheureusement, Ian « zenhack » Denhardt, qui pilotait cette participation, est décédé soudainement récemment
      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...

    • C’est un point de vue vraiment précieux. Moi aussi, j’ai eu du mal à comprendre pourquoi à l’époque. Le point essentiel a été de voir protobuf et Cap'n Proto non pas comme des structures de données en mémoire représentant le monde vu par un seul processus dans une seule version, mais comme des formats de sérialisation qui doivent fonctionner au-delà des frontières d’API, avec différentes versions de schéma et une compatibilité ascendante et descendante
      Par conséquent, le mantra souvent répété « rendre les états illégaux impossibles à représenter » ne s’applique pas ici
    • Typical fournit des champs asymétriques pour aider à l’évolution des types :
      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
    • En poussant cette logique plus loin, on pourrait presque conclure qu’il faut supprimer tous les types statiques. Honnêtement, ce n’est pas complètement faux, et c’est aussi la raison pour laquelle Alan Kay a défini l’orienté objet par le typage dynamique et la liaison tardive. Pourtant, nous allons dans la direction opposée tout en réapprenant sans cesse la même leçon
    • La FAQ [1] dit que « la bonne réponse est que l’application valide ce dont elle a besoin dans le code applicatif »
      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...
    • Il y a un autre piège du même genre : le fait de désérialiser même ce dont on n’a pas besoin, comme avec les clients générés
      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

    • Je suis d’accord sur le fait que l’API nécessaire au zéro copie devient un peu maladroite, surtout côté écriture. Côté lecture, ce n’est pas très différent. En revanche, le zéro copie ne ressemble à un changement de paradigme que dans certains scénarios spécifiques, comme lorsqu’il est utilisé avec mmap() ; pour les communications réseau, cela ne change pas grand-chose à moins d’utiliser des techniques fortes comme RDMA
      J’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
    • Je pense que vous voulez parler de flatbuffers, pas de protobuf. C’est devenu de fait le standard, et quelques autres endroits utilisent SBE
      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
    • Si vous n’avez pas besoin de schéma, MessagePack me paraît plutôt excellent. Cela dit, la sérialisation JSON de V8 est anormalement rapide, au point que MessagePack a aussi du mal à la battre ; dans d’autres langages, il est souvent plus rapide, et il réduit bien le nombre d’octets
    • fbthrift est encore bien vivant
  • 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.

    • Le problème que j’ai rencontré chaque fois que je me suis penché sur cap'n'proto, ce n’est pas seulement qu’il a un avis sur l’architecture serveur, mais aussi qu’en C++, il embarque KJ, une alternative très prescriptive à la STL. Quand j’y ai touché il y a quelques années, il s’immisçait partout dans la base de code existante, ce qui rendait le travail difficile.
      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.
    • Je suis curieux de savoir comment la couche de sérialisation influence le choix du RPC.
  • 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

    • Je n’avais en fait jamais pensé à cette référence.
      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.
    • Comme il était présenté comme un “cerealization protocol”, j’ai toujours pensé que c’était une référence aux céréales Cap'n Crunch.
 
bbulbum 2023-07-30

Il semble qu’il s’agisse de la sérialisation/RPC, donc c’est probablement une faute de frappe.