Cap’n Proto 1.0
(capnproto.org)- RPC cancellation のオプトイン方式が
context.allowCancellation()呼び出しから、スキーマのallowCancellationアノテーションへ変更 context.allowCancellation()を使っていないユーザーは、1.0 へのアップグレード時に変更不要で、cancellation はデフォルトで引き続き無効- 1.0 は 長期サポート (LTS) 性格のリリースで、1.0 branch に bugfix を長期的に backport する計画
- Cap’n Proto RPC の性能改善として、RPC 実装と KJ I/O framework のメモリ割り当て削減、一部 RPC protocol message の省略、小さな message の buffering 改善による syscall 削減を適用
- KJ は MacOS と BSD 系で非同期 I/O 処理に
kqueue()を使用し、従来のより低速なpoll()ベース方式から変更 - KJ HTTP client と server 実装が
CONNECTmethod をサポート capnp::RevocableServerが追加され、wrapper が lifetime を制御しないオブジェクトを RPC wrapper として export する際、use-after-free bug の回避を助ける構造を提供- 2.0 開発は新しい
v2branch で進め、masterbranch は既存プロジェクトが変更で中断しないよう 1.0 LTS branch にする計画 - 2.0 の計画は serialization format や RPC protocol の後方互換性を壊す変更ではなく、C++ API と KJ 中心の変更であり、他言語で書かれたアプリケーションには影響しない
- 2.0 の計画には、C++20 または C++23 compiler の要求、C++20 coroutine の使用、exception disabled と no-RTTI mode のサポート終了、
kj::Maybeとkj::AsyncOutputStreamAPI の変更などが含まれる
3件のコメント
おお..ついにこれが
Hacker News の意見
Cap'n Proto と Sandstorm コミュニティに、とても悲しい知らせを伝えます。Go 実装の中心的な貢献者だった Ian Denhardt(HN の zenhack)が数週間前に急逝しました。この3年間、彼とは多くの共同作業を重ね、友人にもなっていたため、大きな喪失感を覚えています
事実上プロジェクトリードとして、これから Ian の大きな穴を埋めなければならないので、プロジェクトに貢献できる方がいれば切実に助けが必要です。C++、Rust など他の実装の貢献者やメンテナーであれば、ぜひ連絡を取りたいです。Ian の仕事を引き継ぐには、非常に優秀な人たちと一緒に取り組む必要があります
RIP Ian、一緒に働きながら本当に多くを学びました。連絡先: https://github.com/lthibault、https://matrix.to/#/#go-capnp:matrix.org、Telegram @lthibault、gmail louist87
将来から目をそらしているわけではありませんが、人生の小さなことをもっと楽しもうと思うようになりました。Ian は多くの人に届く素晴らしい遺産を残しました。RIP Ian
Cap'n Proto 以外にプロミス・パイプライニングを備えたプロトコルがこれほど少ないことに驚きます。思い浮かぶ別の例は 9p だけですが、9p は汎用プロトコルではありません
https://capnproto.org/news/2013-12-13-promise-pipelining-cap...
それでも、もっと広く使われてもよさそうな機能です
たとえばクライアント Joe が Service A を呼び出し、その約束された結果を Service B に渡すと、Service B はそのプロミス結果を得るために Service A へリモート呼び出しを行う必要があります
この時点でセキュリティ境界は一気に複雑になります。委譲モデルをどうするかも問題ですが、より深刻なのはバックプレッシャーが失われる点です。クライアント Joe が Service A に何千もの呼び出しを作り、まだ実体化されていない結果を Service B に渡すと、Service A が DDoS のように殺到し、Service B がタイムアウトする可能性があります
ただしプロミス・パイプライニングにはクライアント側の対応も必要です。ユーザーが複数の walk を発行したとき、最初の walk 応答を待たずにすべて送る 9p クライアントがあるのか気になります
また 9p は、ファイルディスクリプタに対してのみプロミス・パイプライニングを提供します。これだけでも多くのことができますが、ディレクトリ内のすべてのファイルを読みたいなら、read を発行したあと、その read の結果に対して walk できる必要がありますが、9p はこれをサポートしていないようです。私のリモートシステムコールプロトコルライブラリである rsyscall では、実際にこれをサポートしています
Mark Miller は後に JavaScript のプロミス提案も書いたと記憶しています。ただし RPC 拡張は実現せず、代わりにパイプライニングとはあまり相性がよくなさそうな async/await を手にすることになりました
E の方式で分散権限システムを作ろうとする、より最近の試みである Spritely Goblins と OCapN もパイプライニングを志向しているため、cap-talk にいれば、実際のユースケースは少なくても、似たようなプロトコルをいくつかさらに聞けるはずです
ただし素晴らしい機能ではあっても、プロミス・パイプライニングでは実際に明示的なプロミスでプログラミングする必要があるようで、それがどれほど扱いにくくなり得るかはすでによく知られています
反対側、つまりイベントループと協調的並行実行の「アクティブオブジェクト」側で、興味深いがあまり知られていないアイデアとしては、DCOM/COM+ の causality IDs があります。再入性を制御する手段であり、Microsoft ドキュメントの CoGetCurrentLogicalThreadId と Effective COM の CALLTYPE_TOPLEVEL_CALLPENDING に関する議論を見るとよいです。後には Win8/UWP の ASTA で新機能のように売り込もうとしていたようです
[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...
後者は何とか可能そうですが、前者は結果リストの値の個数などに依存します
リリースおめでとうございます。10年越しなので本当にうれしいでしょうね。今後、ほかの言語実装にもさらに作業が入るのか気になります
フォーマットのアイデアはとても気に入っていますが、私たちのスタックで主に使っている言語は、製品で使いたいと思えるほどサポートされていません
残念ながら、ここで新しいことを約束するのは難しいです。Cap'n Proto の作業は、私の主プロジェクトである Cloudflare Workers ランタイムの必要性に左右されており、そこでは主に C++ を使っています。Go や Rust のサービスともやり取りしていて、それらの実装はその場では役割を果たしているようです
つまり Cap'n Proto はオープンソースプロジェクトであり、人々の役に立ってほしいとは思っていますが、私が売ろうとしている製品ではないので、誰もが採用するようにすることへ特に注力しているわけではありません。いつもどおり、コントリビューションは歓迎します
大きな変化があり得る一つのケースは、Cloudflare が Cap'n Proto を Workers プラットフォームの公開機能にすると決めた場合です。そうなれば、複数の言語で本当に磨き込む直接的な必要性が生まれます。時々議論はしていますが、現時点で計画はありません
試してみたいならやってみても構いません。人々はかなり協力的である可能性が高いです。ただ、単純に作業量が非常に多いことは知っておくべきです
背景を付け加えると、Kenton は Google の社内 proto システムを何年も運用した後に退社し、自分のオープンソース版を作りました
Cloudflare の社員で、Cap'n Proto を protobuf などの別のものではなく選ぶ判断に関わった人がいれば、どのような考慮があったのか気になります。その理由が私にとっても重要なのか、それとも巨大な規模を扱わない限り気にしなくてよいものなのかを知りたいです
今でも Cloudflare のデータパイプライン、つまりエッジでログと分析を生成するシステムは、おおむね Cap'n Proto シリアライゼーションに基づいています。私はそのプロジェクトには個人的にあまり関わっていませんでした
Cloudflare Workers の場合は、私がプロジェクトを始めたので自分のものを使った、ということです。おそらく期待している説明ではないでしょう
それでも Cap'n Proto の RPC プロトコルは代替案よりはるかに表現力が高く、Workers Runtime のサンドボックス実装や Durable Objects のような分散システム機能の実装に大いに役立ったと思います。 https://blog.cloudflare.com/introducing-workers-durable-obje...
Parquet のような列指向ではなく、レコードに近い形のデータを選び、事前のパース時間が実質 0 の形式を求めるなら、選択肢はかなり限られます。読み取り時にフィールド値を変えるならマーシャリングは発生し得ます
https://capnproto.org/news/2014-06-17-capnproto-flatbuffers-...でこのトレードオフを扱っています
Cap'n Proto はもともと https://sandstorm.io/ のために作られ、Kenton が Cloudflare に雇われた後に行ったその仕事は、最終的に Cloudflare Workers へつながったのでしょう
もう一つの考慮事項: https://github.com/google/flatbuffers/issues/2#issuecomment-...
その全体を構築した中心的エンジニアである Albert Strasheim が有力なシリアライゼーションの選択肢をベンチマークし、Cap'n Proto が protobuf よりかなり速いという結果を得たのだと理解しています
優れた C++ 実装があり、nginx で使えました。記憶では、少し Lua も関わっていました。利用側で使っていた Go 実装には荒い部分がありましたが、必要な中核部分は人々が直せました
Cloudflare は常にマシンコスト効率を重視していたため、当時の性能要件を考えると自然な選択でした。データチームにいた間、Cap'n Proto はかなり扱いやすく、中央スキーマリポジトリで proto 定義を共有するやり方もうまく機能していました
Cap'n Proto が OCapN 標準化作業に参加している点に期待しています。これが Cap'n Proto 2.0 の作業の一部になるのか気になります
https://github.com/ocapn/ocapn
私は OCapN が好きですが、今抱えている仕事が多く、個人的にどれだけ時間を投入できるか分かりません。もっと良い知らせを伝えられればよかったのですが、私たち皆にとって悲劇的な喪失です
Cap'n Protoを使ったことはありませんが、プロトコルにおいて必須フィールドがなぜ問題になるのかを説明したkentonvの非常に有益なFAQ回答 [1] には感謝しています。
protobuf 3にrequiredフィールドがなぜないのかと聞かれるたびに、よくリンクしています。
[1] https://capnproto.org/faq.html#how-do-i-make-a-field-require...
したがって、「不正な状態を表現不可能にせよ」という広く繰り返されるマントラは、ここには当てはまりません。
https://github.com/stepchowfun/typical#asymmetric-fields-can...
必須フィールドを安全に追加・削除できるように、Typicalは任意フィールドと必須フィールドの中間状態であるasymmetricを提供します。構造体のasymmetricフィールドは、書き込み側には必須、読み取り側には任意と見なされます。任意フィールドと異なり、asymmetricフィールドは必須へ安全に昇格したり、その逆に戻したりできます。
アプリケーションコードに依存する代わりに、必須メッセージ検証をオン・オフできるパラメータがあればよかったと思います。アプリケーション内部やメッセージバスではオフにできますが、一般的にはオンになっていれば開発者にとって大きな助けになります。
[1] https://capnproto.org/faq.html#how-do-i-make-a-field-require...
Goのインターフェースで本当に気に入っている点は、自分が使うものだけをリモートで型付けし、残りはスキップできることです。サービスが使ってもいない契約変更のせいで障害が起きるのは楽しくありませんし、見つけるのも困難です。
素晴らしい成果です。正直に言うと、Cap'n Protoはおすすめしません。C++ APIが非常にぎこちないです。
ゼロコピー解析の利点も期待より小さいです。使い勝手がぎこちないため、データをCap'n Protoのデータ構造のまま持ち続けたいと思う可能性は低く、99%は結局自分のデータ構造へコピーすることになります。
世の中はこの種のバイナリ実装についてはおおむねProtobufに落ち着いているので、他のシステムとの摩擦も大きくなります。
私はシリアライズ用途でしか使ったことがありません。RPCのほうはもっと魅力的かもしれません。
Protobuf/gRPCの代わりにThriftが成功していれば本当によかったのにと思います。以前にも以後にも見たどのものより設計がはるかに良く、柔軟でした。主にひどいドキュメントのせいで消えていったように見えますし、背後に大きな名前がなかったことも理由だったのでしょう。
ゼロコピーがあまり重要でないユースケース向けに、Cap'n Protoに「普通のC構造体」またはそれに近い形を使い、protobufのように一度コピーするシリアライズを提供する任意の代替APIをずっと追加したいと思っていましたが、まだできていません。
ただ個人的には、シリアライズよりもRPCプロトコルのほうにずっと強い関心を持ってきました。RPCプロトコルは、些細でないほぼすべてのユースケースで実際のパラダイムシフトだと思います。
いずれにせよ、バイナリシリアライズの主な問題はスキーマとメッセージのバージョン管理、そしてデルタエンコーディングです。この2つを無視すれば、フラットなバイナリシリアライズは些細なものです。
上の2つをどちらもうまく扱う解法を提供するライブラリはありません。
capnp のアイデアはいつも気に入っていたが、結局はメッセージエンコーディングプロトコルであるにもかかわらず、私のサーバーアーキテクチャをどう組むべきかにまで意見を持っている点が気に障る。
gRPC にも確かにこうした問題はあるが、protobuf とは非常に明確に分離されており、protobuf には gRPC 関連機能があるにはある。
こうした絡み合いのせいで、capnp と比較するたびに flatbuffers や protobuf のほうに傾いてしまう。特に fb と pb の実装のほうがはるかに単純で、セキュリティとメンテナンスの観点では単純さを非常に高く評価しているためだ。
優れたサードパーティ製の言語実装が不足していることも、この判断が妥当だという直接的なシグナルだと思う。バス係数と長期的な生存性も非常に悪い。単純さが支配する。
Rust 版も独自の規範的な生活様式を要求する。その多くはゼロコピーの世界観では筋が通っているが、それでもいろいろな表現を難しくし、ドキュメントも読みにくかった。
だからこの理由だけでも、たいてい flatbuffers を選ぶことになる。
それでも、いつか cap'n'proto が必要で有用な状況が来ることを願っているし、何年も試そうとしてフォークしてある複数の趣味プロジェクトのうち、どれか一つでも終わらせたい。高品質なエンジニアリングが入っているのは確かだ。
新しくはないが、この名前が Star Trek Voyager への意図的なオマージュなのか、それとも私の知らない別の参照があるのか気になる。
https://memory-alpha.fandom.com/wiki/Captain_Proton
Cap'n Proto という名前は、もともと Capabilities and Protobufs を意味していた。Protocol Buffers ベースのケイパビリティベース RPC プロトコルだった。しかし初期に、まったく別のシリアライゼーション形式を試してみたくなった。それでも「Proto」はプロトコルという意味で依然として合っていたので、名前を維持した。
“cerealization protocol” という言葉遊びは実は別の人が教えてくれたものだが、すぐにロゴに追加した。
Serialization/RPC のことだと思いますが、誤字のようです