CRDT ที่เร็วขึ้น 5000 เท่า: การผจญภัยแห่งการปรับแต่งประสิทธิภาพ
บทนำ
- เมื่อหลายปีก่อน นักวิจัยชาวฝรั่งเศสได้เผยแพร่บทความวิชาการที่เปรียบเทียบอัลกอริทึมสำหรับการแก้ไขงานร่วมกันแบบเรียลไทม์
- พวกเขาได้ติดตั้งใช้งานอัลกอริทึมหลายแบบและทำเบนช์มาร์กประสิทธิภาพ
- อัลกอริทึมบางตัวใช้เวลามากกว่า 3 วินาทีกับการวางข้อความแบบง่าย ๆ ครั้งเดียว
- อัลกอริทึมที่เป็นปัญหาคืออัลกอริทึมที่ ShareJS ใช้งาน
สาเหตุของปัญหา
- ในบทความวิชาการนั้น การวางข้อความขนาดใหญ่ถูกแยกออกเป็นงานย่อยเดี่ยว 1000 งานเพื่อประมวลผล
- นี่ไม่ใช่ปัญหาของตัวอัลกอริทึมเอง แต่เป็นปัญหาของการติดตั้งใช้งาน
เสน่ห์ของ CRDT
- CRDT (Conflict-Free Replicated Data Types) ช่วยให้ผู้ใช้หลายคนแก้ไขข้อมูลพร้อมกันได้
- สามารถทำงานบนเครื่องตัวเองได้โดยไม่มีความหน่วง และเมื่อซิงก์กันก็รักษาความสอดคล้องได้โดยอัตโนมัติ
- ทำงานได้แม้ไม่มีเซิร์ฟเวอร์กลาง
ปัญหาของ Automerge
- Automerge เป็นไลบรารีสำหรับการแก้ไขงานร่วมกัน โดยอิงกับอัลกอริทึม RGA
- มันจัดการอักขระแต่ละตัวของเอกสารด้วย ID ที่ไม่ซ้ำกัน และระบุรายการแม่เมื่อมีการแทรก
- ด้วยปัญหาด้านประสิทธิภาพ ทำให้ใช้เวลา 5 นาทีในการประมวลผลงานแก้ไข 260,000 รายการ
- การใช้หน่วยความจำก็สูงมากเช่นกัน
การปรับแต่งประสิทธิภาพ
- ปัญหาด้านประสิทธิภาพของ Automerge มีสาเหตุจากโครงสร้างข้อมูลแบบต้นไม้ที่ซับซ้อนและการใช้ Immutablejs
- Yjs ใช้ลิสต์แบนเพียงชุดเดียว ทำให้ประสิทธิภาพดีขึ้นอย่างมาก
- Yjs ใช้แคชเพื่อค้นหาตำแหน่งแทรก และใช้ doubly linked list เพื่อจัดการการแทรกได้อย่างมีประสิทธิภาพ
- Yjs เร็วกว่า 30 เท่าและใช้หน่วยความจำน้อยกว่า
การย้ายไปใช้ Rust
- Rust ช่วยควบคุม memory layout ได้ จึงสามารถยกระดับประสิทธิภาพได้อีก
- ด้วยการติดตั้งใช้งาน CRDT แบบใหม่ชื่อ Diamond types จึงทำประสิทธิภาพได้เร็วกว่า Yjs 5 เท่า
- Diamond ที่เขียนด้วย Rust ประมวลผลงานแก้ไข 260,000 รายการได้ในเวลาเพียง 56 มิลลิวินาที
บทสรุป
- ด้วยโครงสร้างข้อมูลที่ปรับแต่งมาอย่างดีและการจัดการหน่วยความจำอย่างมีประสิทธิภาพ เราสามารถยกระดับประสิทธิภาพของ CRDT ได้อย่างมาก
- การใช้ภาษา low-level อย่าง Rust ช่วยให้ไปได้ไกลยิ่งขึ้นในด้านความเร็ว
สรุปโดย GN⁺
- CRDT คืออนาคตของการแก้ไขงานร่วมกัน และเป็นเครื่องมือทรงพลังที่รักษาความสอดคล้องได้โดยไม่ต้องมีเซิร์ฟเวอร์กลาง
- ปัญหาด้านประสิทธิภาพของ Automerge มาจากโครงสร้างข้อมูลที่ซับซ้อนและการใช้หน่วยความจำอย่างไม่มีประสิทธิภาพ
- Yjs และ Diamond types ใช้โครงสร้างข้อมูลที่เรียบง่ายและมีประสิทธิภาพ จึงยกระดับประสิทธิภาพได้อย่างมาก
- การใช้ภาษา low-level อย่าง Rust สามารถให้ประสิทธิภาพที่เร็วขึ้นได้อีก
- หากกำลังพัฒนาเครื่องมือสำหรับการแก้ไขงานร่วมกัน Yjs และ Diamond types เป็นตัวเลือกที่น่าพิจารณา
1 ความคิดเห็น
ความเห็นจาก Hacker News
เหตุผลที่ 32 เอนทรีมีประสิทธิภาพที่สุดคือ cache line มีขนาด 64 ไบต์
ยากที่จะหาตัวอย่างแอปพลิเคชันจริงที่ใช้ CRDTs แล้วมอบประสบการณ์ที่ดีได้
CRDTs ทรงพลัง แต่มีข้อเสียคือทิ้งประวัติของการทำงานย้อนหลังไว้เสมอ (หรือทิ้งองค์ประกอบเก่าไว้)
คำอ้างอิงจาก GitHub Readme ปัจจุบัน:
แม้บทความนี้จะมีเนื้อหาที่ยาก แต่เขียนได้ดีมากจนหยุดอ่านไม่ได้
เมื่อเห็นว่ามีการใช้ลำดับชั้น จึงสงสัยว่าทำไมไม่ใช้ nested sets แทน
เคยเจอโพสต์นี้โดยบังเอิญเมื่อหลายปีก่อน
สงสัยว่าทำไม WASM ถึงช้ากว่าการรันแบบเนทีฟ 4 เท่า
ตอนนี้การทำ Automerge เวอร์ชัน Rust เสร็จสมบูรณ์แล้ว จึงน่าสนใจที่จะได้เห็น benchmark ที่อัปเดต