全局唯一键的一种生成方案(golang)

概述

主要是两部分内容:

  1. 设计一种不易冲突的唯一键生成方案.
  2. 一次唯一键冲突的解决实录

设计一种不易冲突的唯一键生成方案.

一句话说明

使用纳秒数做36进制转换后得到的数字与字母组合成的值作为唯一键.足以应付中等并发量的服务(QPS约等于120).

var num2char = "0123456789abcdefghijklmnopqrstuvwxyz"

//10进制转16或36进制
func NumToBHex(num ,n int) string {
	numStr := ""
	for num != 0 {
		yu := num % n
		numStr = string(num2char[yu]) + numStr
		num = num / n
	}
	return numStr
}

//唯一键生成函数
func getUniqId() (uniqId string){
	uniqId = NumToBHex(int(time.Now().UnixNano()), 36)
	return uniqId
}

一次唯一键冲突的解决实录

其实问题是发现了原本一个以为可靠的方案竟然出现了唯一键冲突, 定位问题的记录如下.

原生成方案原理

[0,9] 1个数字 加上 [a~z]26个字母, 生成一个36进制, 长度为10的唯一键, 按理说发生冲突的概率已经很小很小.

生成代码如下:

func getUniqId() string {
	var uniqId string
	for i := 0; i < 10; i++ {
		rand1 := rand.Int63n(2)
		var res int64
		if rand1 == 0 {
			res = 48 + rand.Int63n(10)
		} else {
			res = 97 + rand.Int63n(26)
		}
		character := fmt.Sprintf("%c", res)
		storid += character
	}
	return uniqId
}

冲突原因

  1. 计算机中的rand的随机都是伪随机, 只是从一张很大的随机整数表中按顺序输出"随机值", 只要seed一样, 多次执行rand的随机结果就一样.
  2. 因为服务启动时, 使用了unix时间戳作为rand的seed,当使用k8s启用多个pod实例时, 极易发生冲突.
func init() {
	rand.Seed(time.Now().Unix())
}

解决方法

  1. 使用纳秒数作为seed.
func init() {
	rand.Seed(time.Now().UnixNano())
}
  1. 使用上述纳秒数做36进制转换的方案

附: 哈希冲突的计算方式

生日悖论适用于哈希冲突, 即哈希冲突发生的几率往往比我们直观感受上更高.
一个60人的班级里, 有两个同学生日为同一天的概率已经达到了99%.

可参考: 从生日悖论谈哈希碰撞

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值