目录
什么是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