Browse Source

id生成算法细微调整

marion 5 years ago
parent
commit
66c3c824a5
2 changed files with 71 additions and 14 deletions
  1. 53 0
      utils/kengen_test.go
  2. 18 14
      utils/keygen.go

+ 53 - 0
utils/kengen_test.go

@@ -0,0 +1,53 @@
+package utils
+
+import (
+	"fmt"
+	"sync"
+	"testing"
+	"time"
+)
+
+func TestNextID(t *testing.T) {
+	idSize := 100000
+	var wg sync.WaitGroup
+	wg.Add(idSize)
+	m := make(map[Long]int)
+
+	startTime := time.Now().UnixNano()
+	q := make(chan Long, 0)
+	go func(m map[Long]int) {
+		for {
+			select {
+			case id := <-q:
+				if _, ok := m[id]; ok {
+					m[id]++
+				} else {
+					m[id] = 1
+				}
+				wg.Done()
+			}
+		}
+	}(m)
+
+	for i := 0; i < idSize; i++ {
+		go func() {
+			q <- NextId()
+		}()
+	}
+
+	wg.Wait()
+	endTime := time.Now().UnixNano()
+	usedTime := time.Duration(endTime - startTime)
+	fmt.Printf("Id size: %d\nTotal seconds:%d\nAvg nanos per id:%d\n", len(m), usedTime/time.Second, int64(usedTime)/int64(idSize))
+
+	badSize := 0
+	for _, v := range m {
+		if v > 1 {
+			badSize++
+		}
+	}
+
+	if badSize > 0 {
+		t.Fail()
+	}
+}

+ 18 - 14
utils/keygen.go

@@ -32,12 +32,16 @@ func SingletonSnowflakeKeyGen() *Snowflake {
 
 /*----------------------------------------------------SnowflakeKeyGen------------------------------------------------*/
 
+// Snowflake程序id生成器
+// 源于Twitter的Snowflake算法
+// 但由于原版算法对应的分布式层级结构太简单,所以目前的算法实际是Sony对Snowflake算法的改进版本的Sonyflake算法
+// Sonyflake算法原版可参考github中的开源项目,当前算法有进一步细微调整
 const (
-	SnowflakeTimeUnit  = 1e7 // 时间单位,一纳秒的多少倍,1e6 = 一毫秒,1e7 = 百分之一秒,1e8 = 十分之一秒
-	BitLenSequence     = 8   // 序列号的个数最多256个(0-255),即每单位时间并发数,如时间单位是1e7,则单实例qps = 25600
-	BitLenDataCenterId = 3   // 数据中心个数最多8个(0-7),即同一个环境(生产、预发布、测试等)的数据中心(假设一个机房相同数据域的应用服务器集群只有一个,则数据中心数等于机房数)最多有8个
-	BitLenMachineId    = 16  // 同一个数据中心下最多65536个应用实例(0-65535),默认是根据实例ip后两段算实例id(k8s环境动态创建Pod,也建议用此方式),所以需要预留255 * 255这么多
-	BitLenTime         = 36  // 时间戳之差最大 = 2的36次方 * 时间单位 / 1e9 秒,目前的设计最多可以用21.79年就需要更新开始时间(随之还需要归档旧数据和更新次新数据id)
+	SnowflakeTimeUnit  = 1e7     // 时间单位,一纳秒的多少倍,1e6 = 一毫秒,1e7 = 百分之一秒,1e8 = 十分之一秒
+	BitLenSequence     = 8       // 序列号的个数最多256个(0-255),即每单位时间并发数,如时间单位是1e7,则单实例qps = 25600
+	BitLenDataCenterId = 3       // 数据中心个数最多8个(0-7),即同一个环境(生产、预发布、测试等)的数据中心(假设一个机房相同数据域的应用服务器集群只有一个,则数据中心数等于机房数)最多有8个
+	BitLenMachineId    = 16      // 同一个数据中心下最多65536个应用实例(0-65535),默认是根据实例ip后两段算实例id(k8s环境动态创建Pod,也建议用此方式),所以需要预留255 * 255这么多
+	BitLenTime         = 1 << 36 // 时间戳之差最大 = 2的36次方 * 时间单位 / 1e9 秒,目前的设计最多可以用21.79年就需要更新开始时间(随之还需要归档旧数据和更新次新数据id)
 	// 总共63位,不超过bit64
 )
 
@@ -66,7 +70,7 @@ func NewSnowflake(st SnowflakeSettings) *Snowflake {
 		return nil
 	}
 	if st.StartTime.IsZero() {
-		sf.startTime = toSnowflakeTime(time.Date(2018, 9, 26, 0, 0, 0, 0, time.UTC)) //没有配置默认使用此时间
+		sf.startTime = toSnowflakeTime(time.Date(2019, 7, 1, 0, 0, 0, 0, time.UTC)) //没有配置默认使用此时间
 	} else {
 		sf.startTime = toSnowflakeTime(st.StartTime)
 	}
@@ -106,7 +110,7 @@ func (sf *Snowflake) NextId() (uint64, error) {
 	sf.mutex.Lock()
 	defer sf.mutex.Unlock()
 
-	current := currentElapsedTime(sf.startTime)
+	current := getCurrentElapsedTime(sf.startTime)
 	if sf.elapsedTime < current {
 		sf.elapsedTime = current
 		sf.sequence = 0
@@ -115,7 +119,7 @@ func (sf *Snowflake) NextId() (uint64, error) {
 		if sf.sequence == 0 {
 			sf.elapsedTime++
 			overtime := sf.elapsedTime - current
-			time.Sleep(sleepTime(overtime))
+			time.Sleep(getSleepTime(overtime))
 		}
 	}
 
@@ -126,17 +130,17 @@ func toSnowflakeTime(t time.Time) int64 {
 	return t.UTC().UnixNano() / SnowflakeTimeUnit
 }
 
-func currentElapsedTime(startTime int64) int64 {
+func getCurrentElapsedTime(startTime int64) int64 {
 	return toSnowflakeTime(time.Now()) - startTime
 }
 
-func sleepTime(overtime int64) time.Duration {
+func getSleepTime(overtime int64) time.Duration {
 	return time.Duration(overtime)*10*time.Millisecond -
 		time.Duration(time.Now().UTC().UnixNano()%SnowflakeTimeUnit)*time.Nanosecond
 }
 
 func (sf *Snowflake) toId() (uint64, error) {
-	if sf.elapsedTime >= 1<<BitLenTime {
+	if sf.elapsedTime >= BitLenTime {
 		return 0, errors.New("over the time limit")
 	}
 
@@ -146,7 +150,7 @@ func (sf *Snowflake) toId() (uint64, error) {
 		uint64(sf.machineId), nil
 }
 
-func privateIPv4() (net.IP, error) {
+func PrivateIPv4() (net.IP, error) {
 	as, err := net.InterfaceAddrs()
 	if err != nil {
 		return nil, err
@@ -167,12 +171,12 @@ func privateIPv4() (net.IP, error) {
 }
 
 func isPrivateIPv4(ip net.IP) bool {
-	return ip != nil &&
+	return ip != nil && len(ip) > 3 &&
 		(ip[0] == 10 || ip[0] == 172 && (ip[1] >= 16 && ip[1] < 32) || ip[0] == 192 && ip[1] == 168)
 }
 
 func GetPrivateIPv4Id() (uint16, error) {
-	ip, err := privateIPv4()
+	ip, err := PrivateIPv4()
 	if err != nil {
 		return 0, err
 	}