Bạn có cần một định danh sẽ không trùng lặp với định danh do người khác tạo ra, trên một máy tính mà bạn chưa từng nghe đến, mà không cần xin phép ai không? Đó là công việc mà một UUID thực hiện. Nó là một con số 128 bit, được viết dưới dạng 36 ký tự theo mẫu 8-4-4-4-12 quen thuộc, và toàn bộ thiết kế của nó là không bao giờ có hai UUID giống hệt nhau mặc dù không có bên nào điều phối ai nhận định danh nào. Trình tạo miễn phí này tạo ra chúng trong trình duyệt của bạn: chọn một phiên bản trong 'Phiên bản', cho biết bạn cần bao nhiêu trong 'Số lượng mục chọn', và nhấn 'Tạo'. Trang web mở ra trên một v4 duy nhất, phiên bản mà hầu hết các dự án mong muốn, vì vậy định danh đầu tiên chỉ cách bạn một cú nhấp chuột.
Mỗi định danh được trình duyệt của bạn xây dựng thông qua Web Crypto API. Phiên bản 4 sử dụng crypto.randomUUID() ở nơi trình duyệt cung cấp và crypto.getRandomValues() ở những nơi khác — một nguồn ngẫu nhiên mạnh mẽ về mặt mật mã thay vì một hàm giả ngẫu nhiên của JavaScript như Math.random(). Phiên bản 7 đặt một dấu thời gian 48 bit tính bằng mili giây ở phía trước, sau đó là bộ đếm 12 bit tăng lên trong cùng một mili giây, rồi đến 62 bit ngẫu nhiên, đây là phương pháp sắp xếp thứ tự được mô tả trong RFC 9562; bộ đếm đó là lý do tại sao một loạt hàng nghìn định danh được xuất ra theo thứ tự thay vì bị xáo trộn. Phiên bản 1 kết hợp một dấu thời gian với định danh nút ngẫu nhiên có thiết lập bit đa hướng, vì vậy nó không bao giờ mang địa chỉ card mạng của bạn theo cách mà các bản triển khai gốc từ những năm 1990 đã làm. Các phiên bản 3 và 5 hoàn toàn không ngẫu nhiên: chúng băm một không gian tên cùng với một tên, sử dụng lần lượt MD5 và SHA-1, và quá trình băm đó cũng diễn ra trên thiết bị của bạn. Không có gì được gửi đến máy chủ, không có gì được ghi lại và sau khi trang đã tải xong, nó vẫn tiếp tục hoạt động kể cả khi ngắt kết nối.
'Phiên bản' là trường quyết định mọi thứ khác. Phiên bản 4 là 122 bit ngẫu nhiên và không có cấu trúc — đây là mặc định và là câu trả lời đúng khi một định danh chỉ cần duy nhất. Phiên bản 7 giữ 62 bit ngẫu nhiên nhưng mở đầu bằng thời gian nó được tạo, vì vậy một tập hợp của chúng sẽ sắp xếp theo thứ tự chúng được tạo ra; đó là lý do tại sao nó là phiên bản nên chọn khi định danh sẽ trở thành một khóa cơ sở dữ liệu. Phiên bản 1 là sơ đồ dựa trên thời gian ban đầu, được giữ ở đây cho các hệ thống vẫn yêu cầu nó. Các phiên bản 3 và 5 là cặp ngoại lệ: chúng mang tính tất định, nghĩa là cùng một đầu vào luôn tạo ra cùng một định danh, và chúng nhận thêm hai trường — 'Không gian tên', là một trong các không gian tiêu chuẩn DNS, URL, OID và X.500 hoặc một không gian 'Tùy chỉnh' của riêng bạn, và 'Tên', tức chuỗi được định danh. Cung cấp cho v5 không gian tên URL và https://example.com/a và bạn sẽ nhận được cùng một UUID vào hôm nay, ngày mai và trên máy tính của người khác. Vì điều đó, 'Số lượng mục chọn' sẽ biến mất khi v3 hoặc v5 được chọn: một nghìn bản sao của một giá trị tất định thì cũng sẽ chỉ là một nghìn bản sao của một giá trị tất định. Đối với mọi phiên bản khác, 'Số lượng mục chọn' chạy từ 1 đến 1000.
Bốn công tắc thay đổi hình dạng của đầu ra mà không thay đổi 128 bit bên dưới. 'Chữ hoa' in các chữ số thập lục phân dưới dạng chữ in hoa, 'Không có dấu gạch ngang' mang lại dạng 32 ký tự nhỏ gọn mà một số cột và tên tệp ưa thích, và 'Dấu ngoặc nhọn' bọc giá trị trong { } — hình dạng mà Windows và thế giới .NET gọi là một GUID. Dưới phần 'Tùy chọn nâng cao', urn:uuid: thêm tiền tố khiến nó trở thành một URN chính thức; nó tắt 'Dấu ngoặc nhọn' và 'Không có dấu gạch ngang' trong khi đang bật, vì tiêu chuẩn cho phép chính xác một dạng URN và đó là dạng chuẩn có dấu gạch ngang. 'Định dạng sao chép' quyết định cách một loạt kết quả được nối với nhau khi bạn lấy nó: mỗi dòng một kết quả, phân tách bằng dấu phẩy, hoặc mỗi giá trị nằm trong dấu ngoặc kép kèm dấu phẩy ở cuối, cho phép dán thẳng vào một mảng trong mã. Nằm dưới kết quả là một dòng báo cáo tính ngẫu nhiên tính bằng bit — 122 đối với v4, 62 đối với v7 — và, đối với v7, là dấu thời gian được mã hóa trong định danh đầu tiên của loạt kết quả, nhờ đó thời gian bên trong giá trị hiển thị rõ ràng thay vì được ngụ ý. 'Sao chép tất cả' và 'Lưu vào tệp' đều tuân theo 'Định dạng sao chép'. 'Lịch sử' lưu giữ 10 loạt kết quả cuối cùng của bạn trong trình duyệt của chính bạn: nhấp vào một loạt để mang nó trở lại, sao chép hoặc xóa một mục nhập đơn lẻ, hoặc xóa toàn bộ. 'Xóa' sẽ làm trống kết quả và giữ nguyên các thiết lập của bạn, và qua mức 50 định danh, danh sách sẽ trở thành một khối duy nhất có thể cuộn được thay vì năm mươi hàng.
Điều quan trọng nhất trên trang này là sự khác biệt giữa v4 và v7 với tư cách là khóa chính, và đó không phải là vấn đề sở thích. Các chỉ mục cơ sở dữ liệu là những B-tree được giữ theo thứ tự đã sắp xếp, và nơi một khóa mới xuất hiện trong thứ tự đó sẽ quyết định chi phí thao tác chèn. Một khóa v4 là ngẫu nhiên, vì vậy các lần chèn liên tiếp sẽ nằm ở những góc không liên quan của chỉ mục: các trang đã đầy sẽ bị phân tách, các phần của cây mà cơ sở dữ liệu đang giữ trong bộ nhớ hiếm khi là những phần mà lần chèn tiếp theo cần đến, và chỉ mục cuối cùng lớn hơn và phân mảnh hơn so với mức độ xứng đáng của các hàng mà nó trỏ tới. Một khóa v7 bắt đầu bằng mili giây hiện tại, do đó các lần chèn liên tiếp sẽ nằm cạnh nhau ở cạnh bên phải của cây, đây là mô hình do một số nguyên tự động tăng tạo ra và cũng là mô hình mà các cấu trúc chỉ mục được xây dựng dựa trên đó. Đó là toàn bộ sự đánh đổi: v7 mang lại cho bạn hành vi chèn của một khóa tuần tự trong khi vẫn giữ nguyên thuộc tính khiến bạn chọn UUID ngay từ đầu, đó là bất kỳ ai cũng có thể tạo ra một khóa mà không cần hỏi máy chủ. Cái giá phải trả là thời gian tạo giờ đây có thể đọc được bên trong định danh, và điều đó có quan trọng hay không là một câu hỏi về dữ liệu của bạn, chứ không phải về định dạng.
Không có gì kiểm tra một UUID để đảm bảo tính duy nhất; kích thước của nó là sự đảm bảo. Không có cơ quan đăng ký, không có chuyến đi khứ hồi tới máy chủ, không có tra cứu — một trình tạo tạo ra một con số và giao nó, và lý do hai trong số chúng không xung đột đơn giản là vì có 2^122 giá trị v4 có thể có, khoảng 5.3 × 10^36. Nghịch lý ngày sinh (birthday problem) là cách trung thực nhất để định lượng điều đó: bạn sẽ cần khoảng 2.7 × 10^18 định danh trước khi có tỷ lệ cân bằng cho sự trùng khớp của bất kỳ hai định danh nào, tức là một tỷ UUID mới mỗi giây trong 86 năm. Việc nói chính xác về những gì điều đó hứa hẹn và không hứa hẹn rất đáng giá. Đây là sự đảm bảo mang tính thống kê, không phải mang tính số học, và nó chỉ giữ nguyên chừng nào tính ngẫu nhiên bên dưới là thực — một trình tạo được cấp seed kém, hoặc một máy ảo được sao chép cùng với entropy pool của nó, sẽ phá vỡ điều đó theo cách mà định dạng không thể phát hiện. Phiên bản 7 làm thu hẹp câu hỏi này hơn nữa: trong cùng một mili giây, một trình tạo không thể tự lặp lại chút nào, vì bộ đếm sẽ tăng lên thay vì quay ngẫu nhiên, và trên các trình tạo độc lập, 62 bit ngẫu nhiên sẽ thực hiện công việc.
Một UUID là một định danh, không phải là mật khẩu. Phiên bản 4 không thể đoán trước, và điều đó cám dỗ người ta coi nó như một bí mật — một liên kết đặt lại mật khẩu, một URL không thể đoán được, một mã thông báo phiên, một khóa API. Tính không thể đoán trước là có thật, nhưng tính bí mật là thuộc tính của cách thức một giá trị được xử lý, và các định danh được thiết kế để bị xử lý một cách bất cẩn: chúng nằm trong các URL, lọt vào lịch sử trình duyệt, nhật ký máy chủ, tiêu đề người giới thiệu và phần phân tích, rồi bị dán vào các tin nhắn trò chuyện. Các phiên bản khác thậm chí còn là những ứng cử viên tồi tệ hơn. Cả phiên bản 1 và phiên bản 7 đều mã hóa thời điểm tạo, do đó bất kỳ ai nắm giữ một định danh đều biết đại khái thời điểm nó được tạo và có thể thu hẹp phạm vi của mọi thứ được tạo cùng với nó. Các phiên bản 3 và 5 cố tình mang tính tất định: một UUID v5 của một địa chỉ email không phải là một bí mật được băm, nó là một giá trị mà bất kỳ ai có cùng địa chỉ đó đều có thể tính toán ra trong một giây. Hãy sử dụng UUID để gọi tên một vật thể. Hãy sử dụng trình tạo mật khẩu, hoặc một mã thông báo từ thư viện được xây dựng cho các bí mật, khi giá trị đó cần được giữ kín.
Tại sao nên chọn trình tạo UUID này?
- Tạo chỉ trên trình duyệt: các định danh được tạo trên thiết bị của bạn và không bao giờ được gửi đi bất cứ đâu
- Tính ngẫu nhiên từ Web Crypto API: an toàn về mặt mật mã, không phải Math.random()
- Năm phiên bản ở một nơi: v1, v3, v4, v5 và v7, không cần chuyển đổi công cụ
- v7 được sắp xếp thứ tự thực sự: một bộ đếm bên trong mili giây, đúng như RFC 9562 mô tả
- v3 và v5 tất định với bốn không gian tên tiêu chuẩn hoặc không gian tên của riêng bạn
- Lên tới 1000 UUID một lần, với danh sách có thể cuộn nhỏ gọn cho số lượng quá năm mươi
- Mọi hình dạng phổ biến: có gạch ngang, nguyên bản, chữ hoa, có ngoặc nhọn hoặc một URN urn:uuid:
- Sao chép dưới dạng các dòng, dấu phẩy hoặc giá trị trong ngoặc kép dán thẳng vào mã
- Không giới hạn và miễn phí: không cần đăng ký, không có giới hạn sử dụng, không có gì trên máy chủ của chúng tôi
UUID xuất hiện bất cứ nơi nào một vật thể phải được đặt tên trước khi bất cứ thứ gì có thể xác nhận tên đó chưa có ai dùng. Mã ứng dụng đúc chúng cho các hàng mà nó chuẩn bị chèn, vì vậy đối tượng có một danh tính trước khi nó đến được cơ sở dữ liệu và một máy khách có thể tham chiếu nó trong khi quá trình ghi vẫn đang diễn ra. Các hệ thống phân tán dựa vào chúng nhiều hơn: một vài dịch vụ cùng ghi vào một bảng, một máy khách di động ngoại tuyến tạo hồ sơ trên máy bay, một hàng đợi phải nhận ra thông báo mà nó đã xử lý — không có cái nào trong số đó có thể đợi đến lượt mình cho một bộ đếm dùng chung. Phiên bản 5 đáp ứng một nhu cầu khác, đó là một định danh ổn định bắt nguồn từ một thứ mà bạn đã có: cùng một tài liệu, cùng một URL hoặc cùng một tài khoản sẽ luôn ánh xạ tới cùng một UUID, vì vậy quá trình nhập có thể chạy hai lần mà không bị trùng lặp bất cứ thứ gì. Ở những nơi khác, chúng đơn giản là định dạng mà một hệ thống yêu cầu — một định danh tương quan xuyên suốt các nhật ký và dấu vết, một tên tệp sẽ không bị xung đột khi bản tải lên của một nghìn người dùng đổ vào chung một vùng, một khóa registry của Windows, một khối dữ liệu thử nghiệm cần phải trông giống như dữ liệu thực.
Vài giới hạn thực tế cũng rất đáng để biết. Một loạt kết quả là một phiên bản: giá trị trong 'Phiên bản' áp dụng cho mọi thứ trong đó, vì vậy một lần chạy ra các v4 và một lần chạy ra các v7 là hai loạt kết quả. Đây là một trình tạo, không phải là một trình kiểm tra — việc dán một UUID vào để đọc lại phiên bản hay dấu thời gian của nó không phải là việc mà trang này làm. 'Lưu vào tệp' ghi một tệp văn bản thuần túy thay vì CSV hay JSON. Phiên bản 7 công khai tiết lộ thời điểm nó được tạo, chính xác đến mili giây, đây là một sự đánh đổi thực sự chứ không phải là một sai sót, và phiên bản 1 cũng làm rò rỉ thời gian theo cách tương tự; nếu điều đó là một vấn đề đối với dữ liệu của bạn, phiên bản 4 là phiên bản không tiết lộ cho ai biết bất cứ điều gì. Có hai giá trị đặc biệt từ tiêu chuẩn không phải là các phiên bản và vì vậy không phải là tùy chọn trong 'Phiên bản', nhưng bạn có thể sao chép chúng từ đây: UUID nil, 00000000-0000-0000-0000-000000000000, và UUID max, ffffffff-ffff-ffff-ffff-ffffffffffff. Mọi thứ trên trang này đều tuân theo RFC 9562, quy cách đã thay thế RFC 4122 vào năm 2024, vì vậy đầu ra sẽ được chấp nhận bởi bất kỳ thư viện, cơ sở dữ liệu hay API nào có xử lý UUID. Trong giới hạn đó, sự đảm bảo rất mạnh mẽ: mỗi định danh đều được xây dựng theo tiêu chuẩn, từ tính ngẫu nhiên an toàn về mặt mật mã, trên chính máy tính của bạn và không có ai khác từng nhìn thấy nó.