博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
借助Redis做秒杀和限流的思考
阅读量:6673 次
发布时间:2019-06-25

本文共 1144 字,大约阅读时间需要 3 分钟。

原文:

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

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

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

 

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

转载地址:http://vkgxo.baihongyu.com/

你可能感兴趣的文章
输入框提示--------百度IFE前端task2
查看>>
实战p12文件转pem文件
查看>>
如何去掉数据库重复记录并且只保留一条记录
查看>>
ubuntu 无线上网不稳定
查看>>
模板 数据结构
查看>>
【Search a 2D Matrix】cpp
查看>>
POJ 1741 Tree(树的点分治,入门题)
查看>>
Opencv3.1.0 & Win10/Win7 64位 contrib编译
查看>>
MPMoviePlayerController播放远程视频存在问题
查看>>
一个已经存在的CCSprite怎么替换新的图片
查看>>
更加安全的存取账户密码(SDK)
查看>>
NSNotificationCenter 的详细说明
查看>>
List/Vector
查看>>
黄聪:FFmpeg 使用指南
查看>>
能否不同udp socket绑定到同一IP地址和port
查看>>
C#:CodeSmith根据数据库中的表创建C#数据模型Model + 因为没有钱买正版,所以附加自己写的小代码...
查看>>
乐视4.14硬件免费日de用户体验
查看>>
ASP.NET Core MVC/WebAPi如何构建路由?
查看>>
数据库巡检脚本
查看>>
有选择的复制对象,即根据客户端传值来复制对象属性值
查看>>