微服务Spring Boot 整合 Redis 分布式锁 Redission 实现优惠卷秒杀 一人一单

时间:2022-10-14 10:55:35

⛅引言

本章节,介绍使用分布式锁Redission完成 优惠卷秒杀,Redis 官方 首推 Redisson 作为Java 客户端!

一、什么是Redission

⚡Redission 介绍

Redission 功能介绍

Redission官网

Redisson 是 Redis 服务器上的分布式 可伸缩Java数据结构 ---- 驻内存数据网格(In-Memory Data Grid,IMDG)。底层使用Netty框架,并提供了与 Java 对象相对应的分布式对象、分布式集合、分布式锁和同步器、分布式服务等一系列的 Redisson 的分布式对象

Redission 作为 Redis 官方首推的 Java 客户端, Redission不仅仅是一个客户端,它还实现了很多分布式特性的工具类,例如:分布式锁,布隆过滤器等。

微服务Spring Boot 整合 Redis 分布式锁 Redission 实现优惠卷秒杀 一人一单

Redission 分布式 的特点

微服务Spring Boot 整合 Redis 分布式锁 Redission 实现优惠卷秒杀 一人一单

基于 Redis 的 Java 分布式可重入Lock对象,并实现Lock接口。

如果获取锁的 Redisson 实例崩溃,那么这种锁可能会在获取状态下永远挂起。为了避免这种 Redisson 维护锁看门狗,它会在锁持有者 Redisson 实例处于活动状态时延长锁的过期时间。默认情况下,锁定看门狗超时为 30 秒,可以通过Config.lockWatchdogTimeout设置进行更改。

二、SetNX实现分布式锁的缺点

重入问题:重入是指 获得锁的线程可以再次进入到相同的锁的代码中,可重入锁的目的是为了防止死锁。

不可重试:不可重试是指 目前的分布式锁只能尝试一次,一般合理的情况是,如果第一次获取失败,则进行重试

超时释放:当前的业务中,如果锁到了我们设定的过期释放时间,会直接释放掉,如果卡顿的时间较长,但锁已经被释放了,那这样是不行的。

主从一致性:如果Redis 提供了主从集群,当我们向集群写数据时,主机需要异步的将数据同步给从机,而万一在同步之前,主机宕机了,就会出现死锁问题

以上问题,我们可以通过分布式锁 Redission 来解决。

三、Spring Boot 整合 分布式锁 Redission 实现优惠卷秒杀

引入依赖

<dependency>
	<groupId>org.redisson</groupId>
	<artifactId>redisson</artifactId>
	<version>3.13.6</version>
</dependency>

配置 Redission 客户端

package com.chen.config;

import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @author whc
 */
@Configuration
public class RedissonConfig {

    @Bean
    public RedissonClient redissonClient() {
        // 配置信息
        Config config = new Config();
        //地址、密码
        config.useSingleServer().setAddress("redis://你的ip地址:端口号").setPassword("password");

        return Redisson.create(config);
    }
}

VoucherServiceImpl 实现类注入RedissionClient

@Resource
private RedissonClient redissonClient;

@Override
public Result seckillVoucher(Long voucherId) {
    //1. 查询优惠卷
    SeckillVoucher seckillVoucher = seckillVoucherService.getById(voucherId);
    //2. 判断秒杀是否开始 开始时间大于当前时间表示未开始抢购
    if (seckillVoucher.getBeginTime().isAfter(LocalDateTime.now())) {
        return Result.fail("秒杀尚未开始!");
    }
    //3. 判断秒杀是否结束
    if (seckillVoucher.getEndTime().isBefore(LocalDateTime.now())) {
        return Result.fail("秒杀已经结束!");
    }
    //4. 判断库存是否充足
    if (seckillVoucher.getStock() < 1) {
        return Result.fail("库存不足!");
    }

    //5. 获取当前用户id
    Long userId = UserHolder.getUser().getId();
    //6. 使用Redission 获取锁对象
    RLock lock = redissonClient.getLock("lock:order" + userId);

    //7. 尝试获取锁
    boolean isLock = lock.tryLock();
    if (!isLock) {
        return Result.fail("抢购失败,用户重复下单!");
    }
    try {
        IVoucherOrderService proxy = (IVoucherOrderService) AopContext.currentProxy();
        return proxy.createVoucherOrder(voucherId, userId);
    } finally {
        lock.unlock();
    }
}

四、测试

打开Jmeter,载入jmx文件,进行200压测
微服务Spring Boot 整合 Redis 分布式锁 Redission 实现优惠卷秒杀 一人一单

结果
微服务Spring Boot 整合 Redis 分布式锁 Redission 实现优惠卷秒杀 一人一单

查看数据库
微服务Spring Boot 整合 Redis 分布式锁 Redission 实现优惠卷秒杀 一人一单

测试成功,一人一单 Redission分布式锁 完成!

五、核心源码

Gitee 源码地址

⛵小结

以上就是【Bug 终结者】对 微服务Spring Boot 整合 Redis 分布式锁 Redission 实现优惠卷秒杀 一人一单 的简单介绍,在分布式系统下,高并发的场景下,会出现此类库存超卖问题,本篇文章介绍了采用Redission实现分布式锁来解决,Redission底层就是采用了Lua脚本,生产可用,Redission是不错的分布式工具,Redis Java 客户端!

如果这篇【文章】有帮助到你,希望可以给【Bug 终结者】点个赞????,创作不易,如果有对【后端技术】、【前端领域】感兴趣的小可爱,也欢迎关注❤️❤️❤️ 【Bug 终结者】❤️❤️❤️,我将会给你带来巨大的【收获与惊喜】????????????!