@@ -75,7 +75,7 @@ limited number of 'clusters' exists). The generator-ID can also be assigned manu
75
75
usually it is desirable for processes to be able to exclusively claim a generator-ID
76
76
automatically.
77
77
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/ ) .
79
79
Generators can stake a claim on a generator-ID for a short period of time (usually ten
80
80
minutes), and repeat this whenever IDs are generated.
81
81
@@ -122,25 +122,135 @@ For local usage the `uniqueid-core` module can be used:
122
122
</dependency >
123
123
```
124
124
125
- ### Distributed usage with a ZooKeeper quorum
125
+ ### Distributed usage
126
126
127
127
If you need to generate unique IDs within a distributed environment, automatic coordination of
128
128
the 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
132
131
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:
134
135
135
136
``` xml
136
137
<dependency >
137
138
<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 >
139
249
<version >${uniqueid.version}</version >
140
250
</dependency >
141
251
```
142
252
143
- #### Preparing the ZooKeeper quorum
253
+ ##### Preparing the ZooKeeper quorum
144
254
145
255
To use this method of generator-ID acquisition, a node on the ZooKeeper quorum must
146
256
be chosen to hold the queue and resource pool used by ` SynchronizedGeneratorIdentity ` .
@@ -172,7 +282,7 @@ Or if the node already exists:
172
282
set /unique-id-generator/cluster-id 1
173
283
```
174
284
175
- #### Using the generator
285
+ ##### Using the generator
176
286
177
287
To use an ` IDGenerator ` with a negotiated generator-Id, create a new instance like this:
178
288
@@ -219,7 +329,7 @@ IDs might have a timestamp that lies further in the past then you might want).
219
329
``` java
220
330
final String zookeeperQuorum = " zookeeper1,zookeeper2,zookeeper3" ;
221
331
final String znode = " /unique-id-generator" ;
222
- IDGenerator SynchronizedUniqueIDGeneratorFactory . generatorFor(zookeeperQuorum, znode, Mode . TIME_SEQUENTIAL );
332
+ IDGenerator generator = SynchronizedUniqueIDGeneratorFactory . generatorFor(zookeeperQuorum, znode, Mode . TIME_SEQUENTIAL );
223
333
// ...
224
334
byte [] id = generator. generate()
225
335
// Extract the timestamp in the ID.
0 commit comments