您的位置:首页 > 其它

秒杀系统并发应对的设计思路小结

2017-10-15 14:16 477 查看
秒杀系统跟抽奖不同,抽奖是随机中奖,秒杀需要在启动时的瞬间,

把所有物料,顺序分配给进入系统的用户,直到分配完毕为止,

用户量大的时候,对系统的冲击也是非常大的,经常出现系统失去响应,崩溃等,

甚至于系统挂了,用户却中不到奖品(奖品超发是程序bug,本文暂不讨论)。

说明:

- 本文主要针对移动h5网站 或 pc端web网站,对手机app而言,其实思路类似

- 文中所有限制数据,需要根据业务实际情况配置,比如10秒,每秒3次之类

设计思路:

1、针对99%的正常用户,在前端进行限制,大致需要实现如下2个逻辑:

1.1、用户点击按钮后,按钮置灰,不再触发点击事件,直到响应返回才启用,

避免用户拼命点击鼠标,代码参考:

<button onclick="doKill(this);">秒杀</button>

function doKill(obj){
$(obj).attr('disabled', 'disabled');
if(window.sending){
return;
}
window.sending = true;
$.ajax({
type: 'GET',
url: 'https://app.baidu.com/api?secondKill',
cache: true,
dataType: 'json',
success: function (response) {
$(obj).removeAttr('disabled');
window.sending = false;
if (response.code !== 200) {
alert('error' + response.msg);
return;
}
alert(response.result);
}
});
}


1.2、cookie限制每用户第二次点击必须10秒以后,才能再次发送请求到后端,所以用户看似在拼命点击,实际上10秒内只发一次有效请求,示例代码:

var cookiename = 'last_kill_time';
var lastSendTime = getCookie(cookiename);
var currentTime = Date.parse(new Date());
var diff = currentTime - lastSendTime;
if(diff < 10000){
return;
}
// 发送请求到服务器的代码,然后再设置cookie
setCookie(cookiename, currentTime);


2、第1步限制了绝大多数的正常用户冲击,但是无法应对有经验的程序员,so,要服务端在IP和用户层面进行限制:

2.1、每IP,每秒只允许3次提交,超过3次,直接返回失败;

2.2、每个用户ID,每秒只允许3次提交,超过3次,直接返回失败;

注1:这2个步骤,可以在内存计数进行限制,也可以通过redis计数限制(存在多服务器分布式部署时)。

注2:需要考虑公司IP,一个IP多用户共用情况,另外无法限制有多ip代理和手上储存了很多用户账号的恶意用户,而且会出现同一时间,对不同用户响应不一致的情况,比如剩余奖品数有差异等等。

3、请求队列,单线程处理所有用户请求

比如有100个奖品,却有1万个正常用户来抢,把全部用户请求透传到DB显然有问题。

通常做法:

3.1、每放过一个请求,redis加1 ,超过总奖品数,直接返回失败;

这一步,要有失败补偿失败,比如有些用户抢到不要了,要给redis计数重置。

3.2、使用消息队列,正常请求全部加入队列,队列达到一定长度,就停止入队,返回失败,队列处理完毕,又允许入队,如此反复。

基本上就是如上3步了,在运维层面也可以做不少事情,比如多服务器负载均衡、前端网关层防冲击等等。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: