七叶笔记 » golang编程 » golang+win10+lua+docker+redis+AB测试,实现商品秒杀代码实现

golang+win10+lua+docker+redis+AB测试,实现商品秒杀代码实现

上一篇文章用php原生代码实现了秒杀功能,本文用golang来实现秒杀;

运行环境:win10,docker+redis+lua最后AB压力测试;

共同点: 用户id都是10000-1000000之间的随机数,库存stock都是1000,AB参数 -n 10000 -c 200两者相同

不同点: 本项目演示中,PHP没有采用框架,go采用gin实现http服务。

先看看下之前php的压力测试结果,为了严谨一点,我执行三次取平均值。三次测试QPS平均值 314

PHP实现

PHP实现

PHP实现

php的秒杀实现请参考我的历史文章 :

按照入门级的理解,go用了框架,应该更繁重点,但是最后的测试结果让人吃惊:

那就是go的QPS将近是PHP的 3.4 倍,所以go不愧是面向工资编程语言,来看结果:

QPS平均值 1068.7

go实现

go实现

go实现

代码奉上,环境搭建此处就不累赘了。

 package main

import (
   "context"
   "fmt"
   "github.com/gin-gonic/gin"
   "github.com/go-redis/redis"
   "math/rand"
   "net/http"
   "strconv"
   "time"
)

var redisDb *redis.Client
var luaScript = `
         local userId   = KEYS[1];
         local goodKey  = KEYS[2];
         local stock    = KEYS[3];
         local userExit = redis.call("sismember",goodKey,userId);
            if tonumber(userExit) == 1 then
                return 2;
            end 
            local num = redis.call("get",stock);
            if tonumber(num) <= 0 then
                return 3;
            else
                redis.call("decr",stock);
                redis.call("sadd",goodKey,userId);
            end 
            return 1;`
var evalSha string

func init() {
   initRedisClient()
}

func initRedisClient() {
   redisDb = redis.NewClient(&redis.Options{
      Addr:     "localhost:6379",
      Password: "",
      DB:       0,
   })

   var err error
   evalSha, err = redisDb.ScriptLoad(context.Background(), luaScript).Result()
   if err != nil {
      panic(err)
   }
}

func main() {
   // 1.创建路由
   r := gin.Default()
   // 2.绑定路由规则,执行的函数
   // gin.Context,封装了request和response
   r.GET("/kill", func(c *gin.Context) {
      kill()
      c.String(http.StatusOK, "秒杀成功")
   })

   // 3.监听端口,默认在8080
   // Run("里面不指定端口号默认为8080")
   r.Run(":8000")

}

func kill() {
   err := redisDb.SetNX(context.Background(), "go_stock", 1000, 0).Err()
   if err != nil {
      panic(err)
   }
   //time.Now().Unix()秒 ab测试产生了很多一样的用户
   rand.Seed(time.Now().UnixNano()) //纳秒
   id := rand.Intn(990001) + 10000  //10000-1000000的随机数
   userId := strconv.Itoa(id)       //整数转字符,如果直接int(id)会出现意想不到的结果
   res, err2 := redisDb.EvalSha(context.Background(), evalSha, []string{userId, "go_user_ids", "go_stock"}).Result()
   if err2 != nil {
      panic(err2)
   }
   if res.(int64) == int64(1) {
      fmt.Println("秒杀成功")
   } else if res.(int64) == int64(2) {
      fmt.Println("请勿重复操作")
   } else {
      fmt.Println("暂无库存了")
   }
}
  

不妥之处请指正。

相关文章