- In past single-library single-phenotype systems, it was often possible to use the auto_INCREMENT attribute inherent in a database field to automatically generate a unique ID for each record. However, after the database is divided into tables, it is impossible to rely on the auto_increment attribute of the database to uniquely identify a record. At this point we can use ZooKeeper to generate globally unique ids in a distributed environment
- Design ideas
- The ZooKeeper server is connected
- Specifies a path to generate a persistent ordered node
- Obtain the serial number and the unique ID in the distributed environment
Experiment 1.
public class GloballyUniqueId implements Watcher.Closeable {
private String ip = null; // IP address and port
private static Integer timeOut = 5000; // Timeout in milliseconds
private final static CountDownLatch countDownLatch = new CountDownLatch(1);
private final static Logger log = Logger.getLogger(GloballyUniqueId.class);
private ZooKeeper zooKeeper = null;
private String parentPath = "/uniqueId";
private GloballyUniqueId(a) {}public GloballyUniqueId(String ip) {
this(ip, timeOut);
}
public GloballyUniqueId(String ip, Integer timeOut) {
this.ip = ip;
GloballyUniqueId.timeOut = timeOut;
initZK(ip, timeOut);
}
public GloballyUniqueId setParentPath(String parentPath) {
this.parentPath = parentPath;
return this;
}
/** * Initialize ZooKeeper **@param ip
* @param timeOut
* @throws IOException
* @throws InterruptedException
*/
private void initZK(String ip, Integer timeOut) {
try {
zooKeeper = new ZooKeeper(ip, timeOut, this);
countDownLatch.await();
} catch (IOException | InterruptedException e) {
log.error("Failed to initialize ZooKeeper"); e.printStackTrace(); }}@Override
public void process(WatchedEvent watchedEvent) {
if (watchedEvent.getType() == Event.EventType.None) {
switch (watchedEvent.getState()) {
case SyncConnected:
log.info("Connection" + ip + "Success");
countDownLatch.countDown();
break;
case Disconnected:
log.error("Connection" + ip + "Disconnected");
break;
case Expired:
log.error("Connection" + ip + "Timed out, need to reconnect server side");
this.initZK(ip, timeOut);
break;
case AuthFailed:
log.error("Authentication failed");
break; }}}/** * key!! Use to generate a new ID by persisting the sequential node and return *@return
* @throws KeeperException
* @throws InterruptedException
*/
public String getUniqueID(a) throws KeeperException, InterruptedException {
if (zooKeeper.exists(parentPath, null) = =null) {
zooKeeper.create(parentPath, "0".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
}
String path = zooKeeper.create(parentPath + parentPath, "0".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT_SEQUENTIAL);
return path.substring(2 * parentPath.length() + 1);
}
@Override
public void close(a) {
try {
zooKeeper.close();
log.info("ZooKeeper is closed");
} catch(InterruptedException e) { e.printStackTrace(); }}}Copy the code
public class GloballyUniqueIdTest {
private final static String IP = "192.168.233.133:2181"; // IP address and port
public static void main(String[] args) {
ExecutorService threadPool = Executors.newCachedThreadPool();
for (int i = 0; i < 4; i++) {
threadPool.execute(new ProductId());
}
threadPool.shutdown();
}
@Slf4j
static class ProductId implements Runnable {
@Override
public void run(a) {
GloballyUniqueId globallyUniqueId = new GloballyUniqueId(IP);
for (int i = 0; i < 30; i++) {
try {
String id = globallyUniqueId.getUniqueID();
log.info(id);
//Thread.sleep(1000);
} catch(KeeperException | InterruptedException e) { e.printStackTrace(); } } globallyUniqueId.close(); }}}Copy the code