• 借助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问题,但我们可以找到许多解决办法。

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

  • 相关阅读:
    Redis连接出现Error: Connection reset by peer的问题是由于使用Redis的安全模式
    redis
    flutter RN taro选型思考
    SpringBoot 使用 Redis Geo
    Redis GEO地理位置学习
    Flink从socket读取数据sink到redis
    Redis的GEO地理位置指令实现IM里“附近的人”
    Redis Windows 64位下安装Redis详细教程
    docker安装redis
    SpringBoot中注入RedisTemplate实例异常解决
  • 【推广】 阿里云小站-上云优惠聚集地(新老客户同享)更有每天限时秒杀!
    【推广】 云服务器低至0.95折 1核2G ECS云服务器8.1元/月
    【推广】 阿里云老用户升级四重礼遇享6.5折限时折扣!
  • 原文地址:https://www.cnblogs.com/nnhy/p/Seckill.html
走看看 - 开发者的网上家园