在多个goroutine中使用命名空间UUIDs

huangapple go评论78阅读模式
英文:

Namespaced uuid's in multiple goroutines

问题

我想在Go语言中创建一个“无冲突”的唯一标识符,用于高度可扩展的应用程序。

维基百科推荐使用UUID的命名空间变体(我只能假设是指版本3或5)。
维基百科明确指出:

在分布式应用程序中需要唯一标识符,以便即使合并来自许多设备的数据时,UUID也不会冲突,每个设备上使用的种子和生成器的随机性必须在应用程序的生命周期内可靠。如果不可行,RFC4122建议使用命名空间变体。

我在这方面遇到了一些困难:

  1. 版本3和5需要对数据进行哈希,这似乎是一种不必要的操作,原因如下:

1.1. 应用程序可能使用相同的数据(我希望为其生成不同的标识符)。

1.2. 我假设在数据泄露方面,内部random()熵被认为是安全的,我不明白为什么需要密码哈希(因为我猜测哈希比一些种子计算需要更多资源)。

  1. 命名空间应该是一个值,可以防止在高并发环境中可能出现的冲突。在Go中,goroutine可以并行运行,并且由于服务器性能高(如维基百科所提到的),可能会使用相同的种子。我假设最好的命名空间值是goroutine的ID,这样可以避免在同一台机器上发生冲突。我找不到任何合适的方法来获取当前goroutine执行的唯一ID。

  2. 如果维基百科实际上是指版本4(随机)与命名空间组件,那么如何生成这样的GUID?文档没有显示这种选项。

TL;DR:
如何在Golang中正确、安全和可扩展地生成唯一标识符?

英文:

I Would like to create a "collision-free" unique id in go language, for highly-scalable application.

Wikipedia recommends a namespace variation of the UUID (That I could only assume referes to version 3 or 5)
Wikipedia Specifically states:
> Where unique identifiers are required for distributed applications, so that UUIDs do not clash even when data from many devices is merged, the randomness of the seeds and generators used on every device must be reliable for the life of the application. Where this is not feasible, RFC4122 recommends using a namespace variant instead.

I'm having a few difficulties with this

  1. Version 3 and 5 requires to hash the data which seems like an unnecessary thing to do for the falowing reasons:

1.1. I the application might use the same data (that I would like a different id for)

1.2. I assume that in data-leakage terms internal random() entropy is considered secured I don't understand why cryptograpic hashing is needed (as hashing I guess takes WAY more resources then some seed calculations).

  1. Namespace should be a value that would protect against collisions that might arise in a high-concurrency environment. In GO, goroutine can run in parallel, and might use the same seed due to high server performance (as wikipedia mentioned). I Assume that the best value for the namespace is the id of the goroutine thus collisions could be avoided on the same machine. I Cannot find any proper way to retrive a uniqe id for the current goroutine execution.

  2. If in fact wikipedia revers to version 4 (random) with a namespace component, How do I generate such guid? the docs do not show this kind of option

TL;DR:
How do I properly securely and scalably generate unique ids in GOLang ?

答案1

得分: 2

文档中指出:func NewRandom() - 返回一个随机的 UUID(版本 4)或者引发 panic。UUID 的强度基于 crypto/rand 包的强度。

这意味着该包使用 crypto/rand 加密强度的随机数生成类型 4 的 UUID。个人而言,如果实现中没有错误,我会相信它,除非我每天要生成数十亿个 ID。

另一个选项是使用版本 5:func NewSHA1(space UUID, data []byte) UUID,并将一个版本 1 的 UUID 作为命名空间,将 crypto/rand 的数据作为“data”。例如:

// 这是该机器的静态命名空间
var namespace = uuid.NewUUID()

// 使用全局命名空间生成随机 UUID
func NewNamespacedRandom() (uuid.UUID, error) {
    // 读取 16 个 crypto-random 字节
    rnd := make([]byte, 16)
    if _, err := rand.Read(rnd); err != nil {
        return nil, err
    }
    return uuid.NewSHA1(namespace, rnd), nil
}

func main() {
    u, err := NewNamespacedRandom()
    if err != nil {
        panic(err)
    }
    fmt.Println(u)
}

希望对你有所帮助!

英文:

The doc states that: func NewRandom() - returns a Random (Version 4) UUID or panics. The strength of the UUIDs is based on the strength of the crypto/rand package.

This means that this package is using the crypto/rand cryptographic strength random to generate type 4 uuids. Personally, provided there aren't bugs in the implementation, I'd trust that unless I'm generating billions of ids daily.

Another option is to use Version 5: func NewSHA1(space UUID, data []byte) UUID, and feed it a Vesion 1 UUID as the namespace, and data from crypto/random as the "data". i.e something like this:

// this is a static namespace for this machine, say
var namespace = uuid.NewUUID()


// generate a random UUID with the global namespace
func NewNamespacedRandom() (uuid.UUID, error) {
	
	// read 16 crypto-random bytes
	rnd := make([]byte, 16)
	if _, err := rand.Read(rnd); err != nil {
		return nil, err
	}
	
	return uuid.NewSHA1(namespace, rnd), nil
}

func main() {
		
	u, err := NewNamespacedRandom()
	if err != nil {
		panic(err)
	}
	fmt.Println(u)

}

huangapple
  • 本文由 发表于 2014年12月22日 01:49:59
  • 转载请务必保留本文链接:https://go.coder-hub.com/27592074.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定