讲好一个项目(一)序列号生成器

442 阅读2分钟

雪花算法

雪花算法生成的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/"路径下创建临时顺序节点判断自己是否为当前最小顺序节点,如果是则获取锁,不是则监听其前一个节点的状态。