7 điểm bởi GN⁺ 3 giờ trước | 1 bình luận | Chia sẻ qua WhatsApp
  • libzstd-rs-sys là dự án nén thứ ba của Quỹ Trifecta sau zlib và bzip2, đồng thời là bản phát hành zstd đầu tiên dựa trên Rust
  • Zstd là định dạng nén được tối ưu cho CPU hiện đại, nhanh hơn gzip và cũng có tỷ lệ nén cao hơn, nên được kỳ vọng sẽ dần thay thế gzip trong lưu lượng web
  • Crate zstd hiện có cho Rust biên dịch mã C từ source, nên cần toolchain C và hỗ trợ cho mục tiêu đích, khiến việc thiết lập trên Windows và WebAssembly có thể khó khăn
  • Bản triển khai bằng Rust có thể được biên dịch thành thư viện C tương thích drop-in, và đang được kiểm chứng như một lựa chọn thay thế cho bản triển khai tham chiếu C bằng test suite, fuzz test và Miri
  • Giải nén mặc định chậm hơn C vài phần trăm, nhưng mức giảm hiệu năng khoảng 3% là cái giá cho an toàn bộ nhớ, và có thể đạt hiệu năng ngang C bằng cờ thử nghiệm

Bản phát hành đầu tiên và ý nghĩa của bản triển khai Rust

  • Trifecta Tech Foundation đã công bố bản phát hành đầu tiên của libzstd-rs-sys, dự án xử lý zstd, là dự án nén thứ ba sau zlibbzip2
  • Zstd là định dạng nén được thiết kế với CPU hiện đại trong đầu, có thể nhanh hơn đáng kể và đạt tỷ lệ nén tốt hơn gzip
  • zstd đã được sử dụng rộng rãi và được kỳ vọng sẽ dần thay thế gzip trong lưu lượng web
  • Trong Rust, zstd đã có thể được sử dụng qua crate zstd, nhưng crate hiện tại biên dịch mã C từ source nên cần toolchain C và hỗ trợ cho mục tiêu đích
  • Việc thiết lập toolchain C cho Windows hoặc WebAssembly có thể khó, vì vậy một bản triển khai thuần Rust mang lại trải nghiệm dùng dependency tốt hơn cho nhà phát triển Rust
  • Giống như các công việc với zlib và bzip2, libzstd-rs-sys có thể được biên dịch thành thư viện C tương thích drop-in và hướng tới mục tiêu trở thành lựa chọn thay thế cho bản triển khai tham chiếu C
  • Bản triển khai tham chiếu C do Meta bảo trì và yêu cầu ký thỏa thuận đóng góp với Meta khi tham gia đóng góp, nên một bản triển khai độc lập, hiệu năng tốt và tương thích có thể củng cố hệ sinh thái mã nguồn mở

Kiểm chứng, hiệu năng và phần việc còn lại

  • Bản triển khai tham chiếu ban đầu được chuyển đổi bằng c2rust, sau đó việc dọn dẹp phần giải nén và dictionary builder đã hoàn tất
  • Mã Rust được biên dịch thành thư viện tĩnh C rồi được kiểm chứng bằng test suite của bản triển khai tham chiếu
  • Fuzz test và Miri cũng được dùng để kiểm chứng tính đúng đắn của bản triển khai
  • Bản pre-release được cung cấp tại libzstd-rs-sys v0.0.1-prerelease.2
  • Cái giá của an toàn bộ nhớ

    • Hiệu năng giải nén mặc định chậm hơn bản triển khai tham chiếu C vài phần trăm
    • Mỗi thay đổi được hợp nhất vào main đều được đo trên benchmark suite
    • Khi bật feature flag unsafe-performance-experimental, hiệu năng sẽ ngang với hiệu năng C
    • Cờ này vô hiệu hóa kiểm tra biên ở 4 vị trí mà dữ liệu đầu vào được dùng để lập chỉ mục cấu trúc dữ liệu
    • Với phần lớn người dùng, mức giảm hiệu năng khoảng 3% nhiều khả năng là cái giá chấp nhận được để đổi lấy an toàn bộ nhớ tốt hơn
    • Nếu cần vắt đến phần hiệu năng cuối cùng, người dùng có thể chấp nhận rủi ro và bật cờ này; hành vi ở 4 vị trí đó sẽ khớp với C vốn không kiểm tra biên
  • Triển khai nén và tích hợp hệ sinh thái

    • Phần nén vẫn đang tìm nguồn tài trợ
    • Có chia sẻ mã giữa nén và giải nén nên một phần mã nén cũng đã được xem xét, nhưng phần lớn công việc dọn dẹp vẫn còn lại
    • Benchmark để ngăn thoái lui hiệu năng nén đã được thiết lập, đồng thời đang dùng test suite của bản triển khai tham chiếu để kiểm tra việc tạo ra kết quả đúng
    • Phần việc còn lại được tổng hợp tại Milestone 4: Encoder implementation
    • Có một bản fork của zstd sử dụng libzstd-rs-sys thay cho thư viện C, và nhóm phát triển mong muốn sau này được đưa ngược lên upstream
    • Với các API được dùng nhiều nhất, việc tích hợp tương đối đơn giản
    • Ở feature experimental, có sự không khớp khi zstd-safe dùng enum nhưng vì an toàn FFI lại phải dùng struct
  • Tài trợ

1 bình luận

 
Ý kiến trên Lobste.rs
  • Đây thực sự là tin rất đáng mừng. Vài ngày trước tôi phải kéo cả libc-dev vào chỉ để build zstd vì một dependency, và đã tự hỏi liệu đã có ai nghiêm túc reimplement nó bằng Rust chưa
    Hy vọng cộng đồng sẽ chấp nhận rộng rãi

  • Tôi đang làm một dự án dựa trên WireGuard bằng Rust, nên cũng đang dùng nhiều thư viện mật mã Rust. Tính an toàn bộ nhớ là một ưu điểm rõ ràng, nhưng không phải thư viện nào cũng đã được kiểm toán bảo mật như các thư viện C lâu đời
    Rốt cuộc điều tôi băn khoăn là: việc viết lại các thuật toán này bằng Rust có thật sự đáng với chi phí bỏ ra không?

    • Hoàn toàn đáng. Mật mã bị qua mặt vì lỗi triển khai nhiều hơn rất nhiều so với việc chính thuật toán bị phá vỡ
      Những phần mã “nhàm chán” không phải mật mã như parsing, trạng thái giao thức, quản lý buffer phải hoạt động đúng thì hệ thống mới an toàn. Nếu kẻ tấn công có thể gửi một gói tin ma thuật để thực thi mã tùy ý, họ sẽ không bận tâm tới phân tích mật mã cao cấp hay side-channel timing để rút thời gian giải mã từ hàng nghìn năm xuống vài chục năm
    • Nếu yêu cầu hiệu năng của dự án không quá ngặt nghèo và bạn chấp nhận một chút FFI, thì cũng có thể dùng stack mật mã Go từ Rust
      Cả hai phía đều an toàn bộ nhớ, và bạn chỉ cần giữ ranh giới unsafe FFI thật hẹp. Các thư viện mật mã Go hiện trưởng thành hơn những gì Rust, hay chính xác hơn là hệ sinh thái crates.io, đang cung cấp
  • Tôi muốn biết liệu có ai biết tài liệu nào giải thích rõ khi nào nên dùng hậu tố -sys-rs-sys không. Theo trực giác tôi từng nghĩ -sys là dành cho crate bọc các thư viện hệ thống không được viết bằng Rust
    Nhưng trong khuôn đó thì hậu tố -rs-sys lại khó hiểu, nên có lẽ trực giác của tôi đã sai. Có ai biết nguồn có thẩm quyền nào không?

    • Tên gói này được đặt gần như tệ nhất có thể. Ba trong bốn thành phần của cái tên là sai hoặc không nên dùng
      *-sys: đây là một quy ước cũ và được dùng rộng rãi, có mô tả tại https://doc.rust-lang.org/cargo/reference/… . Nhưng nó hoàn toàn không phù hợp với crate này
      lib*: ai cũng biết đó là thư viện rồi, trong Rust tiền tố này không phải quy ước, và ở link trên cũng gần như nói thẳng là nên tránh dùng cùng *-sys. libzstd-sys còn có thể khiến người ta nghĩ nó sẽ link tới liblibzstd. Nhân tiện, ngay cả ngoài Rust tôi cũng từng thấy tên có lib lặp đôi thật
      *-rs: như https://rust-lang.github.io/api-guidelines/naming.html đã nói, “mọi crate đều là Rust! Không cần liên tục nhắc người dùng điều đó”
    • Các crate -sys thường phơi ra giao diện kiểu C rất thô, có nhiều mã unsafe bên trong, và thường build hoặc link tới thư viện bên ngoài
      Còn tên -rs-sys thì tôi thấy được dùng kém nhất quán hơn. Có vẻ nó dùng cho các thư viện build mã ngoài đã được gói lại trong một crate Rust, chẳng hạn một bản triển khai Rust còn dang dở vẫn còn phần C, hoặc mã hỗ trợ Rust cho một sys crate
    • Nó cũng có logic riêng
      libzstd là tên gốc. Thư viện C thường có lib trong tên, và thay vì đổi cho hợp quy ước Rust/Cargo thì họ giữ nguyên để tiện tham chiếu
      -rs là để phân biệt với bản triển khai C của Facebook, tức là một bản viết lại bằng Rust. Đây là một hậu tố khá phổ biến trong nhiều dự án Rust, tương tự kiểu thư viện Python đặt tên như pysomething
      -sys là vì bản triển khai này là bản thay thế drop-in phơi ra C API unsafe. Từ góc nhìn người dùng Cargo, đây không phải thư viện Rust. Nó không có giao diện Rust và được gọi như mã C với các hàm C
      Vì vậy đây không phải -rs-sys, mà là phiên bản -sys của libzstd-rs
  • Vì sao nên chọn cái này thay vì ruzstd? Có phải đầu tư vào crate hiện có sẽ tốt hơn không?

    • ruzstd vẫn chưa hoàn thiện phần nén
      Port 1:1 cho phép đạt tốc độ tương tự và tương đương tính năng bằng một quá trình chuyển đổi mã khá thẳng, thay vì phải tự tìm lại cách tạo ra một compressor nhanh và đầy đủ tương đương trên một codebase khác
  • “Bản triển khai tham chiếu bằng C do Meta duy trì, và nếu muốn đóng góp thì phải ký thỏa thuận cộng tác viên với Meta”
    Một điều thú vị tôi mới biết gần đây là bản triển khai zstd tham chiếu do Facebook quản lý cũng đang được viết code bằng LLM và còn là dependency của openssl, nên tôi hoàn toàn ủng hộ việc có thêm nhiều lựa chọn thay thế

  • “Ở cấu hình mặc định, hiệu năng giải nén của bản triển khai chúng tôi chậm hơn bản tham chiếu C vài phần trăm”
    Chỉ cần biết câu này là đủ để hiểu về dự án

    • Bạn có thể giải thích rõ hơn câu đó gợi cho bạn cảm nhận gì không?
      Để tham khảo, ngay sau câu bạn trích thì bài còn viết tiếp như sau
      “Tuy nhiên, nếu bật cờ tính năng unsafe-performance-experimental thì hiệu năng sẽ ngang với C, nên chúng tôi cho rằng mức suy giảm này là hợp lý. Cờ này tắt 4 lần kiểm tra biên tại bốn vị trí nơi dữ liệu đầu vào được dùng để lập chỉ mục cấu trúc dữ liệu. Với phần lớn người dùng, mức giảm hiệu năng khoảng 3% có lẽ là cái giá chấp nhận được để đổi lấy an toàn bộ nhớ tốt hơn. Nếu thực sự cần vắt kiệt hiệu năng cuối cùng, bạn có thể tự chịu trách nhiệm bật cờ này. Hành vi ở bốn vị trí đó sẽ giống với C không kiểm tra biên, và có vẻ đang chạy ổn trong nhiều hệ thống production”