7 คะแนน โดย GN⁺ 3 시간 전 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • libzstd-rs-sys เป็นโปรเจกต์บีบอัดลำดับที่สามของมูลนิธิ Trifecta ต่อจาก zlib·bzip2 และเป็นรีลีสแรกของ zstd ที่พัฒนาบน Rust
  • Zstd เป็นฟอร์แมตการบีบอัดที่ออกแบบมาสำหรับ CPU สมัยใหม่ มีทั้งความเร็วมากกว่า gzip และอัตราการบีบอัดที่ดีกว่า จึงคาดว่าจะค่อย ๆ เข้ามาแทนที่ gzip ในทราฟฟิกเว็บ
  • zstd crate บน Rust ที่มีอยู่เดิมคอมไพล์โค้ด C จากซอร์ส จึงต้องใช้ C toolchain และการรองรับเป้าหมาย ทำให้การตั้งค่าบน Windows·WebAssembly อาจยุ่งยาก
  • อิมพลีเมนเทชัน Rust สามารถคอมไพล์เป็น ไลบรารี C ที่เข้ากันได้แบบ drop-in และกำลังตรวจสอบทางเลือกแทน C reference implementation ด้วย test suite·fuzz testing·Miri
  • การคลายการบีบอัดแบบพื้นฐานช้ากว่า C อยู่ไม่กี่เปอร์เซ็นต์ แต่การลดลงราว 3% เป็นต้นทุนของ memory safety และสามารถใช้แฟล็กทดลองเพื่อให้ได้ประสิทธิภาพเทียบเท่า C

รีลีสแรกและความหมายของการพัฒนาด้วย Rust

  • Trifecta Tech Foundation ประกาศรีลีสแรกของ libzstd-rs-sys ซึ่งดูแล zstd เป็นโปรเจกต์บีบอัดลำดับที่สามต่อจาก zlib และ bzip2
  • Zstd เป็นฟอร์แมตการบีบอัดที่ออกแบบโดยคำนึงถึง CPU สมัยใหม่ ทำงานได้เร็วกว่า gzip มากและให้อัตราการบีบอัดที่ดีกว่า
  • zstd ถูกใช้งานอย่างแพร่หลายอยู่แล้ว และคาดว่าจะค่อย ๆ เข้ามาแทนที่ gzip ในทราฟฟิกเว็บ
  • ใน Rust มีการใช้งาน zstd ได้อยู่แล้วผ่าน crate zstd แต่ crate เดิมคอมไพล์โค้ด C จากซอร์ส จึงต้องใช้ C toolchain และการรองรับสำหรับเป้าหมาย
  • การตั้งค่า C toolchain สำหรับ Windows หรือ WebAssembly อาจทำได้ยาก ดังนั้นอิมพลีเมนเทชัน Rust ล้วนจึงมอบประสบการณ์การใช้ dependency ที่ดีกว่าสำหรับนักพัฒนา Rust
  • libzstd-rs-sys สามารถคอมไพล์เป็น ไลบรารี C ที่เข้ากันได้แบบ drop-in ได้เช่นเดียวกับงานของ zlib·bzip2 และมีเป้าหมายเป็นทางเลือกแทน C reference implementation
  • C reference implementation ได้รับการดูแลโดย Meta และการมีส่วนร่วมต้องทำข้อตกลง Contributor Agreement กับ Meta ดังนั้นการมีอิมพลีเมนเทชันที่เป็นอิสระ มีประสิทธิภาพดี และเข้ากันได้ จึงช่วยเสริมความแข็งแกร่งให้ระบบนิเวศโอเพนซอร์สได้

การตรวจสอบ ประสิทธิภาพ และงานที่เหลือ

  • reference implementation ระยะแรกถูกแปลงด้วย c2rust และหลังจากนั้นได้จัดระเบียบส่วนการคลายการบีบอัดและ dictionary builder เสร็จสิ้นแล้ว
  • โค้ด Rust ถูกคอมไพล์เป็นไลบรารีสแตติกของ C แล้วตรวจสอบด้วย test suite ของ reference implementation
  • ยังใช้ fuzz testing และ Miri เพื่อตรวจสอบความถูกต้องของอิมพลีเมนเทชัน
  • พรีรีลีสมีให้ที่ libzstd-rs-sys v0.0.1-prerelease.2
  • ต้นทุนของ memory safety

    • ประสิทธิภาพการคลายการบีบอัดแบบพื้นฐานช้ากว่า C reference implementation อยู่ไม่กี่เปอร์เซ็นต์
    • ทุกการเปลี่ยนแปลงที่ merge เข้าสู่ main จะถูกวัดด้วย benchmark suite
    • หากเปิดใช้ feature flag unsafe-performance-experimental จะได้ประสิทธิภาพ เทียบเท่า C
    • แฟล็กนี้จะปิดการตรวจสอบขอบเขตใน 4 จุดที่ใช้ข้อมูลอินพุตไปทำ indexing ของโครงสร้างข้อมูล
    • สำหรับผู้ใช้ส่วนใหญ่ การลดลงของประสิทธิภาพราว 3% น่าจะเป็นต้นทุนที่ยอมรับได้เพื่อแลกกับ memory safety ที่ดีขึ้น
    • หากต้องการรีดประสิทธิภาพขั้นสุดท้าย ก็สามารถยอมรับความเสี่ยงแล้วเปิดแฟล็กนี้ได้ โดยพฤติกรรมใน 4 จุดดังกล่าวจะสอดคล้องกับ C ที่ไม่มีการตรวจสอบขอบเขต
  • การพัฒนา compression และการผสานเข้ากับระบบนิเวศ

    • ส่วนของ compression ยังอยู่ระหว่างการหาเงินทุน
    • มีการแชร์โค้ดระหว่าง compression และ decompression จึงได้ตรวจดูโค้ดฝั่ง compression ไปบ้างแล้ว แต่การจัดระเบียบส่วนใหญ่ยังคงเหลืออยู่
    • มีการตั้ง benchmark เพื่อป้องกันประสิทธิภาพของ compression ถดถอย และกำลังตรวจสอบว่าผลลัพธ์ที่สร้างขึ้นถูกต้องหรือไม่ด้วย test suite ของ reference implementation
    • งานที่เหลือสรุปไว้ใน Milestone 4: Encoder implementation
    • มี zstd fork ที่ใช้ libzstd-rs-sys แทนไลบรารี C และต้องการผลักดันให้ถูกรวมเข้าต้นน้ำในอนาคต
    • สำหรับ API ที่ถูกใช้งานมากที่สุด การผสานรวมค่อนข้างตรงไปตรงมา
    • ในฟีเจอร์ experimental มีความไม่สอดคล้องกันตรงที่ zstd-safe ใช้ enum แต่เพื่อความปลอดภัยของ FFI จำเป็นต้องใช้ struct
  • การสนับสนุน

