Raindrop
Raindrop is a distributed id generation utility that mimics the MongoDB BSON ObjectID implementation, with a few key tweaks.
The Raindrop is a 24 character hex string that is automatically encoded into a compact 16 character string represented with the following alphabet:
abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_
The core hex identifier is represented with the following attributes:
- 4-byte value representing the seconds since the Unix epoch (32-bit timestamp down to the second)
- 3-byte process identifier (defaults to random value or user input)
- 1-byte service id (defaults to 0 or user input)
- 1-byte entity type id (defaults to 0 or user input)
- 3-byte incremental counter, reset every second to a random start value
This means the physical structure of the identifier's 5 components is:
FFFFFFFF FFFFFF FF FF FFFFFF
Note: Once the 3-byte incremental counter hits the medium int maximum (12,777,215), it will roll over to 0 and start again
Raindrop is entirely deconstructable into its core values, to allow for the id to travel with key information regarding service origination id and domain-specific entity type identifiers.
Chance of collisions
Raindrops that are generated are highly likely to be unique across collections. The 3-byte incrementing counter is set to a random value every second an operation is performed. Therefore, a total of 16,777,215 unique ids could be inserted every second with the same unique process id and the same service id, without chance of collision.
As long as process id remains unique amongst all of your running processes, and your service id is always registered as being unique, and you do not try to store more than 16,777,215 ids per second, per process id, per service id, you will avoid collisions.
It's recommended to have your service instance pass in a process id likely a combination of machine identifier along with a process id such as a PM2 cluster process identifier.
Motivation
You may be asking yourself, why not just use a GUID? Or perhaps a UUID generator? Isn't that good enough? Maybe. But what if you care about storing some embedded internal domain specific data within your identifier? Why not have your identifier provide some information to help you out? Raindrop gives you:
- Embeddable user-defined information to store 2 bytes of custom information, highly applicable across a tightly controlled service environment. Embed a marker with these attributes on issuing the id to help assist with type and service lookups later on.
- Avoid unnecessary lookups to your data store to determine service issuer and entity type. Create efficiency and optimization by decoding and parsing the information inline as you receive it.
- Reduces the overall id storage footprint by 32 bits over UUID.Raindrop is 96-bit, UUID is 128-bit. This can improve overall data storage efficiency.
- Uses a custom URL-safe alphabet beyond hex to shrink the represented string even further to just 16 characters. UUID/GUID will contain 32-38 characters. This is ideal where sending lengthy strings in URLs or message strings can impact performance.
- Based on an established distributed ID generation system in used by MongoDB. This is not reinventing the wheel; it's just painting the wheel a different color.
Install
$ npm install raindrop
Usage
'use strict' const raindrop = // set options for entityTypeId (0 - 255)// set options for processId (0 - 16777215)// set options for serviceId (0 - 255)const options = 'entityTypeId': 4 'processId': 7844 'serviceId': 1 // create new raindrop with optionsconst drop = // get Raindrop objectconsole // get Raindrop version info (returns Raindrop object version)console // get Raindrop object id as 16 character stringconsole // get Raindrop object materials propertyconsole // get Raindrop object decoded propertiesconsole // get Raindrop object as 24 character hex stringconsole // get timestamp portion up to the second as ISO 8601 date from UTCconsole // get entity type id decodedconsole // get process id decodedconsole // get service id decodedconsole // get counter for that 1 second timestamp range decodedconsole // see if one Raindrop object equals another // trueconsole const drop2 = // falseconsole
License
MIT ©2016 codemouse