基于ZooKeeper的分布式锁——抢购书本

简要

记录一个小项目,通过ZooKeeper加锁实现并发控制。

config层

@Configuration
public class CuratorConfig {
    @Autowired
    private Environment env;

    @Bean
    public CuratorFramework curatorFramework() {
        CuratorFramework curatorFramework =
                CuratorFrameworkFactory.builder().
                        connectString(env.getProperty("zk.host")).
                        namespace(env.getProperty("zk.namespace")).
                        retryPolicy(new RetryNTimes(5, 1000)).build();
        curatorFramework.start();
        return curatorFramework;
    }

}

controller层

@RestController
public class BookRobController {

    //定义日志
    private static final Logger log= LoggerFactory.getLogger(BookRobController.class);
    //定义请求前缀
    private static final String prefix="book/rob";

    //定义核心逻辑处理器服务类 不加锁
    @Autowired
    private BookRobService bookRobService;


    @RequestMapping(value=prefix+"/request",method= RequestMethod.GET)
    public BaseResponse takeMoney(BookRobDto dto){
        //校验参数的合法性
        if(Strings.isNullOrEmpty(dto.getBookNo())|| dto.getUserId()==null||dto.getUserId()<=0){
            return new BaseResponse(StatusCode.InvalidParams);

        }
        BaseResponse baseResponse=new BaseResponse(StatusCode.Success);
        try {
            bookRobService.robWithZKLock(dto);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return baseResponse;
    }
}

dto层

@Data
@ToString
public class BookRobDto implements Serializable {
    private Integer userId;

    private String bookNo;
}

mapper和model层

使用mybatis生成代码

service层

@Service
public class BookRobService {

    //定义日志实例
    private static final Logger log = LoggerFactory.getLogger(BookRobService.class);
    //定义书籍库存实体操作接口Mapper实例
    @Autowired
    private BookStockMapper bookStockMapper;
    //定义书籍抢购实体操作接口Mapper实例
    @Autowired
    private BookRobMapper bookRobMapper;

    //定义Zookeeper客户端CuratorFramework实例
    @Autowired
    private CuratorFramework client;
    //Zookeeper分布式锁的实现原则是由ZNode节点的创建,删除与监听器构成的
    //而ZNode节点将对应一个具体的路径-根Unix文件路径类似-需要以/开头
    private static final String pathPrefix = "/zkLock/";


    /**
     * 处理书籍抢购逻辑-加Zookeeper分布式锁
     *
     * @param dto
     */
    @Transactional(rollbackFor = Exception.class)
    public void robWithZKLock(BookRobDto dto) throws Exception {
        InterProcessMutex interProcessMutex = new InterProcessMutex(client, pathPrefix + dto.getBookNo() + dto.getUserId() + "---lock");
        //获取锁
        try {
            if (interProcessMutex.acquire(20, TimeUnit.SECONDS)) {

                //看此书是否还存在
                BookStock bs = bookStockMapper.selectByBookNo(dto.getBookNo());
                //此人是否已经抢过了
                int total = bookRobMapper.countByBookNoUserId(dto.getUserId(), dto.getBookNo());
                if (bs != null && bs.getStock() > 0 && total <= 0) {
                    int res = bookStockMapper.updateStock(dto.getBookNo());
                    if (res > 0) {
                        //增加用户抢购记录
                        BookRob rob = new BookRob();

                        BeanUtils.copyProperties(dto, rob);

                        rob.setRobTime(new Date());

                        bookRobMapper.insertSelective(rob);
                    }
                }
            } else {
                log.error("--------获取Zookeeper分布式锁失败!!");
                throw new RuntimeException("获取Zookeeper分布式锁失败!");

            }
        } catch (Exception e) {
            log.error("--------获取Zookeeper分布式锁失败!!{}----------", e.getMessage());
        } finally {
            //不管发生何种情况 在处理完核心业务逻辑之后,需要释放该分布式锁
            interProcessMutex.release();
        }

    }
}

util

public class BaseResponse<T> {
    //状态码
    private Integer code;
    //描述信息
    private String msg;
    //响应数据-采用泛型表示可以接受通用的数据类型
    private T data;
    //重载的构造方法一
    public BaseResponse(Integer code, String msg) {
        this.code = code;
        this.msg = msg;
    }
    //重载的构造方法二
    public BaseResponse(StatusCode statusCode) {
        this.code = statusCode.getCode();
        this.msg = statusCode.getMsg();
    }
    //重载的构造方法三
    public BaseResponse(Integer code, String msg, T data) {
        this.code = code;
        this.msg = msg;
        this.data = data;
    }

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }
}
public enum StatusCode {
    //以下是暂时设定的几种状态码类
    Success(0,"成功"),
    Fail(-1,"失败"),
    InvalidParams(201,"非法的参数!"),
    InvalidGrantType(202,"非法的授权类型");

    //状态码
    private Integer code;
    //描述信息
    private String msg;
    //重载的构造方法
    StatusCode(Integer code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }
}

过程

  1. 开启ZooKeeper
    List item
  2. 开启spring
    在这里插入图片描述
  3. 使用jmeter高并发请求
    在这里插入图片描述
    在这里插入图片描述
    user.csv文件内容:
    在这里插入图片描述
    现在6个人抢购10本书。
    未加锁:
    在这里插入图片描述
    加锁:
    在这里插入图片描述
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
当面试中涉及到ZooKeeper分布式锁的问题,通常会涉及以下几个方面: 1. 什么是ZooKeeper分布式锁ZooKeeper分布式锁是基于ZooKeeper提供的原语实现的一种分布式锁机制。它利用了ZooKeeper的有序临时节点和Watcher机制来实现锁的竞争和释放。 2. ZooKeeper分布式锁的实现原理是什么? ZooKeeper分布式锁的实现原理主要依赖于ZooKeeper的有序临时节点和Watcher机制。当一个线程需要获取锁时,它会在ZooKeeper的指定路径上创建一个有序临时节点,并且注册一个Watcher来监听前一个节点是否存在。如果前一个节点不存在,则该线程获取锁成功;否则,该线程需要等待前一个节点被删除后继续竞争锁。 3. ZooKeeper分布式锁存在的问题有哪些? ZooKeeper分布式锁虽然实现了基本的锁机制,但仍然存在以下问题: - 网络延迟:由于网络延迟等原因,可能导致锁的竞争时间增加,影响系统的性能。 - 节点故障:如果持有锁的节点发生故障,可能导致其他节点无法获取锁或长时间等待。 - 死锁:如果在获取锁的过程中发生故障或异常,可能导致死锁情况的发生。 4. 如何解决ZooKeeper分布式锁的问题? 为了解决ZooKeeper分布式锁存在的问题,可以采取以下策略: - 设置合理的超时时间,避免长时间等待导致系统性能下降。 - 使用心跳机制来检测节点的存活状态,及时处理节点故障。 - 采用分布式协调框架或工具,如Curator、Spring Integration等,简化分布式锁的使用和管理。 这些是一些常见的ZooKeeper分布式锁面试题及其答案,希望能对你有所帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值