秒杀和限流 redis

秒杀

基于redis的秒杀方案

在这里插入图片描述
redis是单线程的,所以在redis中所有命令都是原子操作。而当要多条redis命令同时执行而不被打断时,则需要使用redis的事务了。
商品放到redis上面,每一次都在redis里面执行操作,操作之前先watch(key), watch的作用就是检测这个key,如果这key的事务被修改则不会执行,监控一直持续到exec命令,在这两个命令之间还有一个命令multi 在这个命令之后对redis进行更改(事务中的命令是在EXEC之后才执行的,所以在MULTI命令后可以修改WATCH监控的键值)
MULTI命令
用于开启一个事务,它总是返回OK。MULTI执行之后,客户端可以继续向服务器发送任意多条命令, 这些命令不会立即被执行,而是被放到一个队列中,当 EXEC命令被调用时, 所有队列中的命令才会被执行。

EXEC命令
负责触发并执行事务中的所有命令:
如果客户端成功开启事务后执行EXEC,那么事务中的所有命令都会被执行。
如果客户端在使用MULTI开启了事务后,却因为断线而没有成功执行EXEC,那么事务中的所有命令都不会被执行。
需要特别注意的是:即使事务中有某条/某些命令执行失败了,事务队列中的其他命令仍然会继续执行——Redis不会停止执行事务中的命令,而不会像我们通常使用的关系型数据库一样进行回滚。

DISCARD命令
当执行 DISCARD 命令时, 事务会被放弃, 事务队列会被清空,并且客户端会从事务状态中退出。

WATCH 命令
可以为Redis事务提供 check-and-set (CAS)行为。被WATCH的键会被监视,并会发觉这些键是否被改动过了。 如果有至少一个被监视的键在 EXEC 执行之前被修改了, 那么整个事务都会被取消, EXEC 返回nil-reply来表示事务已经失败。

在这里插入图片描述

实现方案(jedis或者redisson,Redistemplate)

基于jedis
jedis.watch(productKey);//保证一致性
Transaction tx = jedis.multi();//开启事务
tx.incrBy(productKey, -1);//扣减库存
List<Object> list = tx.exec();//执行事务
mq.send(order);//发出订单

基于redisson
RSemaphore semaphore = redissonClient.getSemaphore("SEC_KILL" + skuId + "");
boolean b = semaphore.tryAcquire();
//setnxex(user) //控制频率,规定时间内只能秒一个

限流(算法介绍)

下面的代码一般都是写在Nginx里面的(lua脚本)不是写在java代码里面的,写在java代码里面的话就表示请求都进来了,那进行限流就没有意义了.

1.服务器容量(服务器能够允许最大的连接数) -> 容量的限制只需要进行一个session的监听,达到了最大值之后就返回一个通知页面
2.服务器流量 -> 限流就是对服务器流量的限制 服务器的吞吐能力,一般是指服务器在单位时间内能够处理的请求的数量
按秒,计算服务器每秒的请求数量是否达到最大值(max个请求).如果超过该值,则拒绝请求->但是这样的999ms–>1ms之间服务器很有可能会处理到两倍的请求,所以服务器在这个时候会出错,所以我们不能用时间来进行判断

漏桶算法

在这里插入图片描述
桶就一直是在接受请求,桶的眼就是服务器处理请求,桶下面的眼多大取决于服务器的处理能力,


long timeStamp = getNowTime(); 
int capacity = 10000;// 桶的容量,即最大承载值
int rate = 1;//水漏出的速度,即服务器的处理请求的能力
int water = 100;//当前水量,即当前的即时请求压力

//当前请求线程进入漏桶方法,true则不被拒绝,false则说明当前服务器负载水量不足,则被拒绝
public static bool control() {
long  now = getNowTime();//当前请求时间
//先执行漏水代码
//rate是固定的代表服务器的处理能力,所以可以认为“时间间隔*rate”即为漏出的水量
    water = Math.max(0, water - (now - timeStamp) * rate);//请求时间-上次请求时间=时间间隔
    timeStamp = now;//更新时间,为下次请求计算间隔做准备
    if (water < capacity) { // 执行漏水代码后,发现漏桶未满,则可以继续加水,即没有到服务器可以承担的上线
        water ++; 
        return true; 
    } else { 
        return false;//水满,拒绝加水,到服务器可以承担的上线,拒绝请求
   } 
}

在这里插入图片描述

令牌桶算法

令牌桶算法的原理是系统会以一个恒定的速度往桶里放入令牌,而如果请求需要被处理,则需要先从桶里获取一个令牌,当桶里没有令牌可取时,则拒绝服务。
在这里插入图片描述

long timeStamp=getNowTime(); 
int capacity; // 桶的容量 
int rate ;//令牌放入速度
int tokens;//当前水量  

bool control() {
   //先执行添加令牌的操作
   long  now = getNowTime();
   tokens = max(capacity, tokens+ (now - timeStamp)*rate); 
   timeStamp = now;  
   if(tokens<1){
     return false; //令牌已用完,拒绝访问
   }else{ 
     tokens--;
     retun true; //还有令牌,领取令牌
   }
 }

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值