1 ความคิดเห็น

 
GN⁺ 3 시간 전
ความคิดเห็นจาก Lobste.rs
  • ข่าวนี้น่ายินดีมาก เมื่อไม่กี่วันก่อนผมต้องดึง libc-dev เข้ามาเพื่อจะ build zstd เพราะมี dependency ตัวหนึ่ง เลยสงสัยว่ามีใครเคยลอง reimplement แบบจริงจังด้วย Rust บ้างไหม
    หวังว่าจะถูกชุมชนนำไปใช้อย่างแพร่หลาย

  • ผมกำลังทำโปรเจ็กต์ที่อิงกับ WireGuard ด้วย Rust เลยดึงไลบรารีเข้ารหัสของ Rust มาหลายตัว ข้อดีเรื่อง memory safety นั้นชัดเจน แต่ต่างจากไลบรารี C เก่าแก่ตรงที่ไม่ได้ผ่าน security audit กันทั้งหมด
    สุดท้ายสิ่งที่ผมสงสัยคือ การเขียนอัลกอริทึมเหล่านี้ใหม่ด้วย Rust คุ้มกับต้นทุนที่ต้องจ่ายหรือไม่

    • คุ้มมาก การโจมตีระบบเข้ารหัสจำนวนมากไม่ได้เกิดจากตัวอัลกอริทึมถูกทำลาย แต่เกิดจาก implementation flaw ที่ทำให้ถูกเลี่ยงได้
      โค้ดที่ “น่าเบื่อ” และไม่ใช่ส่วนเข้ารหัสอย่าง parsing, protocol state, buffer management ต้องทำงานให้ถูกต้อง ระบบถึงจะปลอดภัย ถ้าผู้โจมตีส่งแพ็กเก็ตวิเศษที่ทำให้รันโค้ดตามอำเภอใจได้ พวกเขาก็ไม่จำเป็นต้องพึ่งการวิเคราะห์คริปโตขั้นสูงหรือ timing side-channel ที่ลดเวลาถอดรหัสจากหลักพันปีเหลือหลักสิบปี
    • ถ้าข้อกำหนดด้านประสิทธิภาพของโปรเจ็กต์ไม่ได้ตึงมากเกินไป และพอยอมรับ FFI ได้บ้าง ก็สามารถใช้สแตกเข้ารหัสของ Go จากใน Rust ได้
      ทั้งสองฝั่งมี memory safety และมีข้อดีตรงที่ต้องมีเพียงขอบเขต unsafe FFI ที่แคบมากเท่านั้น ตอนนี้ไลบรารีเข้ารหัสของ Go มีความสุกงอมมากกว่าสิ่งที่ Rust หรือพูดให้ชัดคือ ecosystem บน crates.io มีให้
  • มีใครรู้แหล่งอธิบายที่จัดทำเป็นเอกสารไหมว่าเมื่อไรควรใช้ suffix -sys กับ -rs-sys? ตามสัญชาตญาณผมคิดว่า -sys ใช้กับ crate ที่ครอบ system library ซึ่งไม่ได้เขียนด้วย Rust
    แต่กรอบคิดนั้นทำให้ -rs-sys ดูไม่ค่อยสมเหตุสมผล เลยเดาว่าสัญชาตญาณของผมน่าจะผิด มีใครรู้แหล่งอ้างอิงที่เชื่อถือได้ไหม?

    • ชื่อแพ็กเกจนี้ตั้งได้แย่เกือบสุดเท่าที่จะจินตนาการได้ สามในสี่ส่วนของชื่อนั้นผิดหรือไม่น่าพึงประสงค์
      *-sys: เป็นธรรมเนียมเก่าและใช้กันแพร่หลาย อธิบายไว้ที่ https://doc.rust-lang.org/cargo/reference/… แต่ไม่เข้ากับ crate นี้เลยแม้แต่น้อย
      lib*: เรารู้อยู่แล้วว่านี่คือ library และใน Rust ก็ไม่ใช่ prefix ตามธรรมเนียม อีกทั้งลิงก์ข้างบนก็ชี้แบบเกือบตรง ๆ ว่าควรหลีกเลี่ยงควบคู่กับ *-sys ถ้าเป็น libzstd-sys คนอาจคาดว่าจะลิงก์กับ liblibzstd และขอเสริมว่าแม้นอกโลก Rust ผมก็เคยเห็นชื่อ lib ซ้อนสองชั้นจริง ๆ
      *-rs: ตามที่ https://rust-lang.github.io/api-guidelines/naming.html บอกไว้ว่า “ทุก crate ก็คือ Rust อยู่แล้ว! ไม่จำเป็นต้องคอยย้ำเตือนผู้ใช้ตลอดเวลา”
    • โดยทั่วไป crate แบบ -sys จะเปิดเผย อินเทอร์เฟซแบบ C ที่ดิบมาก มีโค้ด unsafe อยู่ข้างในเยอะ และมัก build หรือลิงก์กับไลบรารีภายนอก
      ส่วนชื่อ -rs-sys ผมเห็นว่าถูกใช้อย่างไม่ค่อยสม่ำเสมอ ดูเหมือนจะใช้กับไลบรารีที่ build โค้ดภายนอกซึ่งถูกห่อไว้อีกชั้นใน Rust crate เช่น Rust implementation ที่ยังทำไม่เสร็จและยังมีส่วน C เหลืออยู่ หรือ Rust support code สำหรับ sys crate
    • มันก็มีตรรกะของมันอยู่
      libzstd คือชื่อดั้งเดิม ไลบรารี C มักมี lib อยู่ในชื่อ และเขาก็เก็บชื่อนั้นไว้เพื่อการอ้างอิงแทนที่จะเปลี่ยนให้เข้ากับธรรมเนียมของ Rust/Cargo
      -rs ใช้บอกว่าเป็น Rust rewrite เพื่อแยกจาก C implementation ของ Facebook เป็น suffix ทั่วไปที่หลายโปรเจ็กต์ Rust ใช้กัน คล้ายกับที่ไลบรารี Python ตั้งชื่อแบบ pysomething
      -sys มีไว้เพราะ implementation นี้เป็น drop-in replacement ที่เปิดเผย unsafe C API จากมุมมองของผู้ใช้ Cargo มันไม่ใช่ไลบรารี Rust ไม่มี Rust interface และถูกเรียกใช้เหมือน C code ที่เป็น C function
      ดังนั้นมันจึงไม่ใช่ -rs-sys แต่เป็นเวอร์ชัน -sys ของ libzstd-rs
  • ทำไมต้องเลือกตัวนี้แทน ruzstd? หรือว่าควรไปลงทุนกับ crate ที่มีอยู่เดิมมากกว่า?

    • ruzstd ยัง implement ส่วนการบีบอัดได้ไม่ครบ
      การ port แบบ 1:1 ทำให้สามารถได้ทั้งความเร็วใกล้เคียงและความสามารถเทียบเท่า ผ่านการแปลงโค้ดที่ค่อนข้างตรงไปตรงมา แทนที่จะต้องกลับไปหาคำตอบใหม่ว่าจะสร้างตัวบีบอัดที่เร็วและครบถ้วนเท่ากันบนอีก codebase หนึ่งได้อย่างไร
  • “reference implementation ฝั่ง C ถูกดูแลโดย Meta และถ้าจะร่วม contribute ต้องเซ็น contributor agreement กับ Meta”
    ผมเพิ่งรู้ข้อเท็จจริงที่น่าสนใจเมื่อไม่นานมานี้ว่า zstd implementation อ้างอิงที่ Facebook ดูแลอยู่นั้นก็ใช้ LLM เขียนโค้ดเช่นกัน และยังเป็น dependency ของ openssl ด้วย ดังนั้นผมสนับสนุนเต็มที่ถ้าจะมีทางเลือกเพิ่มขึ้น

  • “ในค่าตั้งต้น ประสิทธิภาพการคลายการบีบอัดของ implementation เราช้ากว่า C reference implementation อยู่ไม่กี่เปอร์เซ็นต์”
    แค่นี้ก็เพียงพอแล้วสำหรับสิ่งที่ต้องรู้เกี่ยวกับโปรเจ็กต์นี้

    • ช่วยอธิบายเพิ่มได้ไหมว่าคุณรู้สึกอย่างไรกับประโยคนั้น?
      เพื่ออ้างอิง เนื้อหาถัดจากประโยคที่คุณยกมากล่าวต่อแบบนี้
      “อย่างไรก็ตาม ถ้าเปิด feature flag unsafe-performance-experimental ก็จะได้ประสิทธิภาพเท่ากับ C ดังนั้นผมคิดว่าการลดลงของประสิทธิภาพระดับนี้ถือว่าสมเหตุสมผล feature flag นี้จะปิด boundary check 4 จุดที่ใช้ข้อมูลอินพุตไปทำดัชนีโครงสร้างข้อมูล สำหรับผู้ใช้ส่วนใหญ่ การสูญเสียประสิทธิภาพราว 3% น่าจะเป็นต้นทุนที่ยอมรับได้เพื่อแลกกับ memory safety ที่ดีขึ้น หากต้องการรีดประสิทธิภาพขั้นสุดท้ายจริง ๆ ก็สามารถเปิด flag นี้ได้โดยรับความเสี่ยงเอง พฤติกรรมใน 4 จุดนี้จะเหมือนกับ C ที่ไม่ทำ boundary check และดูเหมือนว่าจะทำงานได้โดยไม่มีปัญหาใน production system จำนวนมาก”