zoukankan      html  css  js  c++  java
  • 借助Redis做秒杀和限流的思考

    最近群里聊起秒杀和限流,我自己没有做过类似应用,但是工作中遇到过更大的数据和并发。

    于是提出了一个简单的模型:

    var count = rds.inc(key);

    if(count > 1000) throw "已抢光!"

    借助Redis单线程模型,它的inc是安全的,确保每次加一,然后返回加一后的结果。如果原来是234,加一了就是235,返回的一定是235,在此中间,不会有别的请求来打断从而导致返回236或者其它。

    其实我们可以理解为inc的业务就是占坑排队,每人占一个坑,拿到排队小票后看看是不是超额了,再从业务层面输出秒杀结果,甚至做一些更加复杂的业务。

    六条提到限流,可能基于某种考虑,希望把key对应的count给限制在1000附近,可以接受1%偏差。

    于是有了改进模型:

    var count = rds.inc(key);

    if(count > 1000){

        rds.dec(key);

        throw "超出限额!"

    就加了一句,超出限额后,把小票给减回去^_^

    采用Redis有一个好处,比如支持很多应用服务器一起抢……

    当然,对于很大量的秒杀,这个模型也不一定合理,比如要枪10万部手机,然后来了300万用户,瞬间挤上来。

    这里有个变通方法可以试一下,那就是准备10个Redis实例,每个放1万。用户请求过来的时候,可以随机数或者散列取模,找对应实例来进行抢购。

    同理可以直接更多用户的场景。总的来说,在数据较大的时候,随机和散列就具有一定统计学意义,相对来说是比较均衡的。

    上面是大量秒杀的简单场景,那么小数据场景呢?比如就只有几万并发的场景

    小数据场景,单应用实例,可以考虑把Redis都给省了。

    初级模型:

    Interlocked.Increase(ref count);

    if(count >= 1000) throw "抢光啦!"

    中级模型:

    private volatile Int32 count;

    var old = 0;

    do {

        old = count;

        if(old >= 1000) throw "抢光啦!"

    }while(Interlocked.CompareExchange(ref count, old + 1, old) != old);

    这个CAS原子操作可是好东西,在x86指令集下有专门指令CMPXCHG来处理,在处理器级别确保比较和交换数据的原子性。大多数系统想要迈过10万tps的门槛向100万tps靠齐,就必须得实现无锁操作lock-free,其中CAS是最为简单易懂,尽管有时候有ABA问题,但我们可以找到许多解决办法。

    在实际使用场景中,可能有更复杂的需求,那就另当别论,这里只能班门弄斧几个简单易用的模型。

  • 相关阅读:
    LeetCode 42. Trapping Rain Water
    LeetCode 209. Minimum Size Subarray Sum
    LeetCode 50. Pow(x, n)
    LeetCode 80. Remove Duplicates from Sorted Array II
    Window10 激活
    Premiere 关键帧缩放
    AE 「酷酷的藤」特效字幕制作方法
    51Talk第一天 培训系列1
    Premiere 视频转场
    Premiere 暴徒生活Thug Life
  • 原文地址:https://www.cnblogs.com/nnhy/p/Seckill.html
Copyright © 2011-2022 走看看