库存秒杀问题-redis解决方案- 接口限流
<?php
/**
* Created by PhpStorm.
* redis 销量超卖秒杀解决方案
* redis 文档:http://doc.redisfans.com/
* ab -n 10000 -c 3000 http://localhost/demo.php 模拟并发
*/ $redis = new Redis();
$redis->connect('127.0.0.1',6379); //1. 对某一个键加锁,这个键是我们自己设置,起到监视作业
$redis->watch('sales'); //获取销量,清空sales 为0
$sales = $redis->get('sales'); //总库存
$store = 4; if($sales>=$store){
exit('已经被抢光了'); //跳转活动结束页面
} //redis事务不会回滚, 开启事务
$redis->multi();
$redis->set('sales',$sales+1); //销量加1
$res = $redis->exec(); if($res){
//减库存
include db.php; //数据库连接
//执行sql ,减库存
}
exit; =====================redis接口限流============================
- 非脚本实现
private boolean accessLimit(String ip, int limit, int time, Jedis jedis) {
boolean result = true;
String key = "rate.limit:" + ip;
if (jedis.exists(key)) {
long afterValue = jedis.incr(key);
if (afterValue > limit) {
result = false;
}
} else {
Transaction transaction = jedis.multi();
transaction.incr(key);
transaction.expire(key, time);
transaction.exec();
}
return result;
}
以上代码有两点缺陷
- 可能会出现竞态条件: 解决方法是用
WATCH监控rate.limit:$IP的变动, 但较为麻烦; - 以上代码在不使用
pipeline的情况下最多需要向Redis请求5条指令, 传输过多.
Lua脚本实现
Redis 允许将 Lua 脚本传到 Redis 服务器中执行, 脚本内可以调用大部分 Redis 命令, 且 Redis 保证脚本的原子性:
- 首先需要准备Lua代码: script.lua
--
-- Created by IntelliJ IDEA.
-- User: jifang
-- Date: 16/8/24
-- Time: 下午6:11
-- local key = "rate.limit:" .. KEYS[]
local limit = tonumber(ARGV[])
local expire_time = ARGV[] local is_exists = redis.call("EXISTS", key)
if is_exists == then
if redis.call("INCR", key) > limit then
return
else
return
end
else
redis.call("SET", key, )
redis.call("EXPIRE", key, expire_time)
return
end
private boolean accessLimit(String ip, int limit, int timeout, Jedis connection) throws IOException {
List<String> keys = Collections.singletonList(ip);
List<String> argv = Arrays.asList(String.valueOf(limit), String.valueOf(timeout));
return 1 == (long) connection.eval(loadScriptString("script.lua"), keys, argv);
}
// 加载Lua代码
private String loadScriptString(String fileName) throws IOException {
Reader reader = new InputStreamReader(Client.class.getClassLoader().getResourceAsStream(fileName));
return CharStreams.toString(reader);
}
Lua 嵌入 Redis 优势:
- 减少网络开销: 不使用 Lua 的代码需要向 Redis 发送多次请求, 而脚本只需一次即可, 减少网络传输;
- 原子操作: Redis 将整个脚本作为一个原子执行, 无需担心并发, 也就无需事务;
- 复用: 脚本会永久保存 Redis 中, 其他客户端可继续使用.
库存秒杀问题-redis解决方案- 接口限流的更多相关文章
- Redis除了做缓存--Redis做消息队列/Redis做分布式锁/Redis做接口限流
1.用Redis实现消息队列 用命令lpush入队,rpop出队 Long size = jedis.lpush("QueueName", message);//返回存放的数据条数 ...
- SpringBoot使用自定义注解+AOP+Redis实现接口限流
为什么要限流 系统在设计的时候,我们会有一个系统的预估容量,长时间超过系统能承受的TPS/QPS阈值,系统有可能会被压垮,最终导致整个服务不可用.为了避免这种情况,我们就需要对接口请求进行限流. 所以 ...
- 基于注解的接口限流+统一session认证
代码心得: 一个基本的做法:对于用户身份认证做到拦截器里,针对HandlerMethod进行统一拦截认证,根据方法上的注解标识,判别是否需要身份验证,并将查找出来的User实体存入ThreadLoca ...
- 【Dnc.Api.Throttle】适用于.Net Core WebApi接口限流框架
Dnc.Api.Throttle 适用于Dot Net Core的WebApi接口限流框架 使用Dnc.Api.Throttle可以使您轻松实现WebApi接口的限流管理.Dnc.Api.Thr ...
- 限流(三)Redis + lua分布式限流
一.简介 1)分布式限流 如果是单实例项目,我们使用Guava这样的轻便又高性能的堆缓存来处理限流.但是当项目发展为多实例了以后呢?这时候我们就需要采用分布式限流的方式,分布式限流可以以redis + ...
- 【高并发】亿级流量场景下如何为HTTP接口限流?看完我懂了!!
写在前面 在互联网应用中,高并发系统会面临一个重大的挑战,那就是大量流高并发访问,比如:天猫的双十一.京东618.秒杀.抢购促销等,这些都是典型的大流量高并发场景.关于秒杀,小伙伴们可以参见我的另一篇 ...
- Guava-RateLimiter实现令牌桶控制接口限流方案
一.前言 对于一个应用系统来说,我们有时会遇到极限并发的情况,即有一个TPS/QPS阀值,如果超了阀值可能会导致服务器崩溃宕机,因此我们最好进行过载保护,防止大量请求涌入击垮系统.对服务接口进行限流可 ...
- 服务限流 -- 自定义注解基于RateLimiter实现接口限流
1. 令牌桶限流算法 令牌桶会以一个恒定的速率向固定容量大小桶中放入令牌,当有浏览来时取走一个或者多个令牌,当发生高并发情况下拿到令牌的执行业务逻辑,没有获取到令牌的就会丢弃获取服务降级处理,提示一个 ...
- Spring Cloud Alibaba基础教程:使用Sentinel实现接口限流
最近管点闲事浪费了不少时间,感谢网友libinwalan的留言提醒.及时纠正路线,继续跟大家一起学习Spring Cloud Alibaba. Nacos作为注册中心和配置中心的基础教程,到这里先告一 ...
随机推荐
- JAVA笔记--static
1.static 修饰变量 public class MyClass { static int i = 4; } 其中static 修饰变量,表示变量 i 属于 MyClass 类,所有的对象共享一个 ...
- Codeforces Round #443 (Div. 1) D. Magic Breeding 位运算
D. Magic Breeding link http://codeforces.com/contest/878/problem/D description Nikita and Sasha play ...
- 自定义simple_tag和filter在html中渲染出来的联系和区别
关于 simple_tag: 1,在app下创建一个(templatetags)目录,(被引用的模块必须放在该目录下,且目录名称不可更改): 2,创建任意py文件: 3,创建template对象: f ...
- python之进程和线程
1 操作系统 为什么要有操作系统 ? 操作系统位于底层硬件与应用软件之间的一层 工作方式:向下管理硬件,向上提供接口 操作系统进程切换: 出现IO操作 固定时间 2 进程和线程的概念 进程就是一个程序 ...
- python之流程控制与运算符
第一:流程控制 一:if条件语句 计算机之所以能做很多自动化的任务,因为它可以自己做条件判断. 单分支语句: 单分支,单个条件 age = 20 if age >= 18: print('you ...
- Sqoop导入到hdfs
1.注意win下直接复制进linux 改一下--等 sqoop-list-databases --connect jdbc:mysql://122.206.79.212:3306/ --usernam ...
- 倾斜摄影数据OSGB进入到ArcGIS平台相关问题小结
版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/zglybl/article/details/75252288 随着倾斜摄影技术的发展,大家 ...
- Creating an LMDB database in Python
LMDB is the database of choice when using Caffe with large datasets. This is a tutorial of how to cr ...
- RbbitMQ消息队列及python实现
1.简介 RabbitMQ是实现了高级消息队列协议(AMQP)的开源消息代理软件(亦称面向消息的中间件).RabbitMQ服务器是用Erlang语言编写的,而集群和故障转移是构建在开放电信平台框架上的 ...
- iqiyi__youku__cookie_设置
iqiyi设置cookie var string = "此处替换iqiyi的cookie"; var getCookie = function( str) { var cookie ...