diff --git a/go.mod b/go.mod index cc08494..068250c 100644 --- a/go.mod +++ b/go.mod @@ -38,6 +38,7 @@ require ( github.com/aliyun/alibaba-cloud-sdk-go v1.61.18 // indirect github.com/andybalholm/brotli v1.1.1 // indirect github.com/buger/jsonparser v1.1.1 // indirect + github.com/bwmarrin/snowflake v0.3.0 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/emirpasic/gods v1.12.0 // indirect @@ -61,7 +62,7 @@ require ( github.com/jinzhu/now v1.1.5 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/klauspost/compress v1.17.11 // indirect + github.com/klauspost/compress v1.18.0 // indirect github.com/konsorten/go-windows-terminal-sequences v1.0.1 // indirect github.com/kr/text v0.2.0 // indirect github.com/leodido/go-urn v1.4.0 // indirect diff --git a/go.sum b/go.sum index 13f773a..f707060 100644 --- a/go.sum +++ b/go.sum @@ -24,6 +24,8 @@ github.com/bsm/gomega v1.26.0 h1:LhQm+AFcgV2M0WyKroMASzAzCAJVpAxQXv4SaI9a69Y= github.com/bsm/gomega v1.26.0/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0= github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs= github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= +github.com/bwmarrin/snowflake v0.3.0 h1:xm67bEhkKh6ij1790JB83OujPR5CzNe8QuQqAgISZN0= +github.com/bwmarrin/snowflake v0.3.0/go.mod h1:NdZxfVWX+oR6y2K0o6qAYv6gIOP9rjG0/E9WsDpxqwE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= @@ -163,6 +165,8 @@ github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfV github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc= github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= +github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= +github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= diff --git a/internal/biz/mixrepos/generate.go b/internal/biz/mixrepos/generate.go index edd03a2..c6d6a1f 100644 --- a/internal/biz/mixrepos/generate.go +++ b/internal/biz/mixrepos/generate.go @@ -4,7 +4,6 @@ import "context" // GenerateMixRepo interface type GenerateMixRepo interface { - // GeneratorString 生成字符串 GeneratorString(ctx context.Context, workId int) (string, error) GeneratorNumber(ctx context.Context, workId int) (uint64, error) } diff --git a/internal/data/mixrepoimpl/generate.go b/internal/data/mixrepoimpl/generate.go index 0484919..c4c0657 100644 --- a/internal/data/mixrepoimpl/generate.go +++ b/internal/data/mixrepoimpl/generate.go @@ -2,9 +2,10 @@ package mixrepoimpl import ( "context" + "github.com/bwmarrin/snowflake" "hash/fnv" "math" - "strconv" + "os" "voucher/internal/biz/mixrepos" "voucher/internal/data" "voucher/internal/pkg/uid" @@ -12,38 +13,64 @@ import ( type GenerateRepoImpl struct { rdb *data.Rdb + + node *snowflake.Node } -func NewGenerateMixRepoImpl(rdb *data.Rdb) mixrepos.GenerateMixRepo { - return &GenerateRepoImpl{rdb: rdb} +func NewGenerateMixRepoImpl(rdb *data.Rdb) (mixrepos.GenerateMixRepo, error) { + + g := &GenerateRepoImpl{rdb: rdb} + + name, err := os.Hostname() + if err != nil { + return nil, err + } + serverId := g.hashMod(name) + + node, err := snowflake.NewNode(int64(serverId)) + if err != nil { + return nil, err + } + + g.node = node + + return g, nil } // GeneratorString 生成字符串 -func (s *GenerateRepoImpl) GeneratorString(ctx context.Context, workId int) (string, error) { - serverIdStr := uid.GetAppId(ctx) - serverId := s.hashMod(serverIdStr) - number, err := uid.NewSignGenerator(s.rdb.Rdb).SetWorkerID(workId).SetServerID(serverId).GetNumber() - if err != nil { - return "", err - } - return strconv.FormatUint(number, 10), nil +func (s *GenerateRepoImpl) GeneratorString(_ context.Context, workId int) (string, error) { + + return s.node.Generate().String(), nil + + //serverIdStr := uid.GetAppId(ctx) + //serverId := s.hashMod(serverIdStr) + // + //number, err := uid.NewSignGenerator(s.rdb.Rdb).SetWorkerID(workId).SetServerID(serverId).GetNumber() + //if err != nil { + // return "", err + //} + // + //return strconv.FormatUint(number, 10), nil } // GeneratorNumber 生成unit64 func (s *GenerateRepoImpl) GeneratorNumber(ctx context.Context, workId int) (uint64, error) { serverIdStr := uid.GetAppId(ctx) serverId := s.hashMod(serverIdStr) + number, err := uid.NewSignGenerator(s.rdb.Rdb).SetWorkerID(workId).SetServerID(serverId).GetNumber() if err != nil { return 0, err } + return number, nil } // hashMod hash mod func (s *GenerateRepoImpl) hashMod(hashStr string) int { hash := fnv.New32a() - hash.Write([]byte(hashStr)) + _, _ = hash.Write([]byte(hashStr)) + hashValue := hash.Sum32() return int(math.Mod(float64(hashValue), 32)) } diff --git a/internal/pkg/uid/generator.go b/internal/pkg/uid/generator.go index 3af19b1..9757892 100644 --- a/internal/pkg/uid/generator.go +++ b/internal/pkg/uid/generator.go @@ -4,15 +4,19 @@ import ( "context" "fmt" "math" + "os" "strconv" + "sync/atomic" "time" "github.com/redis/go-redis/v9" ) const ( - Order = 1 // Order - OrderWechat = 2 // OrderWechat + Order = 1 +) + +const ( BitsFull = 64 // BitsPre = 1 // 固定 BitsTime = 41 // 毫秒时间戳 可以最多支持69年 @@ -38,6 +42,7 @@ func (sg *SignGenerator) GetNumber() (uint64, error) { if sg.ServerID < 0 || sg.ServerID > 31 { return 0, fmt.Errorf("serverID is lost") } + if sg.WorkerID < 0 || sg.WorkerID > 31 { return 0, fmt.Errorf("workerID is lost") } @@ -131,3 +136,27 @@ func (sg *SignGenerator) ReverseNumber(number uint64) map[string]interface{} { return uuidItem } + +var num int64 + +func GenerateNo() string { + t := time.Now() + s := t.Format("20060102150405") + m := t.UnixNano()/1e6 - t.UnixNano()/1e9*1e3 + ms := sup(m, 3) + p := os.Getpid() % 1000 + ps := sup(int64(p), 3) + i := atomic.AddInt64(&num, 1) + r := i % 10000 + rs := sup(r, 4) + n := fmt.Sprintf("%s%s%s%s", s, ms, ps, rs) + return n +} + +func sup(i int64, n int) string { + m := fmt.Sprintf("%d", i) + for len(m) < n { + m = fmt.Sprintf("0%s", m) + } + return m +} diff --git a/internal/pkg/uid/generator_test.go b/internal/pkg/uid/generator_test.go index b963752..fd0375f 100644 --- a/internal/pkg/uid/generator_test.go +++ b/internal/pkg/uid/generator_test.go @@ -1,6 +1,13 @@ package uid import ( + "context" + "fmt" + "github.com/bwmarrin/snowflake" + "hash/fnv" + "math" + "os" + "sync" "testing" "github.com/redis/go-redis/v9" @@ -8,15 +15,119 @@ import ( func TestSignGenerator_GetNumber(t *testing.T) { rdb := redis.NewClient(&redis.Options{ - Addr: "", - Password: "", - DB: 0, + Addr: "47.97.27.195:6379", + Password: "lansexiongdi@666", + DB: 15, }) + number, err := NewSignGenerator(rdb).SetWorkerID(1).SetServerID(2).GetNumber() - t.Log(number, err) + if err != nil { + t.Error(err) + return + } + + t.Log(number) +} + +func TestSignGenerator_Num(t *testing.T) { + rdb := redis.NewClient(&redis.Options{ + Addr: "47.97.27.195:6379", + Password: "lansexiongdi@666", + DB: 15, + }) + + var ids sync.Map + var wg sync.WaitGroup + const concurrency = 2000 + wg.Add(concurrency) + for i := 0; i < concurrency; i++ { + go func() { + defer wg.Done() + id, err := NewSignGenerator(rdb).SetWorkerID(1).SetServerID(2).GetNumber() + if err != nil { + t.Error(err) + return + } + if _, exists := ids.LoadOrStore(id, true); exists { + t.Errorf("duplicate ID generated") + } + }() + } + wg.Wait() } func TestSignGenerator_ReverseNumber(t *testing.T) { reverseNumber := NewSignGenerator(nil).ReverseNumber(556081583078248449) t.Log(reverseNumber) } + +func Test_GenerateNo(t *testing.T) { + //no := GenerateNo() + // + //t.Log(len(no)) + //t.Log(no) + + p := os.Getpid() + + t.Log(p) + t.Log(p % 1000) + + //uid := uuid.New().String() + //t.Log(len(uid)) + //t.Log(uid) + + ctx := context.Background() + serverIdStr := GetAppId(ctx) + + t.Log(serverIdStr) + t.Log(hashMod(serverIdStr)) + + node, err := snowflake.NewNode(1023) + if err != nil { + t.Error(err) + return + } + + nid := node.Generate().String() + + t.Log(len(nid)) + t.Log(nid) +} + +func hashMod(hashStr string) int { + hash := fnv.New32a() + _, _ = hash.Write([]byte(hashStr)) + + hashValue := hash.Sum32() + return int(math.Mod(float64(hashValue), 32)) +} + +func GenerateSnowflakeID(nodeID int64) (string, error) { + if nodeID < 0 || nodeID > 1023 { + return "", fmt.Errorf("invalid node ID: %d", nodeID) + } + node, err := snowflake.NewNode(nodeID) + if err != nil { + return "", err + } + return node.Generate().String(), nil +} + +func TestGenerateID(t *testing.T) { + nodeID := int64(1) // 确保唯一 + node, _ := snowflake.NewNode(nodeID) + var ids sync.Map + var wg sync.WaitGroup + const concurrency = 2000 + wg.Add(concurrency) + for i := 0; i < concurrency; i++ { + go func() { + defer wg.Done() + id := node.Generate().String() + if _, exists := ids.LoadOrStore(id, true); exists { + t.Errorf("duplicate ID generated") + } + }() + } + wg.Wait() +} diff --git a/internal/server/wechat_notify_consumer.go b/internal/server/wechat_notify_consumer.go index 26d63c7..0f2fe40 100644 --- a/internal/server/wechat_notify_consumer.go +++ b/internal/server/wechat_notify_consumer.go @@ -67,7 +67,7 @@ func (w *WechatNotifyConsumer) Start(ctx context.Context) error { } // consumeMessages 消费消息的具体逻辑 -func (w *WechatNotifyConsumer) consumeMessages(ctx context.Context, mqConsumer mqhttpsdk.MQConsumer, tag string) { +func (w *WechatNotifyConsumer) consumeMessages2(ctx context.Context, mqConsumer mqhttpsdk.MQConsumer, tag string) { for { endChan := make(chan int) respChan := make(chan mqhttpsdk.ConsumeMessageResponse)