9 คะแนน โดย GN⁺ 2025-11-01 | 2 ความคิดเห็น | แชร์ทาง WhatsApp
  • Apache Fory Rust คือ เฟรมเวิร์กซีเรียลไลซ์ข้ามภาษา ที่มอบ ประสิทธิภาพการซีเรียลไลซ์ความเร็วสูงมาก และ การจัดการรีเฟอเรนซ์อัตโนมัติ
  • สร้างบนพื้นฐานของ เทคโนโลยี zero-copy และ type safety ของ Rust พร้อมจัดการ circular references, trait objects และ schema evolution โดยอัตโนมัติ
  • รองรับการแลกเปลี่ยนข้อมูลระหว่างภาษาอย่าง Rust, Python, Java, Go และอื่น ๆ โดยไม่ต้องมีไฟล์ IDL หรือการ generate code
  • ผลการทดสอบ benchmark ระบุว่ามี ความเร็วในการประมวลผลมากกว่า JSON และ Protobuf กว่า 10–20 เท่า
  • มีคุณค่าสูงสำหรับการใช้งานในสภาพแวดล้อมที่ต้องการสมรรถนะสูง เช่น microservices, data pipelines และระบบเรียลไทม์

ภาวะกลืนไม่เข้าคายไม่ออกของการซีเรียลไลซ์ และการมาของ Apache Fory Rust

  • วิธีซีเรียลไลซ์แบบเดิมมีข้อจำกัดที่ต้องยอมเสียอย่างใดอย่างหนึ่งระหว่าง ความเร็ว ความยืดหยุ่น และความเข้ากันได้ข้ามภาษา
    • ฟอร์แมตไบนารีที่ทำเองเร็วก็จริง แต่เปราะบางต่อการเปลี่ยน schema
    • JSON/Protobuf ยืดหยุ่น แต่มี performance overhead มากกว่า 10 เท่า
    • โซลูชันเดิม ๆ รองรับความสามารถเฉพาะภาษายังไม่ดีพอ
  • Apache Fory Rust ให้ทั้งประสิทธิภาพและความยืดหยุ่นพร้อมกัน โดย ไม่จำเป็นต้องใช้ IDL หรือจัดการ schema แบบแมนนวล

คุณสมบัติหลัก

  • 1. รองรับข้ามภาษาอย่างแท้จริง

    • ใช้ binary protocol เดียวกันร่วมกันได้ใน Java, Python, C++, Go และภาษาอื่น ๆ
    • ข้อมูลที่ซีเรียลไลซ์ใน Rust สามารถนำไป deserialize ใน Python ได้โดยตรง
    • ไม่มีปัญหาเรื่องไฟล์ schema, การ generate code หรือ version mismatch ช่วยให้การแลกเปลี่ยนข้อมูลระหว่าง microservices หลายภาษาง่ายขึ้น
  • 2. จัดการ circular/shared references อัตโนมัติ

    • ติดตามและคงโครงสร้าง circular references ที่เฟรมเวิร์กส่วนใหญ่มักจัดการไม่ได้โดยอัตโนมัติ
    • แม้อ้างอิงอ็อบเจ็กต์เดียวกันหลายครั้ง ก็จะ ซีเรียลไลซ์เพียงครั้งเดียว และคงเอกลักษณ์ของรีเฟอเรนซ์ไว้
    • เหมาะกับ graph databases, ORM และโดเมนโมเดลที่ซับซ้อน
  • 3. การซีเรียลไลซ์ trait objects

    • รองรับ การซีเรียลไลซ์ trait objects เช่น Box ของ Rust
    • สามารถลงทะเบียน polymorphic types ได้ด้วยแมโคร register_trait_type!
    • รองรับหลายรูปแบบ เช่น Box, Rc, Arc, dyn Any
    • ทำให้สร้าง plugin systems, heterogeneous collections และสถาปัตยกรรมที่ขยายต่อได้
  • 4. Schema evolution (compatible mode)

    • อนุญาตให้เปลี่ยน schema ระหว่างเวอร์ชันของบริการได้ด้วย Compatible mode
      • เพิ่ม ลบ เปลี่ยนลำดับฟิลด์ และแปลงเป็น option type ได้
      • แต่ไม่รองรับการเปลี่ยนชนิดข้อมูล
    • มีประโยชน์ต่อ การ deploy แบบไม่หยุดระบบ และ การพัฒนา microservices แบบอิสระ

พื้นฐานทางเทคนิค

  • การออกแบบโปรโตคอล

    • โครงสร้าง: | fory header | reference meta | type meta | value data |
    • ใช้ จำนวนเต็มความยาวแปรผัน, metadata แบบบีบอัด, การติดตามรีเฟอเรนซ์ และ little-endian layout
    • เพิ่มประสิทธิภาพด้วย การตัดความซ้ำซ้อนของ shared objects และ การบีบอัด type metadata
  • การ generate code ตอน compile time

    • ใช้ การ generate code ด้วยแมโครแทน reflection เพื่อตัด runtime overhead
    • แมโคร #[derive(ForyObject)] จะสร้างฟังก์ชัน serialize/deserialize ให้อัตโนมัติ
    • ช่วยให้ คง type safety, ลดขนาดไบนารี และรองรับ IDE autocomplete
  • องค์ประกอบสถาปัตยกรรม

    • fory/: API ระดับสูง
    • fory-core/: เอนจินซีเรียลไลซ์ (buffer I/O, การลงทะเบียนชนิดข้อมูล, การบีบอัด metadata ฯลฯ)
    • fory-derive/: คำจำกัดความ procedural macro
    • โครงสร้างแบบ แยกโมดูล ช่วยให้ดูแลรักษาและขยายระบบได้ง่าย

ผลการทดสอบ Benchmark

  • เร็วกว่า JSON และ Protobuf มากกว่า 10–20 เท่า
  • ตัวอย่าง:
    • simple_struct(small) → Fory 35,729,598 TPS / JSON 10,167,045 / Protobuf 8,633,342
    • person(medium) → Fory 3,839,656 TPS / JSON 337,610 / Protobuf 369,031
  • ในทุกเคสทดสอบ Fory ทำผลงานได้ดีที่สุด

สถานการณ์การใช้งาน

  • กรณีใช้งานที่เหมาะสม

    • microservices หลายภาษา: แลกเปลี่ยนข้อมูลได้โดยไม่ต้องมีไฟล์ schema
    • data pipelines ประสิทธิภาพสูง: ประมวลผลได้หลายล้านเรกคอร์ดต่อวินาที
    • โดเมนโมเดลที่ซับซ้อน: รองรับโครงสร้างแบบ circular references และ polymorphism
    • ระบบเรียลไทม์: latency ต่ำกว่า 1ms พร้อม zero-copy deserialization
  • ทางเลือกอื่นที่ควรพิจารณา

    • หากต้องการฟอร์แมตที่มนุษย์อ่านง่าย → JSON/YAML
    • หากต้องการฟอร์แมตสำหรับเก็บระยะยาว → Parquet
    • หากเป็นโครงสร้างข้อมูลเรียบง่าย → serde + bincode

เริ่มต้นใช้งาน

  • การติดตั้ง

    • เพิ่มใน Cargo.toml:
      [dependencies]  
      fory = "0.13"  
      
  • ตัวอย่างการซีเรียลไลซ์พื้นฐาน

    • ลงทะเบียน struct ด้วย #[derive(ForyObject)] แล้วใช้ serialize() / deserialize()
    • ลงทะเบียน type ID เพื่อคงความสอดคล้องของข้อมูล
  • การซีเรียลไลซ์ข้ามภาษา

    • เปิดใช้งานโหมดรองรับหลายภาษาด้วยการตั้งค่า compatible(true).xlang(true)
    • รองรับการลงทะเบียนตาม ID หรือชื่อ (register_by_namespace, register_by_name)

ชนิดข้อมูลที่รองรับ

  • ชนิดพื้นฐาน: bool, จำนวนเต็ม, จำนวนทศนิยม, String
  • คอลเลกชัน: Vec, HashMap, BTreeMap, HashSet, Option
  • สมาร์ตพอยน์เตอร์: Box, Rc, Arc, RcWeak, ArcWeak, RefCell, Mutex
  • วันที่/เวลา: ชนิดข้อมูลของ chrono
  • อ็อบเจ็กต์ที่ผู้ใช้กำหนดเอง: ForyObject, ForyRow
  • trait objects: Box/Rc/Arc, Rc/Arc

โรดแมป

  • สิ่งที่มีใน v0.13

    • static code generation, zero-copy Row format, การติดตาม circular references, การซีเรียลไลซ์ trait objects, schema compatible mode
  • ฟีเจอร์ที่กำลังจะมา

    • การซีเรียลไลซ์รีเฟอเรนซ์ข้ามภาษา, การอัปเดต Row บางส่วน

ข้อควรพิจารณาสำหรับโปรดักชัน

  • ความปลอดภัยของเธรด: หลังลงทะเบียนเสร็จแล้วสามารถแชร์ผ่าน Arc ได้ (Send + Sync)
  • การจัดการข้อผิดพลาด: อิง Result และแยกข้อผิดพลาดอย่างชัดเจน เช่น ชนิดข้อมูลไม่ตรงกันหรือบัฟเฟอร์ไม่เพียงพอ

