What it solves
Imagine you’re building an e-commerce site on Azure.
You need to generate order numbers, and they absolutely must be unique.
A few options come to mind initially:
- Let SQL Azure generate the numbers for you. The downside to this approach is that you’re now serializing all of your writes down to a single thread, and throwing away all of the possible benefits from something like a queuing architecture. (Sidenote: on my current project we’re using a NoSQL graph DB with eventual consistency between nodes, so this wouldn’t work for us anyway.)
- Use a GUID. These are far from human friendly. Seriously, can you imagine seeing an order form with a GUID on the top?
- Prefix numbers with some form of machine specific identifier. This now requires some way to uniquely identify each node, which isn’t very cloud-like.
As you can see, this gets complex quickly.
SnowMaker is here to help.
What it does
SnowMaker generates unique ids for you in a highly distributed and highly performant way.
- Ids are guaranteed to be unique, even if your web/worker role crashes.
- Ids are longs (and thus human readable).
- It requires absolutely no node-specific configuration.
- Most id generation doesn’t even require any off-box communication.
How to get it
(if you’re not using NuGet already, start today)
How to use it
var generator = new UniqueIdGenerator(cloudStorageAccount); var orderNumber = generator.NextId("orderNumbers");
The only caveat not shown here is that you need to take responsibility for the lifecycle of the generator. You should only have one instance of the generator per app domain. This can easily be done via an IoC container or a basic singleton. (Multiple instances still won’t generate duplicates, you’ll just see wasted ids and reduced performance.) Don’t create a new instance every time you want an id.
Other interesting tidbits
The name is inspired by Twitter’s id generator, snowflake. (Theirs is more scalable because it is completely distributed, but in doing so it requires node-specific configuration.)
Typical id generation doesn’t even use any locks, let alone off-box communication. It will only lock and talk to blob storage when the id pool has been exhausted. You can control how often this happens by tweaking the batch size (a property on the generator). For example, if you are generating 200 order ids per server per second, set the batch size to 2000 and it’ll only lock every 10 seconds.
Node synchronisation is done via Azure blob storage. Other than that, it can run anywhere. You could quite easily use this library from AppHarbor or on premise hosting too, you’d just wear the cost of slightly higher latency when acquiring new ids batches.
The data persistence is swappable. Feel free to build your own against S3, Ninefold Storage, or any other blob storage API you can dream up.
The original architecture and code came from an excellent MSDN article by Josh Twist. We’ve brushed it off, packaged it up for NuGet and made it production ready.
Under the covers
SnowMaker allocates batches of ids to each running instance. Azure Blob Storage is used to coordinate these batches. It’s particularly good for this because it has optimistic concurrency checks supported via standard HTTP headers. At a persistence level, we just create a small text file for each id scope. (eg, the contents of /unique-ids/some-id-scope would just be “4”.)
One issue worth noting is that not all ids will always be used. Once a batch is checked out, none of the ids in it can ever be reallocated by SnowMaker. If a batch is checked out, only one id is used, then the process terminates, the remaining ids in that batch will be lost forever.
Here’s a sequence diagram for one client:
Here’s a more complex sequence diagram that shows two clients interacting with the store, each using a different batch size: