美文网首页
go处理秒杀系统

go处理秒杀系统

作者: 哆啦在这A梦在哪 | 来源:发表于2018-11-26 15:29 被阅读47次

    秒杀系统的定制:

    前端方案

    浏览器端(js):
    页面静态化:将活动页面上的所有可以静态的元素全部静态化,并尽量减少动态元素,通过CDN来抗峰值
    禁止重复提交:用户提交之后按钮置灰,禁止重复提交
    用户限流:在某一时间内只允许用户提交一次请求,比如可以采取IP限流

    后端方案

    服务器控制器层(网关层)
    限制UID(userID)访问频率:我们上面拦截了浏览器的访问请求,但准对某些恶意请求和攻击或者其他插件,在服务器控制层要准对同一个uid,限制访问频率

    服务层

    上面只拦截了一部分请求,当秒杀的用户量非常大时,即使每个用户只有一个请求,到服务层的请求数量还是很大。比如我们有100w用户同时抢购100台手机,服务层并发请求压力至少为100w。
    1.采用消息队列缓存请求:既然服务器层知道库存只有100台手机,那完全没有必要把100w个请求都传递到数据库里,那么可以先把这些请求都写到消息队列里面缓存一下,数据库层订阅消息减少库存,减库存成功的请求返回秒杀成功,失败的返回秒杀结束
    2.利用缓存应对读请求:对类似12306等购票业务,是典型的读多写少业务,大部分请求时查询请求,所以可以利用缓存分担数据库压力
    3.利用缓存对写请求:缓存也是可以应对写请求,比如我们可以把数据库中库存数据迁移到Redis缓存中,所有减库存操作都在Redis中进行,然后通过后台进程把Redis中的用户秒杀请求同步到数据库中

    数据库层

    数据库层是最脆弱的一层,一般在应用设计时在上游就需要把请求拦截,数据库层只承担“能力范围内”的访问请求。所以,上面通过在服务层引入的队列和缓存,让底层的数据库高枕无忧

    一:保证数据的原子性:

    1 数据库:
    update product set left_num=left_num-1 where left_num>0;
    这里用到的是left_num=left_num-1,如果left_num>0才能执行成功,数据库查询、更新的时候有用到锁,是可以保证更新操作的原子性的。
    数据库性能较差,不建议使用。
    2 分布式锁
    用redis来做一个分布式锁,reids->setnx('lock', 1) 设置一个锁,程序执行完成再del这个锁。
    锁定的过程,不利于并发执行,大家都在等待锁解开,不建议使用。
    3 消息队列
    将订单请求全部放入消息队列,然后另外一个后台程序一个个处理队列中的订单请求。
    并发不受影响,但是用户等待的时间较长,进入队列的订单也会很多,体验上并不好,也不建议使用。
    4 redis递减
    通过 redis->incrby('product', -1) 得到递减之后的库存数。

    二:集群怎么来规划

    前端服务器因为没有相互间关联,集群的数量不受影响。
    redis的性能可以达到每秒几万次响应,所以一个集群的规模,也就是redis服务可以承载的数量。
    比如:一台前端服务器是12k的qps(有库存时),那么10台+1台redis就可以是一个独立的集群,可以支撑12w每秒订单量。
    10个上述的集群就可以做到一秒钟处理10w~20w的有效订单。
    如果秒杀活动的库存量在1w以内,预计参与的人数在百万左右,那么有一个集群也就可以搞定。
    如果秒杀参与的人数超过千万,那么就要用到不止一个集群了。

    三:多个集群的数据怎么保持一致性

    不要做多集群的数据同步,而是用散列,每个集群的数据是独立存在的。
    假设,有10个商品,每个商品有1w库存,规划用10个集群,那么每个集群有10个商品,每个商品是1k库存。
    每个集群只需要负责把自己的库存卖掉即可,至于说,会不会有用户知道有10个集群,然后每个集群都去抢。
    这种情况就不要用程序来处理了,利用运营规则,活动结束后汇总订单的时候再去处理就好了。
    如果担心散列的不合理,比如:某个集群用户访问量特别少,那么可以引入一个中控服务,来监控各个集群的库存,然后再做平衡。

    相关文章

      网友评论

          本文标题:go处理秒杀系统

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