这一部分由于内部技术栈的问题,需要统一,同时,需要有更多的改造,接入公司内部RPC,导入一致的服务治理等需求,所以需要一个Go版本的发号器,搜了网上很多版本,发现并没有Leaf的替代版本,而Leaf的实现细节有很多文章都分析过了,这样看起来移植一下也不困难了。

美团Leaf的技术细节在官方文档中介绍的很详细,这里参考其技术实现细节Leaf——美团点评分布式ID生成系统

遇到的问题

号段模式

在号段模式时,碰到的问题主要有两个:

  • 锁竞的问题
  • context传递的问题

锁竞争的问题是在请求中使用锁,但我在最初的版本中,当并发比较大时,就会出现死锁的问题。后面使用闭包+defer解决了此问题。

1
2
3
4
5
6
7
8
9
10
if value := func() int64 {
cacheSegmentBuffer.RLock()
defer cacheSegmentBuffer.RUnLock()

......

return 0
}(); value != 0 {
return value, nil
}

context传递的问题,这个其实在gin中就碰到过,在handler中开协程出去,若是将handler中的context传递过去,这里面就会出问题,因为handler中的context在handler主体执行完后,会执行context的cancel(若该上下文其为timeout context),也就会导致协程若是用到了这个上下文也会被cancel。

所以这里我改为在传递的时候传入context.TODO()

雪花算法

这里面遇到的问题,就是在创建实例节点的时候,没有自增序号的问题,我这里借助etcd的迷你事务TXN,通过乐观锁形式的创建方式,去创建key,这样来防止创建重复的键值。

输出

https://github.com/younglifestyle/seg-server

参考

美团Leaf源码——号段模式源码解析

美团Leaf源码——snowflake模式源码解析

美团Leaf snowflake模式详解