美文网首页
并发抢票

并发抢票

作者: 彳亍口巴 | 来源:发表于2022-12-25 14:44 被阅读0次
package main

import (
    "fmt"
    "net/http"

    "github.com/gin-gonic/gin"
)

// 高并发抢票服务

func main() {
    //startServer()
    fmt.Println("启动项目")
    r := RoutersInit()
    err := r.Run(":9090")
    if err != nil {
        panic(err)
    }
}

func startServer() {
    r := gin.Default()
    r.GET("/ping", func(c *gin.Context) {
        c.JSON(http.StatusOK, gin.H{
            "message": "pong",
        })
    })

    r.Run(":9090")
}

func RoutersInit() *gin.Engine {

    r := gin.New()

    c := r.Group("/index")
    {

        p := c.Group("/post")
        {
            p.GET("/", Buy)

        }
    }

    return r
}

package main

import (
    "github.com/garyburd/redigo/redis"
)

var constLuaScript = `
        local ticket_key = KEYS[1]
        local ticket_total_key = ARGV[1]
        local ticket_sold_key = ARGV[2]
        local ticket_total_nums = tonumber(redis.call('HGET', ticket_key, ticket_total_key))
        local ticket_sold_nums = tonumber(redis.call('HGET', ticket_key, ticket_sold_key))
        -- 查看是否还有余票,增加订单数量,返回结果值
       if(ticket_total_nums >= ticket_sold_nums) then
            return redis.call('HINCRBY', ticket_key, ticket_sold_key, 1)
        end
        return 0
`

var (
    redisPool *redis.Pool
)

func init() {
    redisPool = NewPool()
}

func NewPool() *redis.Pool {
    return &redis.Pool{
        MaxIdle:   10000,
        MaxActive: 12000, // max number of connections
        Dial: func() (redis.Conn, error) {
            //c, err := redis.Dial("tcp", "127.0.0.1:6379", redis.DialPassword("123456"))
            c, err := redis.Dial("tcp", "127.0.0.1:6379")
            if err != nil {
                panic(err.Error())
            }
            return c, err
        },
    }
}

// RemoteDeductionStock 远端统一扣库存
func RemoteDeductionStock(conn redis.Conn) bool {
    lua := redis.NewScript(1, constLuaScript)
    result, err := redis.Int(lua.Do(conn, "a", "total", "order"))
    if err != nil {
        return false
    }
    return result != 0
}

package main

import (
    "os"
    "strings"

    "github.com/gin-gonic/gin"
)

var done = make(chan struct{}, 1) // 控制并发,一次只能有一个请求通过
var localTicket = &LocalTicket{}

type LocalTicket struct {
    TotalTicket int32
    OrderCount  int32
}

func init() {
    localTicket = &LocalTicket{
        TotalTicket: 150,
        OrderCount:  0,
    }
    done <- struct{}{}
}

func Buy(c *gin.Context) {
    <-done
    localTicket.OrderCount++
    if localTicket.OrderCount > localTicket.TotalTicket {
        writeLog("本地已售罄", "./stat.log")
        c.String(200, "本地已售罄")
        return
    }
    if RemoteDeductionStock(redisPool.Get()) {
        writeLog("购买成功", "./stat.log")
        c.String(200, "购买成功")
        return
    }
    writeLog("全部售罄", "./stat.log")
    c.String(200, "全部售罄")
    return
}

func writeLog(msg string, logPath string) {
    fd, _ := os.OpenFile(logPath, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0644)
    defer fd.Close()
    content := strings.Join([]string{msg, "\r\n"}, "")
    buf := []byte(content)
    fd.Write(buf)
}


并发买票

1、初始化 redis中设置总票数和0订单数
2、本地初始化 根据评估,本地初始化票数,只能是本地有票的情况下才去redis中访问,两个地方同时有票才可以买票成功,否则失败
3、买票时本地票已卖完的话,直接返回失败,不需要访问redis,减少访问
4、为了保证票没有超卖,本地买票的解决方法是通过channel控制,缓存长度为1的channel,请求尝试往里面写入数据,如果可能写入,说明可以拿到锁,否则就阻塞,缺点是会一直阻塞,可通过上下文超时时间自动取消
redis防止超卖是用LUA脚本解决,串行读写,先判断有票,再Hincrby增加即可

订单

上面描述的是并发去买票的经过,保证了买票的顺序进行,并且不会超卖,但是抢到票后,还需要创建订单,付款和发货

相关文章

  • 并发抢票

    并发买票 1、初始化 redis中设置总票数和0订单数2、本地初始化 根据评估,本地初始化票数,只能是本地有票的情...

  • 并发同步案例 抢票

    案例一:订票系统案例,某航班只有一张机票,假定有1w个人打开你的网站来订票,问你如何解决并发问题(可扩展到任何高...

  • 微博热搜、天猫秒杀、12306抢票,都是高并发,难点相同吗?

    又是一年春运抢票时,12306 又挂了。同为高并发,微博热搜、天猫秒杀、12306 抢票有什么不同呢? 本文完全基...

  • 抢票,抢票

    最近,一些网站为了吸引眼球,用了“春运抢票”的字眼,让我想起了多年前我们“抢”和“被抢”的那一幕幕。 上世纪九十年...

  • 集齐了100多个加速包,但还是没抢到票,是又被骗了吗?

    关键词:抢票、抢票、抢票。摘要:又是一年一度抢票季,又开始玩邀请好友来加速的游戏了。 年关将至,又到了全民抢票的时...

  • 12306抢票软件

    12306抢票软件 !> 越来越多标题类似“帮我加速抢票”出现在票圈,如果知道抢票的原理就知道这些都是营销手段。抢...

  • 抢票篇----抢票神器!

    一则不太重要的通知:写文章推送文笔不太好,有很多不足,还请大家共同交流学习,每一次写的文章并不全是原创文章,有些只...

  • 抢票

    九月,于大多数人而言一定是金色的、是硕果累累的。于我,却是红色的、是惊心动魄的。为什么这么说?因为我的家乡在遥远的...

  • 抢票

    长这么大,这是头一回抢火车票。原先购买了22号高铁票,当时因为硬卧票已卖完,所以不得已买了高铁票,这个高铁票时间不...

  • 抢票

    抢到了五月天的票,激动兴奋了半小时,小棉说借此演唱会要跟青春做个告别,。我突然意识到我三十好几的人了。青春年华什么...

网友评论

      本文标题:并发抢票

      本文链接:https://www.haomeiwen.com/subject/aklgqdtx.html