In distributed systems, a unique identifier (UUID) is very common. It is a way to identify data or entities. It is a fixed-length string generated based on an algorithm. However, UUIDs also have some disadvantages, such as they are difficult to sort because they are randomly generated, which leads to some performance issues. ULID is a new solution that solves these problems and provides some additional advantages.
What are ULIDs?
ULID (Universally Unique Lexicographically Sortable Identifier) is a sortable and unique identifier proposed by Alizain Feerasta in 2016. It combines a timestamp and a random number generator to generate a 32-bit identifier suitable for distributed Scenarios such as identifying data entities and events in the system.
The ULID specification defines the following formats:
01AN4Z07BY 000000000001 cc1cca9a-3ccd-11e8-9669-57e0c8c9e133
|--------------| |----------| |----------------------------------|
Timestamp Randomness Unique Identifier
10 chars 6 chars 16 chars
Among them, Timestamp (time stamp) and Randomness (random number) occupy 16 characters in total, and Unique Identifier (unique identifier) occupies 16 characters. The generation order of the ULID is: the ULID with the earlier timestamp comes first, and if the timestamp is the same, the ULID with the smaller random number comes first.
Specifically, the Timestamp part is obtained by base32 encoding the milliseconds of the Unix timestamp (since January 1, 1970), occupying the first 10 characters. The Randomness part is a 6-byte random number generated by CSPRNG (Cryptographically Secure Pseudo-Random Number Generator), which is obtained by base32 encoding and occupies the next 6 characters. The Unique Identifier part is 16 characters of UUID, which is used to ensure the global uniqueness of ULID.
Here is an example ULID:
01F9K1BCRK7X6T9GH6AA7YP6GW
|------------| |-------| |---------------|
Timestamp Randomness Unique Identifier
01F9K1BCRK 7X6T9G H6AA7YP6GW
How to generate ULID?
Generating a ULID requires two parts: a timestamp and a nonce. The timestamp part occupies the first 12 characters of the ULID, using UTC time, accurate to milliseconds. The random number part occupies the last 18 characters of ULID, using a random number generator based on CSPRNG.
Using this generation method can ensure that the generated ULID is globally unique and sortable. Additionally, ULIDs use a timestamp-based prefix, which makes it possible to use the first 12 characters to determine when the ULID was generated. This is very useful for debugging and data management.
Why use ULIDs?
ULIDs have some advantages over UUIDs:
- Sortable : Since ULID is generated based on timestamp, it can be sorted by timestamp, which is very useful for database indexing and query. Also, since the ULID uses a timestamp-based prefix, the first 12 characters can be used to determine the timestamp, which makes debugging and data management easier.
- Readability : ULID is composed of 32 characters, the first 12 characters are generated by the timestamp, and the timestamp can be determined by these 12 characters. This is very useful for debugging and data management.
- Low collision rate : The collision rate of ULID is very low, because it uses a timestamp-based prefix and a random number generator to generate ULID, which makes the generated ULID unique globally.
- Short and lightweight : ULID has only 32 characters, while UUID has 36 characters, which means that ULID is shorter, more lightweight, and more suitable for use in distributed systems.
- Security : ULID uses a CSPRNG-based random number generator to generate the random number part, which makes it more secure and less vulnerable to attacks.
How to use ULID in practice?
If you want to use ULIDs in your application, you can use an existing ULID library to generate ULIDs. Here are some popular ULID libraries:
- ulid (https://github.com/ulid/spec): This is the official ULID implementation library that supports multiple programming languages, including Go, Java, JavaScript, Python, and Ruby.
- ulid-js (https://github.com/ulid/javascript): This is a ULID implementation library for JavaScript, which supports use in browsers and Node.js.
- rust-ulid (https://github.com/mmacedoeu/rust-ulid): This is Rust's ULID implementation library, which provides a safe, efficient, and easy-to-use way to generate ULID.
An example of using ULID is to store ULID as a primary key in the database, which will make the entries in the database sorted by time, thereby improving the efficiency of database queries.
in conclusion
ULID is a better solution than UUID. It has the advantages of sortability, readability, low collision rate, short and lightweight, and security. In a distributed system, using ULID can improve the efficiency of database query while ensuring the uniqueness of data. If you are building a distributed system, consider using ULIDs to identify your data and entities.