这是我参与8月更文挑战的第20天,活动详情查看:8月更文挑战
什么是 UUID ?
UUID 的目的是让分布式系统中的所有元素,都有能够为方便的辨识信息,来表示唯一的序列号,无需考虑数据库创建时名称重复问题,目前最广泛应用的 UUID 是 RFC4122 协议规范。
wiki百科说明: en.wikipedia.org/wiki/Univer…
uuid 规范定义了包含网卡 MAC 地址,时间戳 、NameSpace 、随机或者伪随机、时序等基本元素。根据这些元素生成 UUID。
UUID 例子
1个 UUID 被 -
分成了五段。
比如: 00d460f0-ec1a-4a0f-a452-1afb4b5d1686
格式是 8-4-4-4-12 共 32个字符。其中的字母是 16进制,并且大小写无关的。
UUID 版本迭代
xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx
M: 表示版本号,只会是1 2 3 4 5
N: 只会是 8 9 a b
Version 1, based on timestamp and MAC address (RFC 4122)
Version 2, based on timestamp, MAC address and POSIX UID/GID (DCE 1.1)
Version 3, based on MD5 hashing (RFC 4122)
Version 4, based on random numbers (RFC 4122)
Version 5, based on SHA-1 hashing (RFC 4122)
v1 版本说明
v1 是基于当前时间戳、机器 MAC 地址生成的,因为 MAC 地址是全球唯一的。从而保证 UUID 唯一,这种方式其实暴露了 MAC 地址和生成时间。
v2版本说明
基于时间的 UUID 算法相同,会把时间戳的前4位换成 POSIX 的UID 和GID
v3版本说明
用户指定了一个命名空间和一个具体字符串, 然后通过 MD5散列来生成 UUID。
v4基于随机数
根据随机数或者伪随机数生成 UUID, 这个版本用的比较多。
生成 UUID
Linux 系统上命令usr/bin/uuidgen
生成
>usr/bin/uuidgen
173B0C0E-C08F-4EB1-9228-6F1EDC45A98E
go 语言中,可以直接用代码调用系统命令生成
func TestUUID1(t *testing.T) {
out, err := exec.Command("uuidgen").Output()
if err != nil {
log.Fatal(err)
}
fmt.Printf("%s \n", out)
}
执行结果
=== RUN TestUUID1
5E3D6415-64A1-473A-9EB3-03C3E6F3A291
--- PASS: TestUUID1 (0.00s)
PASS
google 包生成 UUID
需要下载包 go get -u -v github.com/google/uuid
func TestUUID(t *testing.T) {
// V1 基于时间
u1, err := uuid.NewUUID()
if err != nil {
log.Fatal(err)
}
fmt.Println(u1.String())
// V4 基于随机数
u4 := uuid.New()
fmt.Println(u4.String()) // a0d99f20-1dd1-459b-b516-dfeca4005203
}
执行结果:
=== RUN TestUUID
b3e75f46-066b-11ec-807e-acde48001122
11b396b9-c7cf-4b76-86f5-1700ea2a237d
--- PASS: TestUUID (0.00s)
PASS
v4 版本的源码
V4 是根据随机数生成的
源码如下:
// Copyright 2016 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import "io"
// New creates a new random UUID or panics. New is equivalent to
// the expression
//
// uuid.Must(uuid.NewRandom())
func New() UUID {
return Must(NewRandom())
}
// NewString creates a new random UUID and returns it as a string or panics.
// NewString is equivalent to the expression
//
// uuid.New().String()
func NewString() string {
return Must(NewRandom()).String()
}
// NewRandom returns a Random (Version 4) UUID.
//
// The strength of the UUIDs is based on the strength of the crypto/rand
// package.
//
// Uses the randomness pool if it was enabled with EnableRandPool.
//
// A note about uniqueness derived from the UUID Wikipedia entry:
//
// Randomly generated UUIDs have 122 random bits. One's annual risk of being
// hit by a meteorite is estimated to be one chance in 17 billion, that
// means the probability is about 0.00000000006 (6 × 10−11),
// equivalent to the odds of creating a few tens of trillions of UUIDs in a
// year and having one duplicate.
func NewRandom() (UUID, error) {
if !poolEnabled {
return NewRandomFromReader(rander)
}
return newRandomFromPool()
}
// NewRandomFromReader returns a UUID based on bytes read from a given io.Reader.
func NewRandomFromReader(r io.Reader) (UUID, error) {
var uuid UUID
_, err := io.ReadFull(r, uuid[:])
if err != nil {
return Nil, err
}
uuid[6] = (uuid[6] & 0x0f) | 0x40 // Version 4
uuid[8] = (uuid[8] & 0x3f) | 0x80 // Variant is 10
return uuid, nil
}
func newRandomFromPool() (UUID, error) {
var uuid UUID
poolMu.Lock()
if poolPos == randPoolSize {
_, err := io.ReadFull(rander, pool[:])
if err != nil {
poolMu.Unlock()
return Nil, err
}
poolPos = 0
}
copy(uuid[:], pool[poolPos:(poolPos+16)])
poolPos += 16
poolMu.Unlock()
uuid[6] = (uuid[6] & 0x0f) | 0x40 // Version 4
uuid[8] = (uuid[8] & 0x3f) | 0x80 // Variant is 10
return uuid, nil
}