关于抢购系统的一些想法

关于抢购系统的一些想法

昨天SD开放了819 FF14 Fanfest周边的限量抢购。在抢购过程中,不少用户遇到了事务死锁的问题,反复下单无法成功,用户体验极差。根据个人分析猜测,此次抢购时用户下单后会直接在库存数据库中减少库存,而前端进行AJAX请求会直接请求库存数据库中的数据。因此会导致读/写锁定,出现死锁问题。 死锁实例

目前来说,以此次抢购为例,抢购 => 确认订单 =>付款这样的流程而言,在抢购过程中并不需要保证库存的强一致性,因为实际上可以在确认订单时杜绝超售的出现。完全可以在前端请求生成订单后,在后端进行简单确认就把订单送入临时订单表中,该表格只做INSERT和READ操作,不进行ALTER,可以最大程度的减少数据库产生死锁的可能性。

后端实现伪代码:

'use strict'

var stock = new Map()

//Initialize stock map
var initStock = (dataFromDb) => {
    dataFromDb.forEach((e) =>{
        stock.set(e.Id, e.Val);
    });
}

app.post('/flash_sale', isLoggedIn, (req, res) => {
    var now = process.hrtime()

    var order = {
        'TimeStamp': {
            Second: now[0],
            nanoSecond: now[1]
        },
        OrderId: GenerateOrderId(now),
        Items: []
    }

    req.body.items.forEach((e)=>{
        var curStock = stock.get(e.Id)
        if(curStock){
            if(curStock>=1){
                order.Items.push(e)
            }
        }
    })

    if(order.Items.length>0){
        storeOrder(order)
    }

})