温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

Redis+lua进行类似秒杀的实现

发布时间:2020-05-14 16:12:29 来源:网络 阅读:14815 作者:思绪到处飞 栏目:软件技术

Redis+lua进行类似秒杀的实现

由于项目需要,需要多线程去获取和修改数据库的库存,考虑到给数据库加锁效率低,所以采用redis+lua来进行实现 。

redis的单线程操作特性来执行lua脚本,通过lua脚本来保证原子性。如果通过单纯的redis指令来进行更改,在读和写之间会存在多线程并发更新的问题。

1.首先定义redis数据结构

goodId:
 {
 "total":100,
 "released":0;
 }
  • 其中goodId为商品id号,可根据此来查询相关的数据结构信息,total为总数,released为发放出去的数量,可使用数为total-released
    <!--more-->
    2.编写lua脚本
    
    local n = tonumber(ARGV[1])
    if not n or n == 0 then
    return 0
    end
    local vals = redis.call("HMGET", KEYS[1], "total", "released");
    local total = tonumber(vals[1])
    local blocked = tonumber(vals[2])
    if not total or not blocked then
    return 0
    end
    if blocked + n <= total then
    redis.call("HINCRBY", KEYS[1], "released", n)
    return n;
    end
    return 0

- 执行脚本命令`EVAL script_string 1 goodId apply_count`
- 若库存足够则返回申请的数量,否则返回0,不返回可满足的剩余数

3.spring boot 调用 
- pom dependency 

<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>2.0.1.RELEASE</version>

- java code
```java
        long count = redisHelper.getStrCache().execute(new RedisCallback<Long>() {
            @Nullable
            @Override
            public Long doInRedis(RedisConnection redisConnection) throws DataAccessException {
                long ret = redisConnection.eval(script.getScriptAsString().getBytes(), ReturnType.INTEGER, 1, key.getBytes(), String.valueOf(count).getBytes());
                return ret;
            }
        });

4.redis->database

针对redis到databases的更新,思考了很久,没有找到较好的解决办法,先采用定时任务异步更新。至于数据是否丢失的问题,如果redis挂了,重启后redis会恢复数据,等下次定时任务就可以将数据库中的数据保持一致,缺点是redis挂了秒杀活动会失败。

至于redis到database更新的如何驱动,列出两种愚见:

  • redis存一份相关hash键名单表,通过读取名单表来读取更新
  • 通过流式读取databases中的表来读取更新。

欢迎各位提出问题,谢谢您的阅读

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI