其实真是的秒杀不是这样的

来源:-

杨开振

2016-10-28 01:56

作为java的多年经验的码农觉得老师的东西很怪异,CAS原理都不讲的,你用mysql的锁去应对秒杀基本就死在哪里了。

1、老师说得这个行锁很怪异,mysql根本就没有这个东西,没有加for update你会有行锁吗?不知道老师所谓的行锁是从天而降吗??这个称为悲观锁。但是代价太大,我们基本不用。因为使用它,你所有的线程就等着挂起和等待了,系统就基本就死在哪里了。

2、一般我们即时使用数据库,也不会这样用,应该加一个version字段。

(1)首先是程序读取select  version, left from table;

(2)然后记录version字段(旧值),判定left - buyCount(购买数量)>=0,如果否退出,结束业务。否则继续(3)

(3)开始执行减库存

update table set left = left - #{byCount} , version =  version+1

where count >0 and vesion = #{vesion}//这个version是旧值,而更新一次成功version就加1

这里数据库并没有任何锁,但是这里巧妙的使用了version字段,符合一个CAS原理,就是我当初读出的version(旧值)和实时数据库的version(当前需要更新时刻的实时值)是否一致,如果一致,则我会认为这条记录没有被其他线程修改,则减库存成功,如果不一致则我会认为其他线程修改过这个记录。就不会进行操作这个被称为乐观锁。这个时候我们会考虑重入,重复执行(1)-(3)步骤直至(2)的退出或者(3)成功继续我们的操作,这样就是一个没有锁的机制。这就是一个乐观锁的机制,而没有任何等待的机制,是一个非阻塞的过程。


3、企业的秒杀目前应该考虑使用redis,而不是mysql。

别和我说你mysql的性能和redis比,个人自测分别批量插入数据:

redis每秒在我的机子可以执行40万次的插入,而mysql只能执行不到2万次。这个性能差了几十倍。你用mysql是自己找麻烦。这个级别根本不同级,其次redis提供的事务很好的符合了秒杀的功能。

首先任何线程执行redis的操作的时候都是使用lua语言,redis在执行lua语言的时候是原子性的,让它执行减库存,并且记录用户购买记录。

直至秒杀时间到期或者库存为0,才考虑将redis缓存的数据批量一次性把减库存和用户购买的信息批量写入mysql。整个秒杀过程基本在redis完成,而不是数据库,不是你mysql的性能可比的,你服务器上mysql一秒可以4万次,redis可以上百万次,你怎么比??

写回答 关注

5回答

  • 益军
    2016-10-31 14:33:16

    秒杀场景主要两个点:

    1:流控系统,防止后端过载或不必要流量进入,因为慕课要求课程的长度和简单性,没有加。

    2:减库存竞争,减库存的update必然涉及exclusive lock ,持有锁的时间越短,并发性越高。

    CAS是否适用瞬时竞争?

    1:"select  version, left from table where pk= {pid}"不加 for update 并发得到共享version

    2: "update table set left = left - #{byCount} , version =  version+1 where pk={id} count >0 and vesion = #{vesion}" 首先这句sql本身会加row-level exclusive lock。version大量冲突导致减库存失效,客户端重试导致TPS翻倍,加重DB负担。

    3:对于使用redis+LUA实现秒杀库存逻辑,重点在异步MQ落地可靠性和异常回滚机制。

    对于生产环境的秒杀没有这么简单,需要全链路梳理和优化,参见之前同事的分享:http://www.infoq.com/cn/presentations/challenge-of-alipay-red-envelopes

    最后,不用回我了,如果你觉得我讲的问题多,希望你也录一个课程,这样可以帮助大家,何乐不为呢。

  • 益军
    2016-10-31 10:09:45

    首先感谢你的回复,这门课已经说了,用最常用的技术分析实现秒杀场景。

    其次你的思路请在想想。参考一下文档:

    http://dev.mysql.com/doc/refman/5.7/en/innodb-locking.html

    http://www.infoq.com/cn/presentations/seckill-solution-based-sql

    http://geek.csdn.net/news/detail/93986

    作者之前就在阿里淘宝技术部,秒杀处理方式我还是比较清楚的。

    最后这门课只是帮助有需要的同学。

    慕粉3820... 回复杨开振

    update语句执行之后就会获得排它锁了。。。。老师的这种方法 在不是超大规模的并发都很实用 视频里面已经说了啊 用redis加rabbitMQ实现浪费人力物力,如果没有特别大的并发 没必要用那些东西

    2017-12-18 00:59:33

    共 2 条回复 >

  • 慕UI8147805
    2019-08-07 19:55:13

    mysql的默认RR级别,对于写写操作,不是默认加行锁吗?这个人问了一大段的结果问题就是错的

  • 慕粉3820626
    2017-12-18 00:57:41

    mysql执行update语句的时候已经获得了这条记录的排它锁了 也就是老师说的行级锁吧

  • 慕粉4287469
    2016-11-15 03:28:49

    杨开振你这妖孽写完书来这儿砸场子

    杨开振

    多探讨,多点了解而已,有质疑是好事

    2016-11-15 11:52:37

    共 1 条回复 >

Java高并发秒杀API之高并发优化

Java实现高并发秒杀API的第四门课,小伙伴一定可以从中受益

78690 学习 · 182 问题

查看课程

相似问题