From 99821c85bc315c386c6d00e636735881da55e356 Mon Sep 17 00:00:00 2001 From: seelly Date: Tue, 17 Sep 2024 11:22:48 +0800 Subject: [PATCH] feature(voucher):redsync lock --- biz/dal/redis/init.go | 9 +++- biz/middleware/interceptor/refresh_token.go | 20 ++++----- biz/pkg/constants/constants.go | 7 +-- biz/service/voucher/seckill_voucher.go | 49 ++++++++++++++++----- go.mod | 5 ++- go.sum | 9 ++++ main.go | 5 +++ 7 files changed, 78 insertions(+), 26 deletions(-) diff --git a/biz/dal/redis/init.go b/biz/dal/redis/init.go index 33814a2..53e6b86 100644 --- a/biz/dal/redis/init.go +++ b/biz/dal/redis/init.go @@ -5,13 +5,18 @@ import ( "encoding/json" "errors" "github.com/go-redis/redis/v8" + "github.com/go-redsync/redsync/v4" + "github.com/go-redsync/redsync/v4/redis/goredis/v8" "time" "xzdp/biz/model/cache" "xzdp/biz/pkg/constants" "xzdp/conf" ) -var RedisClient *redis.Client +var ( + RedisClient *redis.Client + RedsyncClient *redsync.Redsync +) type ArgsFunc func(args ...interface{}) (interface{}, error) @@ -23,6 +28,8 @@ func Init() { if err := RedisClient.Ping(context.Background()).Err(); err != nil { panic(err) } + pool := goredis.NewPool(RedisClient) + RedsyncClient = redsync.New(pool) } func SetString(ctx context.Context, key string, value interface{}, duration time.Duration) error { diff --git a/biz/middleware/interceptor/refresh_token.go b/biz/middleware/interceptor/refresh_token.go index 7639c0c..8779f4b 100644 --- a/biz/middleware/interceptor/refresh_token.go +++ b/biz/middleware/interceptor/refresh_token.go @@ -14,16 +14,16 @@ import ( func CheckToken(ctx context.Context, c *app.RequestContext) { hlog.CtxInfof(ctx, "check token interceptor:%+v", conf.GetEnv()) - if conf.GetEnv() != "online" { - userdto := model.UserDTO{ - ID: 2, - NickName: "法外狂徒张三", - Icon: "https://img2.baidu.com/it/u=194756667,2850459164&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500", - } - ctx = utils.SaveUser(ctx, &userdto) - c.Next(ctx) - return - } + //if conf.GetEnv() != "online" { + // userdto := model.UserDTO{ + // ID: 2, + // NickName: "法外狂徒张三", + // Icon: "https://img2.baidu.com/it/u=194756667,2850459164&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500", + // } + // ctx = utils.SaveUser(ctx, &userdto) + // c.Next(ctx) + // return + //} token := c.GetHeader("authorization") if token == nil { c.Next(ctx) diff --git a/biz/pkg/constants/constants.go b/biz/pkg/constants/constants.go index 32f5cc7..9b931b9 100644 --- a/biz/pkg/constants/constants.go +++ b/biz/pkg/constants/constants.go @@ -45,7 +45,8 @@ const ( // voucher 相关 const ( - BEGIN_TIMESTAMP = 1725120000 - ICRID_KEY = "id:" - COUNT_BIT = 32 + BEGIN_TIMESTAMP = 1725120000 + ICRID_KEY = "id:" + COUNT_BIT = 32 + VOUCHER_LOCK_KEY = "voucher:lock:" ) diff --git a/biz/service/voucher/seckill_voucher.go b/biz/service/voucher/seckill_voucher.go index bcdf333..ff17274 100644 --- a/biz/service/voucher/seckill_voucher.go +++ b/biz/service/voucher/seckill_voucher.go @@ -3,13 +3,14 @@ package voucher import ( "context" "errors" + "fmt" "github.com/cloudwego/hertz/pkg/app" - "strconv" "sync" "time" "xzdp/biz/dal/mysql" "xzdp/biz/dal/redis" voucherModel "xzdp/biz/model/voucher" + "xzdp/biz/pkg/constants" "xzdp/biz/utils" ) @@ -18,7 +19,9 @@ type SeckillVoucherService struct { Context context.Context } -var mu sync.Mutex +var ( + wg sync.WaitGroup +) func NewSeckillVoucherService(Context context.Context, RequestContext *app.RequestContext) *SeckillVoucherService { return &SeckillVoucherService{RequestContext: RequestContext, Context: Context} @@ -51,16 +54,40 @@ func (h *SeckillVoucherService) Run(req *int64) (resp *int64, err error) { return nil, errors.New("已抢空") } user := utils.GetUser(h.Context) - uuid, _ := utils.RandomUUID() - sec := time.Now().Unix() - lockValue := uuid + strconv.FormatInt(sec, 10) //由于value的全局唯一性,这里用uuid+时间戳,如需要更高精度应考虑雪花算法活其他方法生成 - lock := redis.NewLock(h.Context, user.NickName, lockValue, 10) - ok := lock.TryLock() - if !ok { - return nil, errors.New("重复下单") + //uuid, _ := utils.RandomUUID() + //sec := time.Now().Unix() + //lockValue := uuid + strconv.FormatInt(sec, 10) //由于value的全局唯一性,这里用uuid+时间戳,如需要更高精度应考虑雪花算法活其他方法生成 + //lock := redis.NewLock(h.Context, user.NickName, lockValue, 10) + //ok := lock.TryLock() + mutex := redis.RedsyncClient.NewMutex(fmt.Sprintf("%s:%s", constants.VOUCHER_LOCK_KEY, user.NickName)) + err = mutex.Lock() + if err != nil { + return nil, errors.New("获取分布式锁失败") + } + // 使用通道来接收 createOrder 的结果 + resultCh := make(chan *int64, 1) + errCh := make(chan error, 1) + wg.Add(1) + go func() { + defer wg.Done() + order, err := h.createOrder(*req) + if err != nil { + errCh <- err + } else { + resultCh <- order + } + }() + if ok, err := mutex.Unlock(); !ok || err != nil { + return nil, err + } + select { + case order := <-resultCh: + return order, nil + case err := <-errCh: + return nil, err + case <-h.Context.Done(): + return nil, errors.New("请求超时") } - defer lock.UnLock(lockValue) - return h.createOrder(*req) } func (h *SeckillVoucherService) createOrder(voucherId int64) (resp *int64, err error) { diff --git a/go.mod b/go.mod index d8f412d..93c39d3 100755 --- a/go.mod +++ b/go.mod @@ -22,15 +22,18 @@ require ( github.com/bytedance/gopkg v0.0.0-20240507064146-197ded923ae3 // indirect github.com/bytedance/sonic v1.11.9 // indirect github.com/bytedance/sonic/loader v0.1.1 // indirect - github.com/cespare/xxhash/v2 v2.1.2 // indirect + github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/cloudwego/base64x v0.1.4 // indirect github.com/cloudwego/iasm v0.2.0 // indirect github.com/cloudwego/netpoll v0.6.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/fsnotify/fsnotify v1.5.4 // indirect + github.com/go-redsync/redsync/v4 v4.13.0 // indirect github.com/go-sql-driver/mysql v1.7.0 // indirect github.com/golang/protobuf v1.5.0 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/henrylee2cn/ameda v1.4.10 // indirect github.com/henrylee2cn/goutil v0.0.0-20210127050712-89660552f6f8 // indirect github.com/jinzhu/inflection v1.0.0 // indirect diff --git a/go.sum b/go.sum index a3c6588..a65be5c 100644 --- a/go.sum +++ b/go.sum @@ -15,6 +15,8 @@ github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3z github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y= @@ -36,6 +38,8 @@ github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwV github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= +github.com/go-redsync/redsync/v4 v4.13.0 h1:49X6GJfnbLGaIpBBREM/zA4uIMDXKAh1NDkvQ1EkZKA= +github.com/go-redsync/redsync/v4 v4.13.0/go.mod h1:HMW4Q224GZQz6x1Xc7040Yfgacukdzu7ifTDAKiyErQ= github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc= github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -45,6 +49,11 @@ github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/henrylee2cn/ameda v1.4.8/go.mod h1:liZulR8DgHxdK+MEwvZIylGnmcjzQ6N6f2PlWe7nEO4= github.com/henrylee2cn/ameda v1.4.10 h1:JdvI2Ekq7tapdPsuhrc4CaFiqw6QXFvZIULWJgQyCAk= github.com/henrylee2cn/ameda v1.4.10/go.mod h1:liZulR8DgHxdK+MEwvZIylGnmcjzQ6N6f2PlWe7nEO4= diff --git a/main.go b/main.go index 95c2fe3..c1ce90b 100755 --- a/main.go +++ b/main.go @@ -12,9 +12,14 @@ import ( "github.com/cloudwego/hertz/pkg/app" "github.com/cloudwego/hertz/pkg/app/server" "github.com/cloudwego/hertz/pkg/common/hlog" + "net/http" + _ "net/http/pprof" // 导入 pprof HTTP handler ) func main() { + go func() { + _ = http.ListenAndServe(":6060", nil) + }() h := server.Default(server.WithHostPorts(conf.GetConf().Hertz.Address)) h.Use(interceptor.CheckToken) h.Use(interceptor.Cors)