Computer >> คอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Ruby

เจาะลึก UUID และ ULIDs

วันก่อนที่ทีม HB กำลังสนทนากันอยู่ และ Ben หัวหน้าฝ่ายพัฒนาของเรากล่าวว่าเขาต้องการใช้ ULID แทน UUID สำหรับระบบเฉพาะ

เช่นเดียวกับวิศวกรผู้มากประสบการณ์ ปฏิกิริยาของฉันคือการพึมพำบางอย่างที่ไม่ผูกมัด จากนั้นแอบไปที่ Google เพื่อพยายามค้นหาว่า ULID คืออะไร

สองชั่วโมงต่อมา ฉันก็ปรากฏตัวขึ้นพร้อมกับจ้องเขม็งเป็นพันหลา และตระหนักว่าโลกของตัวระบุที่ไม่ซ้ำกันนั้นใหญ่กว่าและมหัศจรรย์กว่าที่ฉันจะจินตนาการได้

ก่อนที่เราจะเริ่มต้นกับ ULID ให้กลับไปที่พื้นฐานและหารือเกี่ยวกับ UUIDs:

รหัส "ปกติ" มีปัญหาอย่างไร

เว็บแอปพลิเคชันส่วนใหญ่ที่ใช้ฐานข้อมูลเริ่มต้นเป็นรหัสตัวเลขที่เพิ่มขึ้นโดยอัตโนมัติ ตัวอย่างเช่น ใน Rails คุณอาจเห็นพฤติกรรมเช่นนี้:

p1 = Person.create!
p1.id
# => 1

p2 = Person.create!
p2.id
# => 2

ฐานข้อมูลสามารถสร้างรหัสตามลำดับได้เพราะมันเก็บตัวนับที่เพิ่มในการสร้างบันทึก

รูปแบบนี้ยังสามารถเห็นได้นอกฐานข้อมูล บางครั้งเราจำเป็นต้องกำหนดรหัสด้วยตนเอง และเราอาจจัดเก็บตัวนับที่กำหนดเองใน - พูด - อินสแตนซ์ Redis

รหัสตามลำดับใช้งานได้ง่ายสำหรับกรณีการใช้งานที่มีปริมาณน้อย แต่จะกลายเป็นปัญหามากขึ้นเมื่อปริมาณเพิ่มขึ้น:

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

รหัสตามลำดับยังรั่วข้อมูล ซึ่งอาจเป็นปัญหาในบางกรณี:

  • คุณสามารถเดารหัสของทรัพยากรที่อาจไม่ใช่ของคุณได้อย่างง่ายดาย
  • หากคุณสร้างผู้ใช้และรหัสคือ 20 คุณจะรู้ว่าบริการนี้มีผู้ใช้ 20 ราย

UUID เป็นขนาดเว็บ

UUID ดูแตกต่างจากรหัสลำดับเล็กน้อย เป็นตัวเลข 128 บิต โดยทั่วไปจะแสดงเป็นเลขฐานสิบหก 32 หลัก:

123e4567-e89b-12d3-a456-426655440000

UUID ถูกสร้างขึ้นโดยใช้อัลกอริธึมเฉพาะที่กำหนดไว้ใน RFC 4122 พวกเขาพยายามแก้ปัญหามากมายที่เกิดขึ้นกับรหัสตามลำดับ:

  • คุณสามารถสร้าง UUID บนโหนดจำนวนเท่าใดก็ได้โดยไม่ต้องแชร์สถานะหรือการประสานงานระหว่างโหนด
  • คาดเดาได้น้อยกว่ารหัสลำดับเล็กน้อย (เพิ่มเติมในภายหลัง)
  • ไม่เปิดเผยขนาดของชุดข้อมูลของคุณ

สิ่งที่จับได้คือมีโอกาสเล็กน้อยที่โหนดสองโหนดจะสร้างรหัสเดียวกันโดยอิสระ เหตุการณ์นี้เรียกว่า "การชนกัน"

UUID หลากหลายรสชาติ

อัลกอริธึม UUID มีห้าประเภทที่กำหนดไว้ใน RFC 4122 ซึ่งแบ่งออกเป็นสองประเภท:

  • ตามเวลาและการสุ่ม อัลกอริทึมคือสิ่งที่เรากำลังพูดถึง ส่งผลให้มี UUID ใหม่สำหรับทุกการวิ่ง
    • ประเภทที่ 4 :รหัสที่สร้างขึ้นแบบสุ่ม น่าจะเป็นทางออกที่ดีที่สุดของเราสำหรับรหัสใหม่
    • ประเภทที่ 1 :ID ประกอบด้วยที่อยู่ MAC ของโฮสต์และการประทับเวลาปัจจุบัน สิ่งเหล่านี้เลิกใช้แล้วเพราะเดาง่ายเกินไป
    • ประเภทที่ 2 :สิ่งเหล่านี้ดูเหมือนจะไม่ธรรมดา ดูเหมือนว่าจะสร้างมาเพื่อ RPC แบบโบราณ
  • อัลกอริธึมตามชื่อ แตกต่างกันเล็กน้อย พวกเขาสร้าง UUID เดียวกันสำหรับชุดอินพุตที่กำหนดเสมอ
    • ประเภทที่ 5 :ใช้แฮช SHA-1 เพื่อสร้าง UUID แนะนำ
    • ประเภทที่ 3 :ใช้แฮช MD5 และเลิกใช้แล้วเนื่องจาก MD5 ไม่ปลอดภัยเกินไป

