Cap'n Proto 1.0
(capnproto.org)- RPC cancellation đã chuyển từ cơ chế opt-in bằng lệnh gọi
context.allowCancellation()sang annotationallowCancellationtrong schema - Người dùng không sử dụng
context.allowCancellation()sẽ không cần thay đổi gì khi nâng cấp lên 1.0, và cancellation vẫn tiếp tục bị vô hiệu hóa theo mặc định - 1.0 là bản phát hành mang tính chất hỗ trợ dài hạn (LTS), với kế hoạch backport các bản sửa lỗi lên nhánh 1.0 trong thời gian dài
- Cải thiện hiệu năng Cap’n Proto RPC bằng cách giảm cấp phát bộ nhớ trong phần triển khai RPC và framework KJ I/O, lược bỏ một số message của giao thức RPC, và giảm số syscall thông qua cải thiện buffering cho các message nhỏ
- KJ sử dụng
kqueue()để xử lý I/O bất đồng bộ trên MacOS và họ BSD, thay cho cách cũ dựa trênpoll()chậm hơn - Triển khai KJ HTTP client và server hỗ trợ phương thức
CONNECT - Đã bổ sung
capnp::RevocableServer, cung cấp cấu trúc giúp tránh lỗi use-after-free khi export đối tượng mà wrapper không kiểm soát vòng đời dưới dạng RPC wrapper - Việc phát triển 2.0 sẽ diễn ra trên nhánh
v2mới, còn nhánhmasterđược dự định trở thành nhánh 1.0 LTS để các dự án hiện có không bị gián đoạn vì thay đổi - Kế hoạch cho 2.0 không bao gồm các thay đổi phá vỡ tính tương thích ngược của serialization format hay giao thức RPC, mà chủ yếu tập trung vào C++ API và KJ, nên các ứng dụng viết bằng ngôn ngữ khác sẽ không bị ảnh hưởng
- Kế hoạch 2.0 bao gồm yêu cầu compiler C++20 hoặc C++23, sử dụng coroutine của C++20, ngừng hỗ trợ chế độ tắt exception và no-RTTI, cùng các thay đổi đối với API
kj::Maybevàkj::AsyncOutputStream
3 bình luận
Ồ.. cuối cùng cái này cũng ra mắt
Ý kiến trên Hacker News
Xin báo một tin rất đau buồn tới cộng đồng Cap'n Proto và Sandstorm. Ian Denhardt (zenhack trên HN), người từng là contributor cốt lõi của bản triển khai Go, đã đột ngột qua đời vài tuần trước; trong 3 năm qua chúng tôi đã hợp tác rất nhiều và trở thành bạn bè, nên đây là một mất mát lớn
Trên thực tế, với vai trò lead của dự án, giờ tôi phải lấp khoảng trống rất lớn mà Ian để lại, vì vậy nếu bạn có thể đóng góp cho dự án thì chúng tôi rất cần sự giúp đỡ. Nếu bạn là contributor hoặc maintainer của các bản triển khai khác như C++, Rust, v.v., tôi rất muốn được liên hệ. Để tiếp nối công việc của Ian, chúng tôi cần làm việc cùng những người rất thông minh
RIP Ian, tôi đã học được rất nhiều khi làm việc cùng bạn. Liên hệ: https://github.com/lthibault, https://matrix.to/#/#go-capnp:matrix.org, Telegram @lthibault, gmail louist87
Tôi không quay lưng với tương lai, nhưng nó khiến tôi cố gắng tận hưởng hơn những điều nhỏ bé trong cuộc sống. Ian đã để lại một di sản tuyệt vời chạm tới rất nhiều người. RIP Ian
Ngoài Cap'n Proto, thật ngạc nhiên là có ít giao thức có promise pipelining đến vậy. Ví dụ khác hiện nghĩ ra chỉ có 9p, mà 9p thì không phải là giao thức đa dụng
https://capnproto.org/news/2013-12-13-promise-pipelining-cap...
Dù vậy, đây vẫn là tính năng đáng lẽ có thể được dùng rộng rãi hơn
Ví dụ, nếu client Joe gọi Service A rồi chuyển kết quả đã được hứa hẹn đó cho Service B, thì Service B phải thực hiện lời gọi từ xa đến Service A để lấy kết quả promise đó
Khi đó, ranh giới bảo mật ngay lập tức trở nên phức tạp. Mô hình ủy quyền sẽ xử lý thế nào cũng là vấn đề, nhưng nghiêm trọng hơn là backpressure biến mất. Nếu client Joe tạo hàng nghìn lời gọi tới Service A và chuyển các kết quả chưa được hiện thực hóa cho Service B, Service A có thể bị dồn tải như DDoS khiến Service B bị timeout
Tuy nhiên promise pipelining cũng cần client hỗ trợ. Tôi tò mò liệu có client 9p nào, khi người dùng phát ra nhiều lệnh walk, sẽ gửi tất cả mà không chờ phản hồi của lệnh walk đầu tiên hay không
Ngoài ra, 9p chỉ cung cấp promise pipelining cho file descriptor. Chỉ riêng điều này đã làm được rất nhiều, nhưng nếu muốn đọc tất cả file trong một thư mục, bạn cần có thể phát lệnh read rồi walk dựa trên kết quả của read đó, mà có vẻ 9p không hỗ trợ. Trong thư viện giao thức gọi hệ thống từ xa của tôi, rsyscall, thực tế có hỗ trợ việc này
Tôi nhớ Mark Miller sau này cũng viết đề xuất promise cho JavaScript. Tuy nhiên phần mở rộng RPC không thành hiện thực; thay vào đó chúng ta có async/await, thứ có vẻ không hợp lắm với pipelining
Spritely Goblins và OCapN, những nỗ lực gần đây hơn nhằm xây dựng hệ thống quyền phân tán theo phong cách của E, cũng theo đuổi pipelining, nên nếu ở cap-talk, bạn có thể nghe thêm vài giao thức tương tự, dù ca sử dụng thực tế có thể ít
Tuy là tính năng hay, nhưng promise pipelining dường như đòi hỏi phải lập trình bằng các promise tường minh thực sự, và việc đó có thể trở nên rắc rối đến mức nào thì ai cũng đã biết
Ở phía ngược lại, tức phía event loop và các “active object” thực thi đồng thời cộng tác, một ý tưởng thú vị và ít được biết đến hơn là causality IDs của DCOM/COM+. Đây là một phương tiện kiểm soát tính tái nhập; hãy xem tài liệu Microsoft về CoGetCurrentLogicalThreadId và phần thảo luận CALLTYPE_TOPLEVEL_CALLPENDING trong Effective COM. Về sau có vẻ họ từng cố bán nó như một tính năng mới trong ASTA của 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...
Trường hợp sau có vẻ bằng cách nào đó vẫn làm được, nhưng trường hợp trước phụ thuộc vào số lượng giá trị trong danh sách kết quả, v.v.
Chúc mừng ra mắt. Sau 10 năm chắc hẳn rất phấn khích. Tôi tò mò liệu sau này có thêm công việc nào cho các bản triển khai ở ngôn ngữ khác không
Tôi rất thích ý tưởng về định dạng này, nhưng các ngôn ngữ chính trong stack của chúng tôi chưa được hỗ trợ đến mức tôi muốn dùng trong sản phẩm
Đáng tiếc là khó hứa hẹn điều gì mới ở đây. Công việc trên Cap'n Proto được thúc đẩy bởi nhu cầu của dự án chính của tôi, runtime Cloudflare Workers, và phần đó chủ yếu là C++. Nó cũng tương tác với các dịch vụ Go và Rust, và các bản triển khai tương ứng có vẻ làm tròn vai ở đó
Nói cách khác, Cap'n Proto là một dự án mã nguồn mở và tôi hy vọng nó hữu ích với mọi người, nhưng nó không phải là sản phẩm tôi đang bán, nên tôi không đặc biệt tập trung vào việc khiến tất cả mọi người áp dụng. Như mọi khi, mọi đóng góp đều được hoan nghênh
Một trường hợp có thể tạo ra thay đổi lớn là khi Cloudflare quyết định biến Cap'n Proto thành một tính năng công khai của nền tảng Workers. Khi đó sẽ có nhu cầu trực tiếp để thật sự trau chuốt nó trên nhiều ngôn ngữ. Thỉnh thoảng chúng tôi có bàn về chuyện này, nhưng hiện chưa có kế hoạch
Nếu muốn thử thì cứ thử. Mọi người nhiều khả năng sẽ khá hợp tác. Chỉ cần biết rằng khối lượng công việc đơn giản là rất nhiều
Bổ sung bối cảnh: Kenton từng vận hành hệ thống proto nội bộ của Google trong nhiều năm, rồi sau khi rời đi đã tạo phiên bản mã nguồn mở của riêng mình
Nếu có nhân viên Cloudflare nào từng tham gia vào việc chọn Cap'n Proto thay vì những thứ khác như protobuf, tôi tò mò các cân nhắc khi đó là gì. Tôi muốn biết liệu các lý do đó có quan trọng với mình không, hay chỉ khi xử lý quy mô khổng lồ mới cần quan tâm
Đến nay, pipeline dữ liệu của Cloudflare, tức hệ thống tạo log và phân tích ở edge, phần lớn vẫn dựa trên tuần tự hóa Cap'n Proto. Cá nhân tôi không tham gia nhiều vào dự án đó
Còn với Cloudflare Workers thì vì tôi là người khởi động dự án, nên tôi dùng thứ của mình. Có lẽ đó không phải là lời giải thích bạn muốn
Dù vậy, tôi cho rằng giao thức RPC của Cap'n Proto biểu đạt mạnh hơn nhiều so với các lựa chọn thay thế, nên đã giúp ích rất lớn cho việc triển khai sandboxing của Workers Runtime và các tính năng hệ thống phân tán như Durable Objects. https://blog.cloudflare.com/introducing-workers-durable-obje...
Nếu chọn dữ liệu có dạng gần với bản ghi hơn là dạng cột như Parquet, và muốn một định dạng có thời gian phân tích cú pháp ban đầu gần như bằng 0, thì các lựa chọn trở nên khá ít. Khi đọc mà thay đổi giá trị trường thì vẫn có thể có marshalling
https://capnproto.org/news/2014-06-17-capnproto-flatbuffers-... bàn về sự đánh đổi này
Cap'n Proto ban đầu được tạo ra cho https://sandstorm.io/, và công việc Kenton làm sau khi được Cloudflare tuyển dụng rốt cuộc có lẽ đã dẫn tới Cloudflare Workers
Một cân nhắc khác: https://github.com/google/flatbuffers/issues/2#issuecomment-...
Theo tôi hiểu, Albert Strasheim, kỹ sư chủ chốt đã xây dựng toàn bộ hệ thống đó, đã benchmark các lựa chọn tuần tự hóa có triển vọng và thu được kết quả rằng Cap'n Proto nhanh hơn protobuf khá nhiều
Nó có bản triển khai C++ rất tốt và dùng được trong nginx. Nếu nhớ không nhầm thì cũng có một chút Lua liên quan. Bản triển khai Go dùng ở phía tiêu thụ còn thô, nhưng các phần cốt lõi cần thiết thì mọi người có thể sửa được
Cloudflare luôn coi trọng hiệu quả chi phí máy móc, nên xét các yêu cầu hiệu năng khi đó, đây là lựa chọn tự nhiên. Trong thời gian tôi ở đội dữ liệu, Cap'n Proto khá dễ làm việc, và cách chia sẻ định nghĩa proto từ kho schema trung tâm cũng hoạt động tốt
Tôi rất mong chờ việc Cap'n Proto tham gia công tác chuẩn hóa OCapN. Tôi tò mò liệu đây có trở thành một phần của công việc Cap'n Proto 2.0 không
https://github.com/ocapn/ocapn
Tôi thích OCapN, nhưng hiện có nhiều việc đang đảm nhiệm nên không biết cá nhân tôi có thể dành bao nhiêu thời gian cho nó. Ước gì tôi có thể báo tin tốt hơn, nhưng đây là một mất mát bi thảm đối với tất cả chúng ta
Tôi chưa từng dùng Cap'n Proto, nhưng rất cảm ơn câu trả lời FAQ cực kỳ hữu ích của kentonv [1], giải thích vì sao trường bắt buộc trong giao thức lại là một vấn đề
Tôi thường liên kết đến nó mỗi khi mọi người hỏi tại sao protobuf 3 không có trường required
[1] https://capnproto.org/faq.html#how-do-i-make-a-field-require...
Vì vậy câu thần chú được lặp đi lặp lại rộng rãi “hãy làm cho trạng thái bất hợp lệ không thể biểu diễn được” không áp dụng ở đây
https://github.com/stepchowfun/typical#asymmetric-fields-can...
Để thêm và loại bỏ trường bắt buộc một cách an toàn, Typical cung cấp asymmetric, một trạng thái trung gian giữa trường tùy chọn và trường bắt buộc. Một trường asymmetric của struct được xem là bắt buộc ở phía ghi và tùy chọn ở phía đọc. Khác với trường tùy chọn, trường asymmetric có thể được nâng cấp an toàn thành bắt buộc hoặc đảo ngược lại
Giá mà có một tham số để bật/tắt kiểm chứng thông điệp bắt buộc thay vì phụ thuộc vào mã ứng dụng. Có thể tắt nó bên trong ứng dụng hoặc trên message bus, nhưng nhìn chung nếu bật thì sẽ giúp ích rất nhiều cho nhà phát triển
[1] https://capnproto.org/faq.html#how-do-i-make-a-field-require...
Điều tôi thực sự thích ở interface của Go là tôi có thể định kiểu từ xa chỉ những gì mình dùng và bỏ qua phần còn lại. Dịch vụ bị lỗi vì thay đổi hợp đồng mà nó thậm chí không dùng đến thì chẳng vui vẻ gì, và cũng khó tìm ra
Đây là một thành tựu tuyệt vời. Nói thật thì tôi sẽ không khuyến nghị Cap'n Proto. API C++ rất gượng gạo
Lợi ích của phân tích cú pháp không sao chép cũng nhỏ hơn kỳ vọng. Vì tính khả dụng gượng gạo, khả năng cao là bạn sẽ không muốn giữ dữ liệu trong cấu trúc dữ liệu Cap'n Proto mãi, và 99% cuối cùng vẫn sẽ sao chép sang cấu trúc dữ liệu của mình
Thế giới nhìn chung đã ổn định ở Protobuf cho các triển khai nhị phân kiểu này, nên ma sát với các hệ thống khác cũng lớn hơn
Tôi chỉ từng dùng nó cho tuần tự hóa. Phần RPC có thể hấp dẫn hơn
Tôi thực sự ước Thrift đã thành công thay vì Protobuf/gRPC. Thiết kế của nó tốt và linh hoạt hơn nhiều so với bất cứ thứ gì tôi thấy trước hay sau đó. Có vẻ nó biến mất chủ yếu vì tài liệu quá tệ, và có lẽ cũng vì không có tên tuổi lớn đứng sau
Tôi vẫn luôn muốn thêm vào Cap'n Proto một API thay thế tùy chọn dùng “struct C bình thường” hoặc dạng gần như vậy, và cung cấp tuần tự hóa sao chép một lần như protobuf cho các trường hợp sử dụng mà không sao chép không quan trọng lắm, nhưng vẫn chưa làm được
Tuy nhiên cá nhân tôi từ lâu thấy giao thức RPC thú vị hơn nhiều so với tuần tự hóa. Tôi nghĩ giao thức RPC là một sự chuyển đổi mô hình thực sự trong hầu hết mọi trường hợp sử dụng không tầm thường
Dù sao thì vấn đề chính của tuần tự hóa nhị phân là quản lý phiên bản schema và thông điệp, cũng như mã hóa delta. Nếu bỏ qua hai điều này thì tuần tự hóa nhị phân phẳng là chuyện tầm thường
Không có thư viện nào cung cấp giải pháp xử lý tốt cả hai vấn đề trên
Tôi luôn thích ý tưởng của capnp, nhưng rốt cuộc nó là một giao thức mã hóa thông điệp, vậy mà lại có quan điểm cả về việc tôi nên thiết kế kiến trúc máy chủ như thế nào, điều đó khiến tôi khó chịu
gRPC chắc chắn cũng có vấn đề kiểu này, nhưng nó được tách biệt rất rõ với protobuf, và protobuf tuy có một số tính năng liên quan đến gRPC
Chính sự đan xen này khiến mỗi lần so sánh với capnp, tôi lại nghiêng về flatbuffers hoặc protobuf. Đặc biệt vì các implementation của fb và pb đơn giản hơn nhiều, và tôi đánh giá rất cao sự đơn giản xét về bảo mật và bảo trì
Việc thiếu các implementation ngôn ngữ bên thứ ba tốt cũng là một tín hiệu trực tiếp cho thấy phán đoán này là hợp lý. Bus factor và khả năng tồn tại lâu dài cũng rất tệ. Sự đơn giản sẽ thắng
Phiên bản Rust cũng đòi hỏi một lối sống mang tính quy phạm riêng. Phần lớn trong đó có lý trong thế giới không sao chép, nhưng vẫn khiến nhiều cách biểu đạt trở nên khó và tài liệu cũng khó đọc
Vì vậy chỉ riêng lý do này thôi, thường tôi sẽ chọn flatbuffers
Dù vậy, tôi vẫn hy vọng một ngày nào đó sẽ có tình huống cap'n'proto là cần thiết và hữu ích, và muốn hoàn thành dù chỉ một trong số nhiều dự án sở thích mà tôi đã fork suốt nhiều năm để thử dùng nó. Đúng là nó có kỹ thuật chất lượng cao
Không mới, nhưng tôi tò mò không biết cái tên này có phải là một lời tri ân có chủ ý đến Star Trek Voyager, hay còn có tham chiếu nào khác mà tôi không biết
https://memory-alpha.fandom.com/wiki/Captain_Proton
Tên Cap'n Proto ban đầu có nghĩa là Capabilities and Protobufs. Nó từng là một giao thức RPC dựa trên năng lực, xây trên Protocol Buffers. Nhưng từ rất sớm, tôi đã muốn thử một định dạng tuần tự hóa hoàn toàn khác. Dù vậy, “Proto” vẫn hợp lý theo nghĩa là protocol, nên tôi giữ lại tên đó
Cách chơi chữ “cerealization protocol” thật ra là do người khác chỉ cho tôi, nhưng tôi đã thêm ngay vào logo
Có vẻ là Serialization/RPC, chắc là lỗi gõ nhầm.