XXZXGG 2023-03-03 10:27 采纳率: 0%
浏览 21

java zookeeper分布式锁

商品秒杀的业务场景中一般用到锁来解决,但当一线程释放锁时各线程争抢资源会出现羊群效应。
所以下面我使用Zookeeper分布式锁来解决,解决方案及原理如下:

img

  1. 所有请求进来,在/lock下创建 临时顺序节点 ,放心,zookeeper会帮你编号排序
  2. 判断自己是不是/lock下最小的节点
    ①. 是,获得锁(创建节点)
    ②. 否,对前面小我一级的节点进行监听
  3. 获得锁请求,处理完业务逻辑,释放锁(删除节点),后一个节点得到通知(比你年轻的死了,你
    成为最嫩的了)
  4. 重复步骤2

zookeeper客户端的java api没有用curator,用的是原始的没被封装好的zookeeper客户端的依赖jar包:

<dependency>
    <groupId>org.apache.zookeeper</groupId>
    <artifactId>zookeeper</artifactId>
    <version>3.6.0</version>
</dependency>

下面是spring代码实现:
分布式锁主要在Controller层控制:

@Controller
public class OrderController {

    @Autowired
    private OrderService orderService;

    // 集群ip
    static String connectStr = "192.168.1.148,192.168.1.146,192.168.1.188";
    // session连接超时限制
    static private int sessionTimeout = 60000;

    @GetMapping("/buy")
    @ResponseBody
    public Object buy(String id) throws Exception {  //id为商品id
        // 创建监听器
        Watcher watcher = watchedEvent -> {
            if (Watcher.Event.EventType.NodeDeleted.equals(watchedEvent.getType())) {
                try {
                    orderService.buy(id);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        };
        ZooKeeper zooKeeperClient = new ZooKeeper(connectStr,sessionTimeout,watcher);
        System.out.println(zooKeeperClient);
        String s = zooKeeperClient.create("/lock/q", id.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
        List<String> children = zooKeeperClient.getChildren(s, true);
        String delPath = s;
        if (children != null) {
            if (children.size() > 0) {
                children.sort((o1, o2) -> {
                    String substring1 = o1.substring(o1.length() - 5);
                    String substring2 = o2.substring(o2.length() - 5);
                    return Integer.parseInt(substring1) - Integer.parseInt(substring2);
                });
                delPath = children.get(0);
            }
        }
        zooKeeperClient.delete(delPath,0);
        return "ok";
    }
}


service主要实现业务,减库存,里面有逻辑判断库存小于0就抛异常,没有则新增订单:

@Service
public class OrderServiceImpl implements OrderService {

    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private ProductMapper productMapper;

    @Override
    public void buy(String productId) throws Exception{
        Product product = productMapper.selectProductById(Integer.parseInt(productId));
        Thread.sleep(1000);  //模拟大量业务处理的延迟
        if (product.getStock() <= 0) {
            throw new Exception("商品已抢光");
        }
        int affectRows = productMapper.reduceProduct(Integer.parseInt(productId));
        if (affectRows == 1) {
            Order order = new Order();
            order.setId(UUID.randomUUID().toString());
            order.setPid(Integer.parseInt(productId));
            order.setUserid(101);   //为测试方便,userid字段随便写死的
            orderMapper.create(order);
        } else {
            throw new Exception("新增订单失败!");
        }
    }
}

测试过程:在三台zookeeper服务器都正常启动的情况下,在数据库某商品的库存设置成5,然后用jmeter并发请求,1秒请求50次,最后结果是控制台有打印商品已抢光的Excetion栈信息,但数据库该商品的库存变成负数-45。

想请教下是哪里出问题了?

  • 写回答

2条回答 默认 最新

  • 远控源码 2023-03-03 10:58
    关注

    是不是光\只解决了并发,但是库存那边需要设置,当最后一件商品被扣完的时候,整个秒杀状态需要停止.

    评论

报告相同问题?

问题事件

  • 创建了问题 3月3日

悬赏问题

  • ¥15 CBF预处理数据归一化的时候报错了如下图
  • ¥15 qt 转 msvc 后 Opencv 始终打不开视频!
  • ¥15 yolo v5中labelimg的作用
  • ¥30 VBA网抓application/json的网抓怎么写!
  • ¥15 国赛c题2021,没有理解这一串代码的意思,这样报错该怎么解决(语言-matlab)
  • ¥15 一、执行完中断程序后如何继续运行,二、中断结束后如何跳过中断触发前的点位(LOW点不要继续运行,可以运行UP点)(关键词-程序运行)
  • ¥15 if为什么跳过if 直接执行else 中文
  • ¥200 解决登录微信老版本限制封号问题
  • ¥15 mysql中时间处理问题
  • ¥20 讲解此音频放大电路原理及关键部分