ใน Ruby คุณสามารถสร้าง UUID ผ่าน uuidtools อัญมณี. รองรับทุกประเภท ยกเว้นประเภท 2 ลึกลับ

# Code stolen from the uuidtools readme. :)
require "uuidtools"

# Type 1
UUIDTools::UUID.timestamp_create
# => #<UUID:0x2adfdc UUID:64a5189c-25b3-11da-a97b-00c04fd430c8>

# Type 4
UUIDTools::UUID.random_create
# => #<UUID:0x19013a UUID:984265dc-4200-4f02-ae70-fe4f48964159>

# Type 3
UUIDTools::UUID.md5_create(UUIDTools::UUID_DNS_NAMESPACE, "www.widgets.com")
# => #<UUID:0x287576 UUID:3d813cbb-47fb-32ba-91df-831e1593ac29>

# Type 5
UUIDTools::UUID.sha1_create(UUIDTools::UUID_DNS_NAMESPACE, "www.widgets.com")
# => #<UUID:0x2a0116 UUID:21f7f8de-8051-5b89-8680-0195ef798b6a>

ย้ายไปที่ ULID

หมายเหตุ: ในเวอร์ชันดั้งเดิมของบล็อกโพสต์นี้ ฉันลืมเชื่อมโยงไปยังข้อกำหนด ULID นี่มัน. มีลิงก์ไปยังการใช้งานใน Ruby และภาษาอื่นๆ

ULID เป็นแนวทางใหม่ที่มีประโยชน์สำหรับตัวระบุที่ไม่ซ้ำ ความแตกต่างที่ชัดเจนที่สุดคือมันดูแตกต่างออกไปเล็กน้อย:

01ARZ3NDEKTSV4RRFFQ69G5FAV

ประกอบด้วยตัวเลขที่เข้ารหัสฐาน 32 สองตัว การประทับเวลา UNIX ตามด้วยตัวเลขสุ่ม นี่คือโครงสร้างตามที่กำหนดไว้ในข้อกำหนด:

01AN4Z07BY      79KA1307SR9X4MV3

|----------|    |----------------|
 Timestamp          Randomness
   48bits             80bits

โครงสร้างนี้น่าทึ่งมาก! หากคุณจำได้ UUID จะขึ้นอยู่กับการประทับเวลาหรือการสุ่ม แต่ ULID ใช้การประทับเวลาทั้งสอง และ สุ่ม

ด้วยเหตุนี้ ULID จึงมีคุณสมบัติที่น่าสนใจบางประการ:

  • สามารถจัดเรียงศัพท์ (เช่น เรียงตามตัวอักษร) ได้
  • การประทับเวลามีความแม่นยำเป็นมิลลิวินาที
  • สวยกว่า UUID :)

สิ่งเหล่านี้เปิดโอกาสที่ยอดเยี่ยม:

  • หากคุณแบ่งพาร์ติชั่นฐานข้อมูลตามวันที่ คุณสามารถใช้การประทับเวลาที่ฝังใน ULID เพื่อเลือกพาร์ติชั่นที่ถูกต้องได้
  • คุณสามารถจัดเรียงตาม ULID แทนคอลัมน์ created_at แยกต่างหากได้ หากยอมรับความแม่นยำระดับมิลลิวินาทีได้

มีข้อเสียที่เป็นไปได้เช่นกัน:

  • หากการเปิดเผยการประทับเวลาเป็นแนวคิดที่ไม่ดีสำหรับแอปพลิเคชันของคุณ ULID อาจไม่ใช่ตัวเลือกที่ดีที่สุด
  • The sort by ulid วิธีการอาจไม่ทำงานหากคุณต้องการความแม่นยำระดับต่ำกว่าเสี้ยววินาที
  • ตามอินเทอร์เน็ต การใช้งาน ULID บางอย่างไม่สามารถกันกระสุนได้

บทสรุป

UUID เป็นและจะเป็นมาตรฐานต่อไป พวกเขามีมาโดยตลอด และห้องสมุดก็มีให้ในทุกภาษาเท่าที่จะจินตนาการได้ อย่างไรก็ตาม แนวทางใหม่ๆ ก็คุ้มค่าที่จะพิจารณา โดยเฉพาะอย่างยิ่งเมื่อเราเข้าสู่โลกที่ดำเนินการโดยระบบแบบกระจายมากขึ้น แนวทางรหัสที่ไม่ซ้ำกันใหม่อาจช่วยเราแก้ปัญหาที่ไม่แพร่หลายในการเผยแพร่ RFC4122