- 在过去的单库单表型系统中,通常可以使用数据库字段自带的auto_increment 属性来自动为每条记录生成一个唯一的ID。但是分库分表后,就无法在依靠数据库的 auto_increment属性来唯一标识一条记录了。此时我们就可以用zookeeper在分布式环 境下生成全局唯一ID
- 设计思路
- 连接zookeeper服务器
- 指定路径生成持久有序节点
- 取序列号及为分布式环境下的唯一ID
1. 实验
public class GloballyUniqueId implements Watcher, Closeable {
private String ip = null;
private static Integer timeOut = 5000;
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() {
}
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;
}
private void initZK(String ip, Integer timeOut) {
try {
zooKeeper = new ZooKeeper(ip, timeOut, this);
countDownLatch.await();
} catch (IOException | InterruptedException e) {
log.error("初始化zookeeper失败");
e.printStackTrace();
}
}
@Override
public void process(WatchedEvent watchedEvent) {
if (watchedEvent.getType() == Event.EventType.None) {
switch (watchedEvent.getState()) {
case SyncConnected:
log.info("连接 " + ip + "成功");
countDownLatch.countDown();
break;
case Disconnected:
log.error("连接 " + ip + "已断开");
break;
case Expired:
log.error("连接 " + ip + "已超时,需要重新连接服务器端");
this.initZK(ip, timeOut);
break;
case AuthFailed:
log.error("身份验证失败");
break;
}
}
}
public String getUniqueID() 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() {
try {
zooKeeper.close();
log.info("zooKeeper已关闭");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class GloballyUniqueIdTest {
private final static String IP = "192.168.233.133:2181";
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() {
GloballyUniqueId globallyUniqueId = new GloballyUniqueId(IP);
for (int i = 0; i < 30; i++) {
try {
String id = globallyUniqueId.getUniqueID();
log.info(id);
} catch (KeeperException | InterruptedException e) {
e.printStackTrace();
}
}
globallyUniqueId.close();
}
}
}