雪花算法
雪花算法生成的64位ID的含义如上图所示,
其中10bit工作机器Id可自行划分为机房Id和机器Id两部分。
使用zookeeper实现机器Id的生成
实现场景中可能遇到的问题是: 机器id有数量上限,假如机器id占位6位,则每个机房最多支持64台机器。假如一个机器Id对应一个zk的永久节点,服务下线,部署该服务的机器Id对应的节点并不会删除,即没有机器Id回收机制。
采用临时节点的话,服务下线,临时节点会自动删除,[0,64)范围的整数可以重复使用,也解决了服务宕机情况下节点的回收问题。
解决并发问题 —— 依赖zk实现独占分布式锁
加锁的原理: zk监听path="/lock"节点是否被删除(zk.exists(path,watcher)),锁节点删除时认为当前线程获得锁,watcher回调创建锁节点执行业务逻辑,最后删除锁节点表示释放分布式锁。
Stat stat = zk.exists("lock_path", new Watcher() {
@Override
public void process(WatchedEvent event) {
if (event.getState() == KeeperState.SyncConnected &&event.getType() == EventType.NodeDeleted) {
//业务逻辑
//.....
}
});
以上监听存在的问题 : 当多个线程走到zk.exists时,没有获得锁则注册了对lock_path的监听,锁被释放时,所有blocked的线程都会被唤醒来争抢锁,一方面会产生惊群效应,更严重的是没有抢到锁的线程就直接返回失败的结果,并不会再继续监听锁节点的变化。
正确的监听逻辑 : 多米诺式监听,"/lock_path/"路径下创建临时顺序节点判断自己是否为当前最小顺序节点,如果是则获取锁,不是则监听其前一个节点的状态。