Crates.io | snowdon |
lib.rs | snowdon |
version | 0.2.0 |
source | src |
created_at | 2023-06-14 21:51:05.927622 |
updated_at | 2023-07-27 16:53:41.224251 |
description | A lightweight thread-safe snowflake ID implementation for Rust |
homepage | |
repository | https://github.com/archer-321/snowdon |
max_upload_size | |
id | 890544 |
size | 158,460 |
Snowdon is a lightweight snowflake ID implementation in Rust. It offers a simple blocking and a lock-free thread-safe generator implementation. Moreover, it supports custom Snowflake formats and epochs.
Snowflake IDs are unique IDs that include the timestamp of their "birth" (milliseconds since a fixed epoch) and a sequence number to allow the creation of multiple snowflakes in a single millisecond. They can also include a machine or generator ID for unique IDs across multiple generating instances without synchronization.
Twitter originally introduced snowflakes as IDs for tweets. While their implementation had a fixed epoch and snowflake layout, most other services that adopted snowflakes have changed the epoch or layout (e.g. by using all 42 bits to store the timestamp or by omitting the machine ID). Thus, when referring to "snowflake IDs", we mean timestamps associated with a sequence number and, optionally, (instance-specific) constant data like a machine ID or the leading 0 in Twitter's snowflakes.
Snowdon aims to be a general-purpose snowflake ID implementation. We have the following goals:
However, we define the following non-goals to outline what Snowdon is not:
To use this crate, simply add the following line to your Cargo.toml
file in the dependencies
table:
snowdon = "^0.2"
If you want to use the lock-free implementation, it's recommended to disable the blocking
feature (enabled by default)
by disabling this crate's default features:
snowdon = { version = "^0.2", default-features = false, features = ["lock-free"] }
To enable Serde support for snowflakes and snowflake comparators, enable the serde
feature:
snowdon = { version = "^0.2", default-features = false, features = ["serde"] }
The types of this library are designed to make it hard to misuse them. Specifically, snowflakes have two type parameters that represent their layout (the composition of a snowflake - this defines how many bits are used for the individual parts of the snowflake) and their epoch (the timestamp that the individual timestamps in snowflakes are based on). Because of this, it's impossible to use snowflakes in an API that expects a different layout or epoch.
Moreover, this crates doesn't provide an (easy) way to convert timestamps into snowflakes. Instead, it provides a comparator type that can be compared with snowflakes directly. However, users of this crate can't accidentally use those comparators in places that expect snowflakes.
Our documentation includes various examples for all complex methods. When implementing a trait, refer to the function's documentation for detailed requirements and examples.
Snowdon takes Semantic Versioning compatibility seriously. In addition to the SemVer specification, we
guarantee that patch releases for versions starting with 0
(e.g. 0.1.1
) don't include breaking changes. I.e.,
you should be able to (automatically) update from version 0.1.0
to version 0.1.1
without having to check for
breaking changes. This behaviour effectively matches Cargo's SemVer compatibility.
Our current minimum supported Rust version is 1.56.1
. We might increase our MSRV in the future, but we try to only do
so if there's a good reason for it. Only having a few dependencies that each have a stable MSRV policy, we shouldn't
need to increase our MSRV transitively because of a dependency update.
Note that benchmarks and tests require a higher Rust version, as they add dependencies that don't support the MSRV above.
As detailed in Project goals and non-goals, Snowdon aims to be a correct implementation of Twitter's Snowflake algorithm. All generators this crate implements should be safe to use across multiple threads. More specifically, we try to ensure the following behaviour:
1
exists, another snowflake with
the same timestamp and the sequence number 0
must also exist.b
was generated after the snowflake a
, a < b
.Note that "before" and "after" in the list above refer to the actual time. I.e., even if the system clock is not
monotonic, Snowdon only returns a snowflake b
after producing the snowflake a
for all subsequent invocations if
a < b
.
In an attempt to verify the lock-free algorithm, a PROMELA implementation for it is provided in the spin
directory.
Refer to the README in that directory for more information about the model and our lock-free snowflake
implementation.
Please note that while we try to provide a correct and efficient implementation, there's no mathematical proof that Snowdon's implementation is indeed correct. We do our best to ensure that our code is correct, but if you're planning to use Snowdon in a production environment, you should verify that our implementation meets your expectations. If you find any bugs or potential efficiency improvements, please open an issue as described in CONTRIBUTING.md.
Snowdon provides benchmarks in benches
. You can run them with
cargo bench --all-features
When running the test on an AMD Ryzen 9 5900X with Linux 6.3.5, we get the following results:
Benchmark | Average time per snowflake (in ns) | Estimated snowflake IDs per second |
---|---|---|
Lock-free generator (sequential) | 29.188 | 34260655 |
Blocking generator (sequential) | 29.038 | 34437633 |
Lock-free generator (10 threads) | 84.954 | 11771076 |
Blocking generator (10 threads) | 1594.4 | 627195 |
The last two entries in the table above are for an extreme scenario where ten threads concurrently generate snowflakes in a loop. It's meant to simulate severe contention between threads, and with most applications, the actual times per snowflake should be closer to the sequential benchmarks. Moreover, most implementations outperform the limitations of snowflake layouts with 12 sequence number bits. Under almost all circumstances, the generators are fast enough for a regular application's ID requirements. This includes applications that need to generate more than 100000 IDs per second.
Copyright (C) 2023 Archer archer@nefarious.dev
Snowdon is licensed under either of
at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 licence, shall be dual licensed as above, without any additional terms or conditions.