Redis队列实现Java版秒杀系统(无脚本、可用于生产)

需求是做一个秒杀系统,比如大家来抢100台手机,先到先得。

查阅了网上很多用redis实现秒杀的demo(java语言),竟然没一个能用的!!!

有些是php的,没闲心研究了,现在说说为什么不能用:

  • 绝大多数的DEMO都是基于redis的watch特性的事务实现①,

  • 个别是基于redis分布式锁实现②。

  • 当然还有些用了脚本的,我也没仔细看是lua还是调用redis指令,哪有那个闲心去研究哇。

照顾一下小白,正文分析一下为什么这几种实现不行

正文

1.基于watch特性的 不靠谱 实现

其实这两种实现方式,完全可以理解为乐观锁(watch)和悲观锁(加分布式锁)

watch事务,相当于是乐观锁,这种方法在并发情况下极为不靠谱,假设有100个人同时尝试秒杀,那么极端情况下,有99个人都会失败,只有一个能修改成功。

然而demo里甚至没写如果修改失败了就重试这个功能,那显然这失败的99个人,已经提示失败了,过一会回来,发现还剩了90多。那我是怎么失败的?我替他们问问了。

并且使用这种方式实现呢,在并发量较大的时候,过多的重试线程应该会严重影响服务器性能。

2.基于用redis做个分布式锁的 不靠谱 实现

这种实现方式相当于一个悲观锁,每次执行减减操作之前,在redis中存入一个k,v键值对,使用特定的名称,并且使用setNX特性,确保抢锁没有安全问题,并在使用完成后释放锁。那么问题是,在100个人秒杀时,只有一个人抢到锁,剩下99个人怎么办?

demo里同样没写个重试,抢不到锁就失败,醉了,不过就算写重新抢锁的机制,那么几十个上百个线程不断抢锁,想想是个挺恐怖的事,更别提高并发了。

基于脚本的实现 不靠谱 实现

作为一个C系语言开发,我看不太懂,看不懂就是不靠谱,出了问题都不知道改哪里,你说靠不靠谱

正题:使用spring操作redis的list队列实现

我用的是springboot的StringRedisTemplate,至于如何整合jedis到spring等等,去查阅其他文章吧,我就不重复写了。

贴工具类:
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import java.time.Duration;
import java.util.Collection;

@Service
public class RedisServiceImpl<T> implements RedisService<T> {
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    //添加字符串并设置过期时间
    @Override
    public void addString(String key, String value, Duration duration) {
        stringRedisTemplate.opsForValue().set(key, value, duration);
    }

    //查找字符串
    @Override
    public String findString(String key) {
        return stringRedisTemplate.opsForValue().get(key);
    }

    //根据Key删除
    @Override
    public Boolean deleteByKey(String key) {
        return stringRedisTemplate.delete(key);
    }

 //在队列尾部减少一个对象
    @Override
    public String removeOneEntryOnListRight(String listName) {
        return stringRedisTemplate.opsForList().rightPop(listName);
    }

 //在队列头部新增对象
    @Override
    public Long addEntriesOnListLeft(String listName, Collection<String> args) {
        return stringRedisTemplate.opsForList().leftPushAll(listName, args);
    }

}

解释一下哈 这个类的父类是我自己写的service层,不是提供好的

主要使用的是最后两个方法,最后一个方法,在队列头部新增对象,如果没有这个队列,他会创建出来这个队列,然后将一个集合统统塞到这个redis队列中。倒数第二个方法每调用一次,会删除队列中最后一个元素,然后返回这个元素的值,如果队列中已经没有元素了(队列已经没了)那么他会返回null,他们都是原子操作。

如此,每个请求都无需经过加锁操作,直接利用redis的单线程特性,即可实现高并发下的秒杀:请求到达redis,redis会逐个执行,每一次执行要么返回一个值,要么返回null。很显然,返回值的就是抢到了,返回null的就是没抢到。而且可以灵活的为这个队列新加入一些元素(老板发话再加100台)或者直接把这个队列删了(老板说不行,不卖了)都不会对代码产生任何影响。

其中对应的redis操作指令分别是:

  • 在队列左侧新增:lpush

  • 在队列右侧消费:rpop

老板不卖了:del (笑)

接下来贴出十分简单的使用方法

先贴在任务开始时向redis中插入一个大队列

List<String> entriesList = new LinkedList<>();
   for (int i = 0; i < 100; i++){
       entriesList.add("某个商品");
   }
   redisService.addEntriesOnListLeft("队列名",entriesList);

突然想到这个实现即使秒杀100台不同型号的手机(并且在秒到时就通知用户秒到的是啥),也不用改代码。

每次秒杀执行:

String redisResult = redisService.removeOneEntryOnListRight("队列名");
    if (null == redisResult) {
        //说明没抢到
    }else{
 //说明抢到了 执行抢到逻辑
}

突然发现这个实现看起来甚至比那些所谓的秒杀demo还简单

但他既没有并发问题,也没有为了解决并发问题而衍生的性能问题。

虽然没经过测试,不过我认为就算秒杀10万台,放到redis队列里,应该也占用不了多少内存。

赶工分布式秒杀,没想到如此基本的内容,竟没找到一个靠谱的实现,从上午写到现在(周末晚8点)一顿饭没吃,被网上过于demo的资源逼的,忍饿怒出此文。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,457评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,837评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,696评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,183评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,057评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,105评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,520评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,211评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,482评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,574评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,353评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,897评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,489评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,683评论 2 335

推荐阅读更多精彩内容