上个月,腾讯有机会去逛了一圈,面试工作,虽然没有承认,但在整个过程而言仍然令人愉快。面试面试过程中我的孩子(看看关于年龄26,7岁)他问了我一个关于秒杀问题。他说,腾讯游戏往往有秒杀活动。致server死锁或压力太大,应该怎样设计减轻数据库server压力。当然由于面试的是PHP职位,我做的是C#和JAVA我知道应该没机会所以本不想太过“配合”的回答,可是看面试我的小朋友看我好像非常不削的样子(可能由于面试的是PHP职位并且一上来就让我做题目,尽管我有点不情愿做题可是毕竟是腾讯还是做了可是PHP接触的真的不多所以题目差点儿是连蒙带猜的完毕的,预计不是非常好看),所以还是认真想了想解决方式。
秒杀说究竟就是瞬间大规模訪问,导致的压力,前端我们能够使用集群技术,数据库呢?拆表?是个方法,可是假设仅仅是简单拆表仍然会有问题,毕竟秒杀商品被记录到表中后用户秒杀必然是须要通过改动表中已有的秒杀商品记录来确定这个商品是否已经被秒走。为了防止抢到同一条记录加锁是必须。
而数据库一锁性能问题就来了。那怎么办呢?我想了一个方法(至少有一点能够确定腾讯游戏没实用这种方法解决),秒杀时并非立马去改动数据库中记录(进行update操作),而是先向一张表中插入一条记录,类似进入等待队列,为了防止大规模插入操作导致锁表我们能够将队列表拆成多张同样结构表。有一个job会不断读取这些队列表并依照插入时间排列计算那些记录被秒杀成功。而client在点击秒杀button后断开连接,几秒后再次通过查询语句来查询结果。并返回给前台客户。
这样做的优点秒杀过程是分段的。前台用户在秒杀时仅是向(多张队列表中)某一张队列表中插入一条记录。之后便断开本次连接进入等待,job程序通过合并查询将多张秒杀表合并按插入时间排序。按规则得出秒杀成功的用户并改动秒杀商品表。表明此商品已被秒杀。前台程序在等待几秒后查询秒杀商品表获得自己是否已秒杀成功。
由于第一步骤是只插入操作,而不必担心因脏数据同步问题。因此,我们可以拆表来分散压力通过降低隔离级别。更新操作是一个单独的job计划完成,因为只有一个程序来更改记录,所以它不会质疑锁表的存在。最后,前台得到结果的查询,因为查询不需要任何商品秒杀结果只需要知道订单是否不够抓住自己。它有可能使用with(nolock)忽略一类的锁定机构来运行。