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

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

  • 相关阅读:
    c# base64及MD5工具类
    c# dateTime格式转换为Unix时间戳工具类
    c# 金钱大写转小写工具类
    c# bitmap的拷贝及一个图像工具类
    C# DataTable映射成Entity
    Kubernetes---Service(SVC)服务--ingress api
    Kubernetes---Service(SVC)服务
    为网站文字前面添加图标 在线调用 Font Awesome 字体icon小图标 美化网站
    [转]office 2016 4合1/3合1 专业版 增强版 精简绿色安装版
    [转]数据恢复 文件恢复工具 DiskGenius v4.9.1 绿色专业版及单文件
  • 原文地址:https://www.cnblogs.com/nnhy/p/Seckill.html
Copyright © 2011-2022 走看看