23 คะแนน โดย kunggom 2022-02-24 | 15 ความคิดเห็น | แชร์ทาง WhatsApp

หากจะสร้าง ID สำหรับระบุรีซอร์สใดรีซอร์สหนึ่งให้ไม่ซ้ำกัน โดยทั่วไปเท่าที่ทราบมักมีวิธีหลัก ๆ อยู่ 2 แบบ แบบแรกคือใช้ค่าเลขจำนวนเต็มแบบลำดับที่ได้จากการตั้ง Auto Increment ไว้กับ Primary Key ของตาราง DB ตรง ๆ และอีกแบบคือสร้าง GUID แบบสุ่มขนาด 128 บิต (หรือที่เรียกกันว่า UUID) ขึ้นมาใช้ในแต่ละครั้ง

ข้อมูลของบริการจำนวนมหาศาลที่เราเห็นบนเว็บนั้น มี RDBMS รับผิดชอบอยู่เป็นจำนวนมาก และ Auto Increment ของ DBMS แบบนี้ก็ถูกปรับแต่งมาอย่างดีภายในอยู่แล้ว อีกทั้งในมุมของนักพัฒนาก็เข้าใจง่าย คาดเดาง่าย และยังจัดเรียงตามลำดับที่ข้อมูลเข้ามาได้อย่างง่ายดายด้วย เพราะมันแค่เพิ่มตัวเลขทีละ 1 เท่านั้นเอง แต่แนวทางนี้ก็มีข้อเสียในบางกรณี เช่น อาจเปิดเผยข้อมูลที่ไม่อยากให้ภายนอกรับรู้ในเชิงความปลอดภัย (เช่น คู่แข่งอาจเดาจำนวนผู้ใช้หรือดัชนีสำคัญอื่น ๆ ของบริการเราได้ง่าย) หรืออาจกลายเป็นปัญหาในสถาปัตยกรรมแบบกระจายศูนย์

ส่วนการใช้ GUID นั้นมีคุณสมบัติตรงข้ามกับแบบข้างต้น GUID เป็นค่า 128 บิตที่แทบจะไม่ชนกันและถือว่าไม่ซ้ำกันในทางปฏิบัติ โดยสร้างขึ้นมาใช้ได้ทันทีโดยไม่ต้องพึ่งพาสิ่งอื่น จึงไม่มีปัญหาในสถาปัตยกรรมแบบกระจายศูนย์ และยังไม่เสี่ยงหลุดข้อมูลที่มีความหมายอื่นออกไปภายนอกด้วย อย่างไรก็ตาม การนำค่าที่สุ่มขึ้นมาไปใช้ใน RDBMS อาจทำให้ประสิทธิภาพลดลง และตัวมันเองก็ไม่สามารถใช้จัดเรียงตามลำดับที่ข้อมูลเข้ามาได้ เพื่อชดเชยจุดอ่อนนี้ บางกรณีจึงใช้สิ่งอย่าง Timeflake ที่ไม่ได้สุ่มล้วน แต่ผสมข้อมูลเวลาเข้าไป ทำให้มีความเป็นลำดับแบบไม่สมบูรณ์ แม้ผมจะยังไม่เคยใช้เอง แต่ได้ยินมาว่าเฟรมเวิร์กอย่าง Laravel ก็ใช้แนวทางลักษณะนี้เช่นกัน

ส่วนตัวแล้ว ตอนนี้ผมทำงานในบริษัทที่พัฒนาผลิตภัณฑ์ซึ่งต้องเชื่อมต่อกับสิ่งที่ใช้ GUID อย่างจริงจัง เช่น Microsoft Office 365 หรือ Graph API เลยทำให้เริ่มรู้สึกว่าวิธีที่ใช้ GUID อย่างจริงจังก็น่าสนใจไม่น้อย แต่สุดท้ายแล้วเรื่องแบบนี้ก็ขึ้นอยู่กับกรณีใช้งานและเป้าหมายว่าอะไรเหมาะกว่า ดังนั้นการเข้าใจข้อดีข้อเสียของแต่ละวิธีให้ชัดเจนจึงเป็นเรื่องสำคัญ และด้วยเหตุนี้จึงอยากแนะนำเธรดทวีตที่บันทึกไดอารีสมมติของนักพัฒนาบริการคนหนึ่งเกี่ยวกับประเด็นนี้ (ภาษาเกาหลี)

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

 
kunggom 2022-04-22

