当前位置: 首页 > 工具软件 > go-snowflake > 使用案例 >

Golang - 分布式ID和snowflake雪花算法

傅阿苏
2023-12-01
一、雪花算法snowflake
package snowflake

import (
	"fmt"
	"sync"
	"time"
)

// 算法模式如下:
// |  1   |    41     |    10    |    12    |
// | sign | timestamp | workerId | sequence |

const (
	baseTime    int64 = 1514736000000 // 2018-01-01 00:00:00为时间基
	sequenceMax int64 = 0xfff         // 最大的序号
	workerMaxID int64 = 0x3ff         // 最大的业务ID
)

type SnowFlake struct {
	workerId int64 // 当前的业务ID
	sequence int64 // 当前毫秒时刻ID的序号
	lastTime int64 // 最后记录的时间戳
	mutex    sync.Mutex
}

func NewSnowFlake(wID int64) (*SnowFlake, error) {
	if wID > workerMaxID || wID < 0 {
		return nil, fmt.Errorf("WorkerId %d invalid.", wID)
	}
	return &SnowFlake{workerId: wID}, nil
}

func (s *SnowFlake) NextID() (int64, error) {
	s.mutex.Lock()
	defer s.mutex.Unlock()

	nowTime := time.Now().UnixNano() / 1e6

	if nowTime < s.lastTime {
		return 0, fmt.Errorf("Clock is moving backwards. Rejecting requests until %d.", s.lastTime)
	}

	if nowTime == s.lastTime {
		s.sequence = (s.sequence + 1) & sequenceMax

		if s.sequence == 0 {
			for nowTime <= s.lastTime {
				nowTime = time.Now().UnixNano() / 1e6
			}
		}
	} else {
		s.sequence = 0
	}

	s.lastTime = nowTime

	return (nowTime-baseTime)<<22 | s.workerId<<12 | s.sequence, nil
}

关键是解决workerId的重复问题,推荐使用redis在应用启动时锁定一个1024个workerId中的一个,设置好过期时间,并在过期之前激活,循环往复即可。

 类似资料: