golang生成30位uuid

2,485 阅读1分钟
原文链接: www.aprilboy.com

uuid简介

uuid是通用识别码(Universally Unique Identifier)的缩写,它的作用是让分布式系统中的所有元素都具有唯一标识,也可以用来生成数据库中的主键。其要求是所有机器同一时间或不同时间生成的uuid都不一致,这里提供了golang关于30位uuid的实现,参考自MongoDb的ObjectId。

时间戳,8位

获取生成时刻的时间戳,16进制,能用到2106/2/7 14:28:15

计算机名Hash值,6位

读取计算机名字,并调用adler32来生成hash值,再转为16进制

进程Id,8位

调用os.Getpid()来获取进程编号,并转化为16进制

uint32自增值,8位

声明静态自增值count,每次访问count时对count采用原子自增操作,降低碰撞率

实现

import (
	"bytes"
	"crypto/rand"
	"encoding/binary"
	"encoding/hex"
	"fmt"
	"hash/adler32"
	"io"
	"os"
	"sync/atomic"
	"time"
)
 
var machineId = getMachineId()
var processId = getPid()
 
func getMachineId() []byte {
	id := make([]byte, 3)
 
	hostName, err1 := os.Hostname()
	fmt.Println(hostName)
	if err1 != nil {
		_, err2 := io.ReadFull(rand.Reader, id)
		if err2 != nil {
			panic("无法读取计算机名")
		}
 
		return id
	}
 
	hash := adler32.New()
	hash.Write([]byte(hostName))
 
	copy(id, hash.Sum(nil))
 
	return id
}
 
func getPid() []byte {
	pid := make([]byte, 4)
	pidNo := os.Getpid()
 
	pid[0] = byte(pidNo >> 24)
	pid[1] = byte(pidNo >> 16)
	pid[2] = byte(pidNo >> 8)
	pid[3] = byte(pidNo)
 
	return pid
}
 
type IdGenerator struct {
	counter uint32
}
 
func (generator *IdGenerator) Generate() string {
	buffer := bytes.Buffer{}
	buffer.Write(generator.getUnix())
	buffer.Write(machineId)
	buffer.Write(processId)
	buffer.Write(generator.getCount())
 
	return hex.EncodeToString(buffer.Bytes())
}
 
func (generator *IdGenerator) getUnix() []byte {
	bytes := make([]byte, 8)
 
	binary.BigEndian.PutUint64(bytes, uint64(time.Now().Unix()))
 
	return bytes[4:]
}
 
func (generator *IdGenerator) getCount() []byte {
	count := atomic.AddUint32(&generator.counter, 1)
	countRes := make([]byte, 4)
 
	countRes[0] = byte(count >> 24)
	countRes[1] = byte(count >> 16)
	countRes[2] = byte(count >> 8)
	countRes[3] = byte(count)
 
	return countRes
}