@@ -75,7 +75,7 @@ limited number of 'clusters' exists). The generator-ID can also be assigned manu
7575usually it is desirable for processes to be able to exclusively claim a generator-ID
7676automatically.
7777
78- This library facilitates this using [ ZooKeeper] ( http://zookeeper.apache.org/ ) .
78+ This library facilitates this using [ Etcd ] ( https://etcd.io/ ) or [ Apache ZooKeeper] ( http://zookeeper.apache.org/ ) .
7979Generators can stake a claim on a generator-ID for a short period of time (usually ten
8080minutes), and repeat this whenever IDs are generated.
8181
@@ -122,25 +122,135 @@ For local usage the `uniqueid-core` module can be used:
122122</dependency >
123123```
124124
125- ### Distributed usage with a ZooKeeper quorum
125+ ### Distributed usage
126126
127127If you need to generate unique IDs within a distributed environment, automatic coordination of
128128the generator-ID is also a possibility. The acquisition of a generator-ID can be handled by a
129- ` SynchronizedGeneratorIdentity ` instance, which uses
130- [ Apache ZooKeeper] ( http://zookeeper.apache.org/ ) to claim its generator-ID — for a short while,
131- or as long as it maintains a connection to the ZooKeeper quorum.
129+ ` SynchronizedGeneratorIdentity ` instance, which uses [ Etcd] ( https://etcd.io/ ) or
130+ [ Apache ZooKeeper] ( http://zookeeper.apache.org/ ) to claim its generator-ID
132131
133- For this functionality the ` uniqueid-zookeeper ` module is used:
132+ #### With an Etcd cluster
133+
134+ For this Etcd the ` uniqueid-etcd ` module is used:
134135
135136``` xml
136137<dependency >
137138 <groupId >org.lable.oss.uniqueid</groupId >
138- <artifactId >uniqueid-core</artifactId >
139+ <artifactId >uniqueid-etcd</artifactId >
140+ <version >${uniqueid.version}</version >
141+ </dependency >
142+ ```
143+
144+ ##### Preparing the Etcd cluster
145+
146+ To use this method of generator-ID acquisition, a namespace on the Etcd cluster must
147+ be chosen to hold the resource pool used by ` SynchronizedGeneratorIdentity ` .
148+
149+ For example, if you choose ` unique-id-generator/ ` as the namespace, these keys can be
150+ automatically created when the library is used:
151+
152+ ```
153+ unique-id-generator/cluster-id
154+ unique-id-generator/pool/0
155+ unique-id-generator/pool/1
156+ …
157+ unique-id-generator/pool/255
158+ ```
159+
160+ Note that if you do not create the ` cluster-id ` key yourself (recommended), the default
161+ value of ` 0 ` will be used. To use a different cluster ID, set the content of this key to
162+ one of the 16 permissible values (i.e., ` 0..15 ` ).
163+
164+ If you have access to the ` etcdctl ` command line utility you can set the
165+ cluster-ID like so:
166+
167+ ```
168+ etcdctl --endpoints=… put unique-id-generator/cluster-id 1
169+ ```
170+
171+ ##### Using the generator
172+
173+ To use an ` IDGenerator ` with a negotiated generator-Id, create a new instance like this:
174+
175+ ``` java
176+ // Change the values of etcdCluster and namespace as needed:
177+ final List<String > etcdCluster = Arrays . asList(" https://etcd1:2379" ," https://etcd2:2379" ," https://etcd3:2379" );
178+ final String namespace = " unique-id-generator/" ;
179+ final ByteSequence ns = ByteSequence . from(namespace, StandardCharsets . UTF_8 );
180+ final Client client = Client . builder()
181+ .endpoints(etcdCluster)
182+ .namespace(ns)
183+ .build();
184+ IDGenerator generator = SynchronizedUniqueIDGeneratorFactory . generatorFor(client, Mode . SPREAD );
185+ // ...
186+ byte [] id = generator. generate()
187+ // ...
188+ ```
189+
190+ If you expect that you will be using dozens of IDs in a single process, it is more
191+ efficient to generate IDs in batches:
192+
193+ ``` java
194+ Deque<byte[]> ids = generator. batch(500 );
195+ // ...
196+ byte [] id = ids. pop();
197+ // etc.
198+ ```
199+
200+ If you intend to generate more than a few IDs at a time, you can also wrap the generator in
201+ an ` AutoRefillStack ` , and simply call ` generate() ` on that whenever you need a new ID.
202+ It will grab IDs in batches from the wrapped ` IDGenerator ` instance for you. This is
203+ probably the simplest and safest way to use an ` IDGenerator ` in the default ` SPREAD ` mode.
204+
205+ ``` java
206+ final List<String > etcdCluster = Arrays . asList(" https://etcd1:2379" ," https://etcd2:2379" ," https://etcd3:2379" );
207+ final String namespace = " unique-id-generator/" ;
208+ final ByteSequence ns = ByteSequence . from(namespace, StandardCharsets . UTF_8 );
209+ final Client client = Client . builder()
210+ .endpoints(etcdCluster)
211+ .namespace(ns)
212+ .build();
213+ IDGenerator generator = new AutoRefillStack (
214+ SynchronizedUniqueIDGeneratorFactory . generatorFor(client, Mode . SPREAD )
215+ );
216+ // ...
217+ byte [] id = generator. generate()
218+ // ...
219+ ```
220+
221+ For the ` TIME_SEQUENTIAL ` mode the above is usually not what you want, if you intend to use
222+ the timestamp stored in the generated ID as part of your data model (the batched pre-generated
223+ IDs might have a timestamp that lies further in the past then you might want).
224+
225+ ``` java
226+ final List<String > etcdCluster = Arrays . asList(" https://etcd1:2379" ," https://etcd2:2379" ," https://etcd3:2379" );
227+ final String namespace = " unique-id-generator/" ;
228+ final ByteSequence ns = ByteSequence . from(namespace, StandardCharsets . UTF_8 );
229+ final Client client = Client . builder()
230+ .endpoints(etcdCluster)
231+ .namespace(ns)
232+ .build();
233+ IDGenerator generator = SynchronizedUniqueIDGeneratorFactory . generatorFor(client, Mode . TIME_SEQUENTIAL );
234+ // ...
235+ byte [] id = generator. generate()
236+ // Extract the timestamp in the ID.
237+ long createdAt = IDBuilder . parseTimestamp(id);
238+ ```
239+
240+
241+ #### With a ZooKeeper quorum
242+
243+ For ZooKeeper the ` uniqueid-zookeeper ` module is used:
244+
245+ ``` xml
246+ <dependency >
247+ <groupId >org.lable.oss.uniqueid</groupId >
248+ <artifactId >uniqueid-zookeeper</artifactId >
139249 <version >${uniqueid.version}</version >
140250</dependency >
141251```
142252
143- #### Preparing the ZooKeeper quorum
253+ ##### Preparing the ZooKeeper quorum
144254
145255To use this method of generator-ID acquisition, a node on the ZooKeeper quorum must
146256be chosen to hold the queue and resource pool used by ` SynchronizedGeneratorIdentity ` .
@@ -172,7 +282,7 @@ Or if the node already exists:
172282set /unique-id-generator/cluster-id 1
173283```
174284
175- #### Using the generator
285+ ##### Using the generator
176286
177287To use an ` IDGenerator ` with a negotiated generator-Id, create a new instance like this:
178288
@@ -219,7 +329,7 @@ IDs might have a timestamp that lies further in the past then you might want).
219329``` java
220330final String zookeeperQuorum = " zookeeper1,zookeeper2,zookeeper3" ;
221331final String znode = " /unique-id-generator" ;
222- IDGenerator SynchronizedUniqueIDGeneratorFactory . generatorFor(zookeeperQuorum, znode, Mode . TIME_SEQUENTIAL );
332+ IDGenerator generator = SynchronizedUniqueIDGeneratorFactory . generatorFor(zookeeperQuorum, znode, Mode . TIME_SEQUENTIAL );
223333// ...
224334byte [] id = generator. generate()
225335// Extract the timestamp in the ID.
0 commit comments