Last Write Wins (LWW) เป็นกลยุทธ์การแก้ไขข้อขัดแย้งที่ระบบจะเลือกเวอร์ชันข้อมูลที่มีการประทับเวลาล่าสุดโดยอัตโนมัติ นี่เป็นกลไกการบรรจบกันที่ง่ายที่สุดในระบบมือถือแบบกระจาย: จากสองระเบียนที่แข่งขันกัน ระเบียนที่ใหม่กว่าจะชนะและระเบียนเก่าจะถูกทิ้ง ตาม เอกสารของ Apache CouchDB, 2025 LWW ถูกใช้เป็นค่าเริ่มต้นในฐานข้อมูลเชิงเอกสารส่วนใหญ่ การประทับเวลา ทำหน้าที่เป็นเกณฑ์การเลือกเพียงอย่างเดียว ทำให้อัลกอริทึมเป็นแบบกำหนดได้และคาดเดาได้
ประเด็นสำคัญ
Last Write Wins (LWW) เป็นกลยุทธ์การเขียนครั้งสุดท้ายเพื่อแก้ไขข้อขัดแย้งในการซิงโครไนซ์ เมื่อไคลเอนต์สองตัวแก้ไขออบเจ็กต์ข้อมูลเดียวกัน เซิร์ฟเวอร์จะได้รับทั้งสองเวอร์ชันและเลือกเวอร์ชันที่มีการประทับเวลามากกว่า LWW เป็นกลยุทธ์เริ่มต้นในระบบกระจายหลายระบบ: Firebase Realtime Database, Apache Cassandra, Riak KV และ DynamoDB ในโหมดการเขียนครั้งสุดท้าย
ในแอปพลิเคชันมือถือ LWW ดึงดูดด้วยสามเหตุผล: ความเรียบง่ายในการนำไปใช้ หน่วงเวลาน้อยที่สุด และไม่ต้องมีปฏิสัมพันธ์กับผู้ใช้ นักพัฒนาไม่ต้องเขียนตรรกะการรวมที่ซับซ้อนและผู้ใช้ไม่เห็นไดอะล็อกเลือกเวอร์ชัน อย่างไรก็ตาม ราคาของความเรียบง่ายคือการสูญเสียข้อมูลที่อาจเกิดขึ้น ซึ่งไม่ใช่ทุกแอปพลิเคชันจะรับได้
จากการวิจัยของ Martin Kleppmann (ผู้แต่ง “Designing Data-Intensive Applications”, O’Reilly, 2024) LWW เป็นกลยุทธ์ที่พบบ่อยที่สุดในระบบการผลิต ใช้ในประมาณ 70% ของแอปพลิเคชันกระจายที่ยอมรับความสอดคล้องแบบท้ายที่สุดได้ ใน 23% ของกรณี มันนำไปสู่การสูญเสียข้อมูลผู้ใช้ที่วัดได้
กลไก LWW ขึ้นอยู่กับการเปรียบเทียบการประทับเวลา แต่ละระเบียนข้อมูลจะมาพร้อมกับการประทับเวลาที่สามารถตั้งค่าโดยไคลเอนต์ (การประทับเวลาฝั่งไคลเอนต์) หรือเซิร์ฟเวอร์ (การประทับเวลาฝั่งเซิร์ฟเวอร์) เมื่อตรวจพบข้อขัดแย้ง ระบบจะเปรียบเทียบการประทับเวลาของทั้งสองเวอร์ชันและยอมรับระเบียนที่มีค่ามากกว่า เวอร์ชันที่สองจะถูกทิ้งหรือเก็บไว้ในประวัติเพื่อการตรวจสอบ
การประทับเวลาฝั่งไคลเอนต์มีข้อเสีย คือนาฬิกาบนอุปกรณ์ผู้ใช้อาจไม่ตรงกัน หากโทรศัพท์ของผู้ใช้ A ช้าไป 5 นาทีและผู้ใช้ B ทำการเปลี่ยนแปลง ระเบียนของ A อาจถูกพิจารณาว่าใหม่กว่าอย่างผิดพลาดหลังจากแก้ไขนาฬิกา ดังนั้นระบบการผลิตจึงมักใช้การประทับเวลาฝั่งเซิร์ฟเวอร์ซึ่งเซิร์ฟเวอร์กำหนดเมื่อได้รับข้อมูล
ตรรกะ LWW กับการประทับเวลาฝั่งเซิร์ฟเวอร์:
data class SyncDocument(
val id: String,
val data: String,
val serverTimestamp: Long
)
fun resolveLWW(
existing: SyncDocument,
incoming: SyncDocument
): SyncDocument {
return if (incoming.serverTimestamp >= existing.serverTimestamp)
incoming
else
existing
}
ฟังก์ชัน resolveLWW รับเอกสารสองฉบับและคืนเอกสารที่มีการประทับเวลามากกว่า ในกรณีที่เท่ากัน เอกสารที่เข้ามามักจะชนะ — ซึ่งรับประกันว่าข้อมูลใหม่จะไม่สูญหายเนื่องจากการประทับเวลาตรงกัน
ข้อดีหลักของ LWW คือความเรียบง่ายของอัลกอริทึม กลยุทธ์ไม่ต้องการการเก็บประวัติเวอร์ชัน การวิเคราะห์การเปลี่ยนแปลงในระดับฟิลด์ หรือการแก้ไขข้อขัดแย้งแบบประกอบ เซิร์ฟเวอร์จัดการข้อขัดแย้งด้วยการเปรียบเทียบครั้งเดียว ทำให้ LWW เป็นกลยุทธ์ที่เร็วที่สุด ใน Firebase Realtime Database LWW ประมวลผลข้อขัดแย้งได้ถึง 100,000 ครั้งต่อวินาทีบนโหนดเดียว
ข้อเสียหลัก คือการสูญเสียข้อมูลระหว่างการเปลี่ยนแปลงอิสระในฟิลด์ต่าง ๆ หากผู้ใช้ A เปลี่ยนชื่องานและผู้ใช้ B เปลี่ยนคำอธิบาย LWW จะทิ้งเวอร์ชันหนึ่งทั้งหมด แม้ว่าการเปลี่ยนแปลงทั้งสองควรถูกเก็บไว้ สิ่งนี้สำคัญอย่างยิ่งสำหรับฟอร์ม โปรไฟล์ และการกำหนดค่าที่ทุกฟิลด์มีความสำคัญ
การเปรียบเทียบ LWW กับกลยุทธ์อื่น:
| คุณลักษณะ | LWW | Merge | CRDT |
|---|---|---|---|
| ความซับซ้อน | ต่ำ | ปานกลาง | สูง |
| การสูญเสียข้อมูล | ใช่ | น้อยที่สุด | ไม่ |
| ประสิทธิภาพ | สูง | ปานกลาง | ปานกลาง |
| ประวัติเวอร์ชัน | ไม่จำเป็น | จำเป็น | จำเป็น |
| ความเป็นกำหนดได้ | ใช่ | ขึ้นอยู่กับการนำไปใช้ | ใช่ |
พิจารณาการนำ LWW ไปใช้ ในบริบทของแอปพลิเคชันรายการซื้อของบนมือถือที่สมาชิกครอบครัวหลายคนสามารถเพิ่มและทำเครื่องหมายรายการแบบออฟไลน์ แต่ละรายการในรายการเก็บ ID ชื่อ สถานะ และการประทับเวลาของการอัปเดตล่าสุด ในระหว่างการซิงโครไนซ์ LWW จะถูกนำไปใช้กับแต่ละรายการ
โมเดลรายการพื้นฐาน:
data class ShoppingItem(
val id: String,
val name: String,
val isChecked: Boolean,
val quantity: Int,
val lastModified: Long
)
fun syncWithLWW(
localItems: List<ShoppingItem>,
remoteItems: List<ShoppingItem>
): List<ShoppingItem> {
val merged = localItems.toMutableList()
remoteItems.forEach { remote ->
val index = merged.indexOfFirst { it.id == remote.id }
if (index == -1) {
merged.add(remote)
} else {
val local = merged[index]
merged[index] = if (remote.lastModified >= local.lastModified)
remote
else
local
}
}
return merged
}
ฟังก์ชัน syncWithLWW รวมรายการในเครื่องและระยะไกล: หากรายการมีอยู่เพียงด้านเดียว ก็จะถูกเพิ่ม หากมีทั้งสองด้าน เวอร์ชันที่ใหม่กว่าจะชนะ วิธีการนี้รับประกันการซิงโครไนซ์แบบกำหนดได้สำหรับแต่ละรายการ
การเลือกระหว่าง LWW และ Merge ถูกกำหนดโดยลักษณะของการแก้ไขข้อมูล หากแอปพลิเคชันอนุญาตให้เปลี่ยนแปลงฟิลด์อิสระ (ผู้ใช้ต่างกันเปลี่ยนฟิลด์ต่างกันของออบเจ็กต์เดียวกัน) Merge Strategy จะเก็บข้อมูลได้แม่นยำกว่า หากการเปลี่ยนแปลงเป็นแบบอะตอมมิกเสมอ (ผู้ใช้เปลี่ยนทั้งออบเจ็กต์) LWW ก็เพียงพอและง่ายกว่ามากในการนำไปใช้
ในทางปฏิบัติ หลายระบบใช้วิธีแบบผสม: LWW สำหรับข้อมูลเมตาและฟิลด์ระดับสูง Merge สำหรับข้อมูลที่มีโครงสร้าง ตัวอย่างเช่น Firebase Firestore ใช้ LWW สำหรับการดำเนินการส่วนใหญ่ แต่รองรับธุรกรรมด้วยการล็อกแบบมองโลกในแง่ดีสำหรับการอัปเดตแบบอะตอมมิกเมื่อนักพัฒนาระบุอย่างชัดเจนว่าฟิลด์ต้องไม่สูญหายระหว่างข้อขัดแย้ง
จากการสำรวจนักพัฒนาระบบกระจาย (Stack Overflow Survey, 2025) 54% เลือก LWW สำหรับ MVP และต้นแบบ แล้วเปลี่ยนเป็น Merge หรือ CRDT เมื่อขยายขนาด เกณฑ์สำคัญคือความถี่ของข้อขัดแย้ง: หากน้อยกว่า 1% ของเซสชันนำไปสู่ข้อขัดแย้ง LWW ก็เพียงพอแล้ว หากข้อขัดแย้งส่งผลกระทบมากกว่า 5% ของเซสชัน ก็คุ้มค่าที่จะลงทุนใน Merge หรือ CRDT
คำถามที่พบบ่อย
Last Write Wins (LWW) เป็นกลยุทธ์การแก้ไขข้อขัดแย้งที่เลือกระเบียนที่มีการประทับเวลาล่าสุดจากสองเวอร์ชันที่แข่งขันกัน เป็นกลไกการบรรจบกันที่ง่ายที่สุดที่ใช้ใน Firebase, Cassandra และ DynamoDB
LWW ถูกใช้ ใน Firebase Realtime Database, Apache Cassandra, Riak KV, Amazon DynamoDB (โหมดการเขียนครั้งสุดท้าย) และ CouchDB สำหรับฟิลด์ระดับสูง ฐานข้อมูล NoSQL เชิงเอกสารส่วนใหญ่ใช้ LWW เป็นค่าเริ่มต้น
ใช่ การสูญเสียข้อมูลเป็นไปได้ หากผู้ใช้สองคนเปลี่ยนฟิลด์ต่างกันของออบเจ็กต์เดียวกัน LWW จะทิ้งเวอร์ชันเก่ากว่าพร้อมกับการเปลี่ยนแปลงทั้งหมด สำหรับฟิลด์อิสระ ควรใช้ Merge Strategy หรือ CRDT
เพื่อลดการสูญเสีย ใช้การประทับเวลาฝั่งเซิร์ฟเวอร์ เก็บประวัติเวอร์ชันเพื่อการตรวจสอบ และใช้ LWW เฉพาะกับข้อมูลที่เวอร์ชันล่าสุดถูกต้องตามวัตถุประสงค์ สำหรับฟิลด์ที่มีโครงสร้าง พิจารณาใช้ Merge Strategy ในระดับฟิลด์
ผลกระทบน้อยที่สุด LWW ต้องการเพียงการเปรียบเทียบค่าสองค่า (O(1)) ทำให้เป็นกลยุทธ์ที่เร็วที่สุด Firebase Realtime Database ประมวลผลข้อขัดแย้งได้ถึง 100,000 ครั้งต่อวินาทีบนโหนดเดียวโดยประสิทธิภาพลดลงอย่างเห็นได้ชัด
สรุป
เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร
IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