Skip to content

Commit

Permalink
代码优化,并发且号段用完时只申请一次号段,其它请求只申请自己使用号码
Browse files Browse the repository at this point in the history
  • Loading branch information
nianxy committed Apr 7, 2023
1 parent c1b06ff commit bf6c42e
Showing 1 changed file with 115 additions and 34 deletions.
149 changes: 115 additions & 34 deletions generator/day_unique_id.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,16 @@ import (
"errors"
"fmt"
"math/rand"
"net"
"strings"
"sync"
"sync/atomic"
"time"
)

const (
constIdFormat = "%s-%s%s"
constIncrementStep = 1000
constIncrementStep = 10000
LeastAvailableIdNum = 50 //当剩余可用id数小于这个数时,申请新号段,建议小于步长较多
)

Expand Down Expand Up @@ -39,7 +41,7 @@ type RangeUsageInfoStruct struct {
prefix string
bizType string
appName string
port int //用来区别服务不同实例,降级随机生成方案避免不同实例重复
hostKey string //用来区别服务不同实例,降级随机生成方案避免不同实例重复
rander *rand.Rand
}

Expand Down Expand Up @@ -68,24 +70,23 @@ var keyMap = map[byte]byte{
func New(caller NumbersReqFunc, logs LogInterface, prefix string) *RangeUsageInfoStruct {
source := rand.NewSource(time.Now().UnixNano())
rander := rand.New(source)
hostKey := GetHostKey()
return &RangeUsageInfoStruct{
reqNumbersCaller: caller,
logs: logs,
prefix: prefix,
bizType: prefix,
rander: rander,
hostKey: hostKey,
}
}

func (usage *RangeUsageInfoStruct) GenerateIdWithAppendPrefix(applicationName string, port int, appendPrefix string) (string, error) {
func (usage *RangeUsageInfoStruct) GenerateIdWithAppendPrefix(applicationName string, appendPrefix string) (string, error) {

if usage.appName == "" {
//首次调用设置,后面不再变更,避免同一个实例被应用在不同业务场景中
usage.appName = applicationName
}
if usage.port == 0 {
usage.port = port
}

currentTime := time.Now()
var currentId int64
Expand All @@ -98,49 +99,65 @@ func (usage *RangeUsageInfoStruct) GenerateIdWithAppendPrefix(applicationName st
Step: constIncrementStep,
}

var finalPrefix = usage.prefix
if appendPrefix != "" {
finalPrefix = usage.prefix + "-" + appendPrefix
}

usage.logs.Debug("{} {} {} 请求新的id, 当前号段: {} {} {}", usage.appName, usage.bizType, usage.prefix, usage.applyDate, usage.currentMaxId, usage.currentRangeEnd)

if currentTime.Day() != usage.applyDate.Day() { //新的一天或服务重启了,获取新的号段
usage.logs.Debug("{} {} {} 新的一天,取新号段", usage.appName, usage.bizType, usage.prefix)
resp, bSuccess := usage.getNewIdRange(&req)
if !bSuccess {
usage.logs.Debug("{} {} {} 当天初始号段已经在获取中,不再重复请求", usage.appName, usage.bizType, usage.prefix)
resp, bUseOnce, err := usage.getNewIdRange(&req)
if err != nil {
usage.logs.Debug("{} {} {} 请求号段失败 {}", usage.appName, usage.bizType, usage.prefix, err.Error())
//return "", errcode.IdGenFailed.Error()
} else {
currentId = usage.replaceRange(resp.RangeStart, resp.RangeEnd, currentTime)
usage.logs.Debug("{} {} {} 号段更替,新号段 {} {} {}", usage.appName, usage.bizType, usage.prefix, usage.currentMaxId, usage.currentRangeEnd, usage.applyDate)
if bUseOnce {
currentId = resp.RangeStart
return usage.GenerateKey(currentId, finalPrefix, todayFormat)
} else {
currentId = usage.replaceRange(resp.RangeStart, resp.RangeEnd, currentTime)
usage.logs.Debug("{} {} {} 号段更替,新号段 {} {} {}", usage.appName, usage.bizType, usage.prefix, usage.currentMaxId, usage.currentRangeEnd, usage.applyDate)
}
}
} else if usage.currentMaxId+LeastAvailableIdNum > usage.currentRangeEnd {
//号段即将用完,获取新号段
usage.logs.Debug("{} {} {} 当天号段用完了,重新申请", usage.appName, usage.bizType, usage.prefix)
resp, bSuccess := usage.getNewIdRange(&req)
if !bSuccess {
usage.logs.Debug("{} {} {} 当天初始号段已经在获取中,不再重复请求", usage.appName, usage.bizType, usage.prefix)
resp, bUseOnce, err := usage.getNewIdRange(&req)
if err != nil {
usage.logs.Error("{} {} {} 请求号段出错 {}", usage.appName, usage.bizType, usage.prefix, err.Error())
//return "", errcode.IdGenFailed.Error()
} else {
currentId = usage.replaceRange(resp.RangeStart, resp.RangeEnd, currentTime)
usage.logs.Debug("{} {} {} 号段更替,新号段 {} {} {}", usage.appName, usage.bizType, usage.prefix, usage.currentMaxId, usage.currentRangeEnd, usage.applyDate)
if bUseOnce {
currentId = resp.RangeStart
return usage.GenerateKey(currentId, finalPrefix, todayFormat)
} else {
currentId = usage.replaceRange(resp.RangeStart, resp.RangeEnd, currentTime)
usage.logs.Debug("{} {} {} 号段更替,新号段 {} {} {}", usage.appName, usage.bizType, usage.prefix, usage.currentMaxId, usage.currentRangeEnd, usage.applyDate)
}
}
} else {
//号段内递增
currentId = usage.incrementAndGet()
usage.logs.Debug("{} {} {} 使用已有号段获得的号码 {}", usage.appName, usage.bizType, usage.prefix, currentId)
}

var finalPrefix = usage.prefix
if appendPrefix != "" {
finalPrefix = usage.prefix + "-" + appendPrefix
}
if (currentId == 0) || (currentId > usage.currentRangeEnd) {
//号段获取失败
//当前号段资源已用完且还未请求到新号段(高并发下低概率),降级到随机生成方案
usage.logs.Warn("{} {} {} 获取号段失败或等待请求号段中,先降级到随机生成业务编号方案", usage.appName, usage.bizType, usage.prefix)
randSuffix := usage.randId(usage.port)
randSuffix := usage.randId(usage.hostKey)
randOrderId := fmt.Sprintf(constIdFormat, finalPrefix, todayFormat, randSuffix)
return randOrderId, nil
}

uniqueKey := fmt.Sprintf("%05d", currentId)
return usage.GenerateKey(currentId, finalPrefix, todayFormat)

}

func (usage *RangeUsageInfoStruct) GenerateKey(currentId int64, finalPrefix string, todayFormat string) (string, error) {
uniqueKey := fmt.Sprintf("%06d", currentId)

uniqueKeyLen := len(uniqueKey)

Expand All @@ -162,20 +179,61 @@ func (usage *RangeUsageInfoStruct) GenerateIdWithAppendPrefix(applicationName st
return orderId, nil
}

func (usage *RangeUsageInfoStruct) GenerateId(applicationName string, port int) (string, error) {
return usage.GenerateIdWithAppendPrefix(applicationName, port, "")
func (usage *RangeUsageInfoStruct) GenerateId(applicationName string) (string, error) {
return usage.GenerateIdWithAppendPrefix(applicationName, "")
}

func (usage *RangeUsageInfoStruct) randId(port int) string {
//
//func (usage *RangeUsageInfoStruct) UniqueIdByTime(port int, calcTime time.Time) string {
//
// dayStartTime := time.Date(calcTime.Year(), calcTime.Month(), calcTime.Day(), 0, 0, 0, 0, calcTime.Location())
//
// diffMs := calcTime.UnixMilli() - dayStartTime.UnixMilli()
//
// suffix := make([]byte, 0)
// suffix = append(suffix, 'Y')
//
// for ; port > 0; port = port / 26 {
// pos := port % 26
// pos += 'A'
// suffix = append(suffix, uint8(pos))
// }
// randSuffix := make([]byte, 0)
// diffMs = diffMs + 26
// for ; diffMs > 0; diffMs = diffMs / 26 {
// pos := diffMs % 26
// pos += 'A'
// randSuffix = append(randSuffix, uint8(pos))
// }
// length := len(randSuffix)
// if length < 8 {
// for i := 0; i < 8-length; i++ {
// randSuffix = append(randSuffix, 'A')
// }
// }
//
// suffix = append(suffix, randSuffix...)
// return string(suffix)
//}

func (usage *RangeUsageInfoStruct) randId(hostKey string) string {
num := usage.rander.Intn(10000000000)
suffix := make([]byte, 0)
suffix = append(suffix, 'Y')

for ; port > 0; port = port / 26 {
pos := port % 26
pos += 'A'
for k, ch := range hostKey {
if k == 3 {
break
}
pos := ch + 17
suffix = append(suffix, uint8(pos))
}

lenHostKey := len(hostKey)
for i := 0; i < 3-lenHostKey; i++ {
suffix = append(suffix, 'A')
}

randSuffix := make([]byte, 0)
for ; num > 0; num = num / 26 {
pos := num % 26
Expand Down Expand Up @@ -227,24 +285,47 @@ func (usage *RangeUsageInfoStruct) incrementAndGet() int64 {
return usage.currentMaxId
}

func (usage *RangeUsageInfoStruct) getNewIdRange(req *ApplyReq) (*NewRangeResp, bool) {
func (usage *RangeUsageInfoStruct) getNewIdRange(req *ApplyReq) (*NewRangeResp, bool, error) {

bUseOnce := false
var curCounter int32
curCounter = atomic.AddInt32(&(usage.gettingIdRangeCounter), 1)
defer atomic.AddInt32(&(usage.gettingIdRangeCounter), -1)
if curCounter > 1 { //已经有请求在进行了,不必再请求
usage.logs.Debug("已有号段申请进行中 {}", curCounter)
return nil, false
if curCounter > 2 { //已经有请求在进行了,只申请自用号码即可
usage.logs.Debug("只申请单次使用号段 {}", curCounter)
bUseOnce = true
req.Step = 1
}

//logs.Debug("执行号段申请 {}", curCounter)
resp, err := usage.reqNumbersCaller(req)
if err != nil {
usage.logs.Debug("号段申请失败 {} {}", err.Error(), curCounter)
return nil, false
return nil, bUseOnce, err
}

//logs.Debug("号段申请成功 {}", curCounter)
return resp, true
return resp, bUseOnce, nil

}

func GetHostKey() string {
addrs, err := net.InterfaceAddrs()
if err != nil {
return ""
}

for _, a := range addrs {
if ipnet, ok := a.(*net.IPNet); ok && ipnet.IP.IsGlobalUnicast() && ipnet.IP.To4() != nil {
if ipnet.IP.IsPrivate() {
ip := ipnet.IP.String()
ipF := strings.Split(ip, ".")
if len(ipF) < 4 {
continue
}
return ipF[3]
}
}
}
return ""
}

0 comments on commit bf6c42e

Please sign in to comment.