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