分布式锁(三)基于zookeeper的分布式锁实现

什么是Zookeeper?

1.Zookeeper介绍

Zookeeper(业界简称zk)是一种提供配置管理、分布式协同以及命名的中心化服务,这些提供的功能都是分布式系统中非常底层且必不可少的基本功能,但是如果自己实现这些功能而且要达到高吞吐、低延迟同时还要保持一致性和可用性,实际上非常困难。因此zookeeper提供了这些功能,开发者在zookeeper之上构建自己的各种分布式系统。
Zookeeper提供一个多层级的节点命名空间(节点称为znode),每个节点都用一个以斜杠(/)分隔的路径表示,而且每个节点都有父节点(根节点除外),非常类似于文件系统。例如,/foo/doo这个表示一个znode,它的父节点为/foo,父父节点为/,而/为根节点没有父节点。与文件系统不同的是,这些节点都可以设置关联的数据,而文件系统中只有文件节点可以存放数据而目录节点不行。Zookeeper为了保证高吞吐和低延迟,在内存中维护了这个树状的目录结构,这种特性使得Zookeeper不能用于存放大量的数据,每个节点的存放数据上限为1M。
有序性是zookeeper中非常重要的一个特性,所有的更新都是全局有序的,每个更新都有一个唯一的时间戳,这个时间戳称为zxid(Zookeeper Transaction Id)。而读请求只会相对于更新有序,也就是读请求的返回结果中会带有这个zookeeper最新的zxid。

2.Zookeeper服务端

Zookeeper服务端集群搭建https://blog.csdn.net/Z_Vivian/article/details/101291716

Zookeeper服务端而为了保证高可用,zookeeper需要以集群形态来部署,只要集群中一半以上的机器可用,那么zookeeper集群仍然可用。客户端在使用zookeeper时,需要知道集群机器列表,通过与集群中的某一台机器建立TCP连接来使用服务,客户端使用这个TCP长连接来发送请求、获取结果、获取监听事件以及发送心跳包。如果这个连接异常断开了,客户端可以连接到另外的机器上。

3.Zookeeper客户端

客户端的读请求可以被集群中的任意一台机器处理,如果读请求在节点上注册了监听器,这个监听器也是由所连接的zookeeper机器来处理。对于写请求,这些请求会同时发给其他zookeeper机器并且达成一致后,请求才会返回成功。因此,随着zookeeper的集群机器增多,读请求的吞吐会提高但是写请求的吞吐会下降。

zookeeper分布式锁的使用

项目github地址:https://github.com/ZiXinZhu/zookeeper
下面是基于curator开源项目提供的zookeeper分布式锁实现

1.配置pom.xml文件

        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-recipes</artifactId>
            <version>4.0.0</version>
        </dependency>

2.测试类ZooKeeperLockController

import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.locks.InterProcessMutex;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ZooKeeperLockController {
    @Autowired
    RedisTemplate<String, Object> redisTemplate;

    @GetMapping("/zk/sell")
    public String zookeeper_lock() throws Exception {

        //创建zookeeper的客户端
        RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);
        CuratorFramework client = CuratorFrameworkFactory.newClient(IP, retryPolicy);
        client.start();
        //创建分布式锁, 锁空间的根节点路径为/zk-provider/lock
        InterProcessMutex mutex = new InterProcessMutex(client, "/zk-provider/lock");
        mutex.acquire();
        //获得了锁, 进行业务流程
        int stock = Integer.parseInt(String.valueOf(redisTemplate.opsForValue().get("zzx")));
        if (stock > 0) {
            redisTemplate.opsForValue().set("zzx", (stock - 1) + "");
            System.out.println("结果:" + (stock - 1));
        }else {
            System.out.println("商品已售完!");
        }
        //完成业务流程, 释放锁
        mutex.release();
        //关闭客户端
        client.close();
        return "success";
    }
}

3.分别在两个zookeeper客户端测试

这里我使用了jmeter压力测试工具分别请求两个应用结果如下:
在这里插入图片描述
在这里插入图片描述
可以看到上面已经实现了分布式锁,这里只是简单的zookeeper实现,要研究其源码,请参考下面这个老哥的博客。
https://blog.csdn.net/qiangcuo6087/article/details/79067136

发布了55 篇原创文章 · 获赞 23 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/Z_Vivian/article/details/102562919