Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

关于Leaf-snowflake解决时钟回拨的本质 #104

Open
hellolvs opened this issue Apr 29, 2020 · 9 comments
Open

关于Leaf-snowflake解决时钟回拨的本质 #104

hellolvs opened this issue Apr 29, 2020 · 9 comments

Comments

@hellolvs
Copy link

不知道是不是理解错误,本质就是用zookeeper判断是否发生时钟回拨,发生就报警? 本地保存上次时间戳不就可以判断是否回拨吗?

@NotFound9
Copy link

NotFound9 commented Apr 29, 2020

zookeeper除了起保存上次时间戳的作用,还起给每个ip:port分配一个固定的workId的作用(通过在zookeeper特定路径下创建永久有序节点,序号作为workId),如果不用zookeeper,那么使用新的机器或者新的端口部署leaf服务会没法获得唯一的workId。所以不知道考虑到一些小公司,他们在使用leaf时,需要单独维护一个zookeeper集群,是否代价太大,能否增加以下两种workId分配方式:
1.使用数据库来作为注册中心,
使用数据库替代替代zookeeper,因为一般的后端项目都会使用到数据库的概率,而不一定会有专门维护的zookeeper集群。
2.在项目中显式分配workID
针对一些小公司,他们可能一般部署leaf服务的ip和port不会变化。在项目中的配置文件显式得配置某某ip:某某port对应哪个workId,每次部署新机器,新port的时候在项目中添加这个配置,然后时间戳也每次同步到机器上。

@Yaccc 你好,这两种workId分配方式我已经开发完成,稍后会push到我fork的项目中https://github.com/NotFound9/Leaf
不知道Leaf项目需不需要这两种模式,如果Leaf项目需要这两种模式,我也希望可以给Leaf项目提PR,谢谢了

@NotFound9
Copy link

@hellolvs 你好,原有的模式在连接Zookeeper失败后会使用本地缓存的workerID.properties文件,但是这个文件只存了workId,没有存时间戳,所以还是存在潜在的时间回拨问题,我对这个问题进行了修复,并且增加了很多新的功能支持,你可以看看我的这个项目
https://github.com/NotFound9/Leaf

@nekolr
Copy link

nekolr commented May 20, 2020

你好,我这里有另外一种处理时钟回拨的思路,具体参考的是:https://www.jianshu.com/p/b1124283fc43,在他的基础上我进行了修改,我的 fork:https://github.com/nekolr/Leaf/tree/ring_snowflake

@NotFound9
Copy link

你好,我这里有另外一种处理时钟回拨的思路,具体参考的是:https://www.jianshu.com/p/b1124283fc43,在他的基础上我进行了修改,我的 fork:https://github.com/nekolr/Leaf/tree/ring_snowflake

简书这篇文章里面写的代码是有问题的,单看这种方案的话,
好处也仅仅是时钟回拨时,可以复用一些之前剩余的ID,维持一小段时间,而且能维持的时间也取决于平常的获取ID的QPS,没有真正解决时钟回拨问题。
坏处是仅仅为了在发生时钟回拨时能多维持一段时间,就每次获取ID都需要去使用CAS操作更新数组,开销比较大。而且时间回拨后使用的这些ID的生成时间与实际获取时间不一致。

这种方案还不如为每一个正在运行的节点分配一个备用的机器ID,发生时间回拨时,如果回拨时间较短就休眠等待,回拨时间较长就使用备用的机器ID。使用备用ID时,再次发送回拨的话就抛出异常。

@nekolr
Copy link

nekolr commented May 20, 2020

你好,我这里有另外一种处理时钟回拨的思路,具体参考的是:https://www.jianshu.com/p/b1124283fc43,在他的基础上我进行了修改,我的 fork:https://github.com/nekolr/Leaf/tree/ring_snowflake

简书这篇文章里面写的代码是有问题的,单看这种方案的话,
好处也仅仅是时钟回拨时,可以复用一些之前剩余的ID,维持一小段时间,而且能维持的时间也取决于平常的获取ID的QPS,没有真正解决时钟回拨问题。
坏处是仅仅为了在发生时钟回拨时能多维持一段时间,就每次获取ID都需要去使用CAS操作更新数组,开销比较大。而且时间回拨后使用的这些ID的生成时间与实际获取时间不一致。

这种方案还不如为每一个正在运行的节点分配一个备用的机器ID,发生时间回拨时,如果回拨时间较短就休眠等待,回拨时间较长就使用备用的机器ID。使用备用ID时,再次发送回拨的话就抛出异常。

CAS 操作与 Leaf 的同步获取 ID 相比,理论上来说相差应该不大吧。
生成时间与获取时间不一致会有什么问题吗?

@NotFound9
Copy link

NotFound9 commented May 20, 2020

时间不一致一般不会有什么问题,只是丧失了一些业务含义,如果一些业务要求id跟生成时间必须一直到话。这种方案跟普通的获取ID的方案有额外的判断和CAS操作存储ID的时间开销和内存开销,而且发生了时间回拨也无法真正解决问题,只是多维持了一段时间。

@nekolr
Copy link

nekolr commented May 20, 2020

时间不一致一般不会有什么问题,只是丧失了一些业务含义,如果一些业务要求id跟生成时间必须一直到话。这种方案跟普通的获取ID的方案有额外的判断和CAS操作存储ID的时间开销和内存开销,而且发生了时间回拨也无法真正解决问题,只是多维持了一段时间。

感谢解答。

@automvc
Copy link

automvc commented Jun 8, 2020

https://www.jianshu.com/p/b1124283fc43

这个解决方案需要依赖redis,是不是与原来雪花算法的初衷不一样了

@NotFound9
Copy link

NotFound9 commented Jun 9, 2020

https://www.jianshu.com/p/b1124283fc43

这个解决方案需要依赖redis,是不是与原来雪花算法的初衷不一样了

目前几乎所有的分布式id生成框架都是有依赖的,因为需要对不同机器上生成的分布式id进行区分,所以每个部署了Leaf服务的ip:port都会有一个workID,Leaf依赖于Zookeeper去给每个ip:port分配一个workID,百度的uid-generator每次机器启动时依赖于数据库的自增键,分配一个workID。只是依赖强弱的区别,Leaf框架目前来看启动时,运行期间都是依赖于Zookeeper的,虽然说运行期间Zookeeper挂了,可以继续运行,但是会导致当前生成id的最大时间戳不能上报,而百度的uid-generator只在启动时依赖数据库,因为每次启动时获得的workID是不同的,下次启动时不需要复用上次的workID。

如果你要做到没有依赖,只能是在项目中的property配置文件中写一个映射表,对每个会部署分布式id服务的机器IP:port对应一个workId,也就是我fork了Leaf项目后,开发的local模式
项目地址:https://github.com/NotFound9/Leaf
介绍文章:https://juejin.im/post/5eaea4f4f265da7b991c4c31

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants