A unique ID generator that generates unique¹ eight byte identifiers in a distributed context.
- Unique within the confines of the chosen computing environment.
When you want to assign unique identifiers to database records in a distributed computing environment that are short and guaranteed to be unique (within your data realm), this library can provide them.
For Java 8 and newer, please use the 2.x
series of releases. For Java 7 version 1.14
may be
used.
If you have a computing environment where you know exactly which processes may generate IDs.
The simple LocalUniqueIDGenerator
can be used. This generator assumes that you know which
process may use which generator-ID at any time.
For example, if you have just one process that handles the creation of new IDs (perhaps a single server that creates database records using these IDs), a generator can be used like this:
final int generatorID = 0;
final int clusterID = 0;
IDGenerator generator = LocalUniqueIDGeneratorFactory.generatorFor(generatorID, clusterID);
// Generate IDs
byte[] id = generator.generate();
The LocalUniqueIDGeneratorFactory
assumes that you can guarantee that it is the only
generator with the specific generator-ID and cluster-ID combination you chose, during its
lifetime.
If there is a fixed number of processes that may generate IDs, you can assign one of the 256 possible generator-IDs to each one. For a more in-depth explanation of generator-IDs and cluster-IDs, see eight byte ID structure.
For a cluster of Tomcat servers in a high-availability setup, you could configure a system property on each server with a unique generator ID.
For local usage the uniqueid-core
module can be used:
<dependency>
<groupId>org.lable.oss.uniqueid</groupId>
<artifactId>uniqueid-core</artifactId>
<version>${uniqueid.version}</version>
</dependency>
If you need to generate unique IDs within a distributed environment, automatic coordination of
the generator-ID is also a possibility. The acquisition of a generator-ID can be handled by a
SynchronizedGeneratorIdentity
instance, which uses
Apache ZooKeeper to claim its generator-ID — for a short while,
or as long as it maintains a connection to the ZooKeeper quorum.
For this functionality the uniqueid-zookeeper
module is used:
<dependency>
<groupId>org.lable.oss.uniqueid</groupId>
<artifactId>uniqueid-core</artifactId>
<version>${uniqueid.version}</version>
</dependency>
To use this method of generator-ID acquisition, a node on the ZooKeeper quorum must
be chosen to hold the queue and resource pool used by SynchronizedGeneratorIdentity
.
For example, if you choose /unique-id-generator
as the node, these child nodes will be
created:
/unique-id-generator/
├─ queue/
├─ pool/
└─ cluster-id
Note that if you do not create the cluster-id
node yourself (recommended), the default
value of 0
will be used. To use a different cluster ID, set the content of this znode to
one of the 16 permissible values (i.e., 0..15
).
If you have access to the zkcli
(or hbase zkcli
) command line utility you can set the
cluster-ID like so:
create /unique-id-generator/cluster-id 1
Or if the node already exists:
set /unique-id-generator/cluster-id 1
To use an IDGenerator
with a negotiated generator-Id, create a new instance like this:
// Change the values of zookeeperQuorum and znode as needed:
final String zookeeperQuorum = "zookeeper1,zookeeper2,zookeeper3";
final String znode = "/unique-id-generator";
IDGenerator generator = SynchronizedUniqueIDGeneratorFactory.generatorFor(zookeeperQuorum, znode);
// ...
byte[] id = generator.generate()
// ...
If you expect that you will be using dozens of IDs in a single process, it is more efficient to generate IDs in batches:
Deque<byte[]> ids = generator.batch(500);
// ...
byte[] id = ids.pop();
// etc.
If you intend to generate more than a few IDs at a time, you can also wrap the generator in
an AutoRefillStack
, and simply call generate()
on that whenever you need a new ID.
It will grab IDs in batches from the wrapped IDGenerator
instance for you. This is
probably the simplest and safest way to use an IDGenerator
.
final String zookeeperQuorum = "zookeeper1,zookeeper2,zookeeper3";
final String znode = "/unique-id-generator";
IDGenerator generator = new AutoRefillStack(
SynchronizedUniqueIDGeneratorFactory.generatorFor(zookeeperQuorum, znode)
);
// ...
byte[] id = generator.generate()
// ...