เมื่อไม่นานมานี้เกิดเหตุการใช้งานโดยทุจริตที่ Shinhan Card และจากกรณีนี้ก็ยืนยันได้ว่ามีความเสี่ยงที่บริษัทบัตรดังกล่าวอาจเปิดช่องให้เกิดการใช้งานทุจริตจากต่างประเทศได้ เนื่องจากออกหมายเลขบัตรเครดิตแบบเรียงลำดับ
แค่เปลี่ยนหมายเลขนิดหน่อยก็ "ชำระเงิน" ได้…บัตรเครดิตเสี่ยงถูกขโมยข้อมูล
หน่วยงานกำกับดูแลการเงิน เร่งจัดทำมาตรการต่อกรณีการใช้งานโดยทุจริตล่าสุดของ Shinhan Card เป็นต้น

 
kunggom 2022-02-24

ต้องขอบคุณที่หลาย ๆ ท่านเข้ามาแสดงความคิดเห็น ทำให้ผมได้รู้อะไรหลายอย่างที่ก่อนหน้านี้ยังไม่ค่อยทราบ
ด้วยเหตุนี้ ผมจึงเพิ่งได้รู้จักทั้ง Hashids, Nano ID และ วิธีที่ Instagram ใช้ เป็นครั้งแรก

 
ehlegeth 2022-02-24

แรงจูงใจคงคล้ายกับ ulid แต่มี Internet Draft ที่กำลังถูกเสนออยู่ ผมเลยเคยใช้สเปกนี้ในโปรเจ็กต์ก่อนหน้านี้ครับ
https://github.com/uuid6/uuid6-ietf-draft

ระบบ id ที่สร้างกันในลักษณะนี้เห็นได้บ่อย แต่ตอนนี้ก็น่าจะถึงเวลาที่อย่างน้อยพวกที่เป็นแนว UUID จะต้องถูกรวมให้เป็นมาตรฐานเดียวกันสักทีครับ

 
kunggom 2022-02-24

แต่ก็มักมีคนพูดกันว่า ความพยายามที่จะสร้างมาตรฐานใหม่ขึ้นมาเพื่อรวมมาตรฐานที่กระจัดกระจายให้เป็นหนึ่งเดียวนั้น สุดท้ายแล้วก็มักแค่เพิ่มผู้เข้าแข่งขันรายใหม่ในตลาดขึ้นมาอีกหนึ่งรายเท่านั้นเอง 555
https://xkcd.com/927/

 
ehlegeth 2022-03-02

ใช่เลย 555 สงสัยทุกคนก็เลยพากันเสนอ id แบบใหม่กันมั้งครับ

 
nallwhy 2022-02-24

คุณกยูวอนเคยแชร์เรื่องนี้ไว้เมื่อไม่นานมานี้ แต่จริง ๆ แล้วมันไม่ใช่ปัญหาที่เรียบง่ายไม่ใช่หรือ?
https://byterot.blogspot.com/2013/02/…

 
roxie 2022-02-24

ผมก็อยากได้คำอธิบายเพิ่มเติมเหมือนกันว่าเรื่องที่ว่าเป็น "ปัญหาง่ายๆ" นั้นหมายถึงอะไร

 
ehlegeth 2022-02-24

หมายถึงว่าเป็นปัญหาที่เรียบง่ายในแง่ไหนกันหรือครับ?

ในบทความนี้แม้จะบอกว่า 'With storage nowadays very cheap, this normally is not a problem from the storage point of view.' แต่ก็ดูเหมือนว่าจะมีบางสถานการณ์ที่ต้องปฏิเสธการใช้ UUID ตามบริบทอยู่เหมือนกัน เช่น กรณีที่ id นี้ต้องวิ่งอยู่บนเครือข่าย ต้องทำหน้าที่เป็นคีย์ในหน่วยความจำ หรือเป็นคีย์ที่ต้องถูกใช้งานในหลายจุดกับข้อมูลขนาดใหญ่ ซึ่งในกรณีเหล่านี้การลดลงแม้เพียงไม่กี่ไบต์ก็อาจมีความสำคัญ

 
nallwhy 2022-02-25

ปัญหาที่บทความนี้พูดถึงคือประสิทธิภาพที่ลดลงเมื่อใช้ค่าที่สุ่มสร้างขึ้นเป็น primary key
(มีการพูดถึงปัญหาอื่นด้วย แต่ถ้าผมจับประเด็นไม่ครบก็ช่วยบอกด้วยนะครับ)
สำหรับปัญหานั้นจริง ๆ มีคำตอบอยู่แล้วครับ มันเป็นปัญหาเดียวกับตอนทำ cursor based pagination ตามลำดับเวลา ดังนั้นคิดว่าหลายคนน่าจะแก้กันมาแล้วครับ

 
nallwhy 2022-02-25

ผมเองก็สงสัยเหมือนกันว่ามันเป็นปัญหาที่ซับซ้อนในแง่ไหน
ในเมื่อบอกว่าสถานการณ์ที่พูดถึงเป็นสถานการณ์ที่ควรปฏิเสธ ก็ดูเหมือนจะเป็นปัญหาที่เรียบง่ายนะ...
หรือว่าปัญหาที่ซับซ้อนก็คือเวลาที่ตัดสินใจไม่ได้ว่าจะเอายังไงดีไม่ใช่เหรอ?

 
ehlegeth 2022-03-02

ผมถามเพราะคำว่า "ปัญหาที่เรียบง่าย" เปิดช่องให้ตีความได้หลายแบบ เลยอยากทราบว่าคุณใช้ในความหมายไหนครับ เช่น หมายถึงว่าตัวปัญหาเองไม่ได้ยาก หรือหมายถึงว่าเพราะในบทความมีคำตอบที่ชัดเจน(?) เสนอไว้ จึงมีพื้นที่ให้กังวลหรือขบคิดไม่มากนัก เป็นต้น
ส่วนอย่างแรกนั้น อย่างที่พูดไว้ข้างต้น ในบางสถานการณ์ id จำเป็นต้องใช้ได้แม้กระทั่งนอกฐานข้อมูลด้วย จึงมีปัจจัยที่ต้องพิจารณาหลายอย่าง และผมคิดว่าไม่ใช่ปัญหาที่เรียบง่ายนัก

 
yolatengo 2022-02-24

ใน python/django ก็มีแบบนี้เหมือนกันนะ https://pypi.org/project/django-hashid-field/1.0.0/

 
kunggom 2022-02-24

โอ้ มีวิธีอย่าง Hashids ด้วยสินะครับ
ถ้า Salt รั่วไหล ก็อาจเกิดปัญหาการเปิดเผยข้อมูลออกสู่ภายนอกตามที่กล่าวไว้ในบทความหลักได้ แต่ถึงอย่างนั้นก็ยังคิดว่าเป็นวิธีที่ดีครับ

 
majorika 2022-02-24

ยังมี ulid ด้วย 128 บิต และสามารถเรียงลำดับตามเวลาได้
https://github.com/ulid/spec

 
kunggom 2022-02-24

จะใช้ ID ของทรัพยากรเป็น GUID หรือเป็นแบบลำดับดี?

พอเห็นว่าหลายอย่างหน้าตาคล้ายๆ กันไปหมด ก็อดคิดไม่ได้ว่าความคิดของคนนั้นส่วนใหญ่ก็คงไม่ได้ต่างกันเท่าไรนัก…?