เอกสารและชุมชน

  • เอกสารทางการ: fory.apache.org/docs
  • เอกสาร API: docs.rs/fory
  • ชุมชน: มี GitHub, Slack และ Issue Tracker
  • โอเพนซอร์สภายใต้ Apache License 2.0

สรุป

  • Apache Fory Rust คือ เฟรมเวิร์กซีเรียลไลซ์ยุคใหม่ที่ขจัดการต้องแลกกันระหว่างประสิทธิภาพ ความยืดหยุ่น และความเข้ากันได้ข้ามภาษา
  • ด้วย ระบบอัตโนมัติบนพื้นฐานแมโคร, การรองรับ trait objects และ การจัดการ circular references จึงช่วยเพิ่มประสิทธิภาพการพัฒนาได้อย่างมาก
  • พร้อมนำไปใช้ได้ทันทีใน microservices, data pipelines และระบบเรียลไทม์

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

 
qlghwp123 2025-11-01

ประสิทธิภาพแบบนี้เป็นไปได้จริงเหรอ?

 
GN⁺ 2025-11-01
ความคิดเห็นจาก Hacker News
  • อยากให้โฟกัสกับการพัฒนา tooling ของเทคโนโลยีที่มีอยู่แล้วอย่าง W3C EXI(Binary XML) มากกว่าการสร้างฟอร์แมตใหม่
    แค่เร็วอย่างเดียวไม่พอ และฟอร์แมตที่ไม่มี ecosystem แบบ Aeron/SBE ก็ขยายการใช้งานได้ยาก ส่วน XML มี ecosystem นี้อยู่แล้ว

    • การเข้ารหัสแบบ Binary XML มีประโยชน์ในบางสถานการณ์ แต่ไม่มีประสิทธิภาพเท่าฟอร์แมต binary serialization สมัยใหม่
      อีกทั้งยังไม่สามารถแสดง object graph ที่ซับซ้อนอย่าง shared reference หรือ circular reference ได้อย่างเป็นธรรมชาติ
      ฟอร์แมต Fory ถูกออกแบบมาตั้งแต่ต้นเพื่อแก้ปัญหาเหล่านี้ พร้อมรองรับความเข้ากันได้ข้ามภาษาและการวิวัฒน์ของสคีมา
    • ไม่แน่ใจว่า W3C EXI หรือ ASN.1 BER อันไหนดีกว่ากัน แต่คิดว่าแนวทางแบบ DOP(data-oriented design) น่าจะถูกต้อง
      กล่าวคือควรออกแบบ encoding ก่อน แล้วค่อยขยายย้อนกลับไปยังภาษาและไคลเอนต์
  • สงสัยว่า benchmark ยุติธรรมหรือไม่
    ดูจากโค้ดลิงก์ จะเห็นว่าในกรณีที่ไม่ใช่ Fory struct มีการรวมขั้นตอน แปลง to/from เข้าไปใน serialization ด้วย
    กระบวนการแปลงนี้ทำให้เกิดการคัดลอกสตริงหรือการจัดสรรอาร์เรย์ใหม่
    ในระบบจริง tonic มีบัฟเฟอร์ 8KB ให้ จึงน่าจะมีประสิทธิภาพกว่า Vec::default() แบบธรรมดา

    • benchmark นี้ ไม่ยุติธรรม
      บน CPU Xeon Gold 6136 มันดูเหมือนเร็วขึ้น 10 เท่า แต่ถ้าตัดการแปลง to/from และการคัดลอก Vec ออก แล้วจองบัฟเฟอร์ 8KB ไว้ล่วงหน้า ผลจริงจะอยู่ราว 3 เท่า
      benchmark ควรถูกเขียนใหม่ในสไตล์ tower service/codec ที่ไม่มีโค้ดเฉพาะของ Fory ปะปนเลย
      Fory ใช้ writer pool ระหว่างการทดสอบ
      ดูโค้ดที่เกี่ยวข้อง
  • ในระยะยาว ถ้าต้องการรักษาความเข้ากันได้ข้ามภาษา คิดว่าจำเป็นต้องมี สัญญาที่ระบุไว้ชัดเจนบนพื้นฐาน IDL
    แนวทางที่เริ่มจากภาษาแล้วค่อยทำ serialization แม้จะสะดวกในช่วงแรก แต่เมื่อเวลาผ่านไปจะเปราะบางต่อการเปลี่ยนแปลงของ runtime ของภาษา

    • ยิ่งมีหลายภาษา สคีมาอย่างเป็นทางการ ก็ยิ่งสำคัญ
      โปรเจ็กต์ภาษาเดียวอาจคงความเรียบง่ายได้โดยไม่ต้องมี IDL แต่พอเกินสามภาษา IDL จะทำหน้าที่เป็น single source of truth
      Apache Fory มีแผนจะเพิ่มการรองรับ IDL แบบเลือกใช้ได้ เพื่อให้ทีมเลือกแนวทางแบบยึดภาษานำหรือยึดสคีมานำตามสถานการณ์ได้
  • สงสัยว่าหากไม่มีสคีมา จะรักษา shared type ข้ามภาษาอย่างไร

    • มีตาราง type mapping อยู่
      ในภาษาแบบมี type จะอนุมานสคีมาจากการประกาศคลาส ส่วนภาษาแบบไม่มี type จะใช้การใส่ annotation ลงในโค้ดโดยตรง
      ตัวอย่าง Python ดูได้ที่นี่
    • การบอกว่าทีมแบบหลายภาษา(polyglot) เป็น use case หลัก แต่ขณะเดียวกันก็ไม่ต้องมีไฟล์สคีมา ฟังดูชวนสับสน
      ดูบล็อกโพสต์ที่เกี่ยวข้อง
    • ยังสงสัย ว่าแนวทางนี้จะเวิร์กดีในระยะยาวหรือไม่
    • คำอธิบายเรื่องการใช้งานจริงใน production ยังมีน้อยเกินไป เลยยังไม่น่าเชื่อถือ
  • สงสัยว่าทำไมถึงควรใช้ Fory แทน ฟอร์แมตแบบไม่ต้อง deserialize อย่าง CapnProto หรือ Flatbuffers
    ถ้าต้องการบีบอัดก็ใช้ zstd ได้
    ถึงอย่างนั้น การรองรับหลายภาษาอย่างกว้างขวาง และความสะดวกในการใช้งานของ Fory ก็น่าประทับใจ
    บน Python ก็ยังชอบ dill มากกว่า เพราะมัน serialize ได้แม้กระทั่ง code object
    ลิงก์ dill

    • จากผล benchmark ที่เทียบกับ dill, Fory เร็วกว่า 20~40 เท่าและมีอัตราการบีบอัดดีกว่าสูงสุด 7 เท่า
      ดูโค้ด benchmark
    • Apache Fory ใช้เป็น ตัวแทนของ pickle/cloudpickle ได้ด้วย และยังรองรับ การ serialize code object เช่น local function หรือ class
      ลิงก์ตัวอย่าง
      pyfory มีอัตราการบีบอัดดีกว่า cloudpickle 3 เท่า และมี ฟีเจอร์ตรวจสอบความปลอดภัย เพื่อป้องกันการโจมตีจาก malicious deserialization
  • ลิงก์ benchmark เป็น 404 แต่เจอลิงก์ที่ถูกต้อง

  • น่าเสียดายที่เปลี่ยนชื่อจาก “Fury” เป็น “Fory”
    Fury เป็นชื่อที่เหมาะกับเฟรมเวิร์ก serialization เร็ว ๆ มาก

    • “Fury” เป็นชื่อที่ฉันตั้งเองแต่แรกเลยผูกพันกับมันอยู่เหมือนกัน แต่สุดท้ายก็จำเป็นต้องเปลี่ยน
  • โปรโตคอลไบนารี ส่วนใหญ่มุ่งลดขนาดข้อมูล
    Protobuf ใช้การบีบอัดจำนวนเต็ม(varint, zigzag)
    ถ้าเทียบแค่ TPS อย่างเดียว วิธี “do nothing” ที่ส่ง C struct ตรง ๆ ก็ย่อมชนะอยู่แล้ว

    • Fory ก็รองรับการบีบอัดจำนวนเต็มเช่นกัน และมี ขนาดข้อมูลแทบเท่ากับ Protobuf
      มีการแสดงตารางเปรียบเทียบกับชุดข้อมูลหลายแบบ
    • มี โหมดความเข้ากันได้ของสคีมา อยู่สองแบบ แต่ไม่มี การรับประกันความเข้ากันได้ของไบนารี ระหว่าง minor version
  • สงสัยว่าข้อจำกัด 4096 type ของ Fory เพียงพอหรือไม่
    ดูโค้ดที่เกี่ยวข้อง

    • อาจไม่พอสำหรับทุกกรณี แต่ถ้าจำเป็นก็ขยายได้
      ที่ผ่านมายังแทบไม่เคยเห็นกรณีที่นิยาม protocol message เกิน 4096 แบบจริงจัง
  • ลิงก์ Rust benchmark ให้ข้อผิดพลาด 404
    จากรากเอกสาร ก็หาไดเรกทอรี benchmark ไม่เจอ