• 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
  1. The ZooKeeper server is connected
  2. Specifies a path to generate a persistent ordered node
  3. 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