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
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).
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.
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 ?
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)
}