ZooKeeper分布式锁原理
核心思想:当客户端要获取锁,则创建节点,使用完锁,则删除该节点。
1.客户端获取锁时,在lock节点下创建临时顺序节点。
2.然后获取lock下面的所有子节点,客户端获取到所有的子节点之后,如果发现自己创建的子节点序号最小,那么就认为该客户端获取到了锁。使用完锁后,将该节点删除。
3.如果发现自己创建的节点并非lock所有子节点中最小的,说明自己还没有获取到锁,此时客户端需要找到比自己小的那个节点,同时对其注册事件监听器,监听删除事件
4.如果发现比自己小的那个节点被删除,则客户端的Watcher会收到相应通知,此时再次判断自己创建的节点是否是lock子节点中序号最小的,如果是则获取到了锁,如果不是则重复以上步骤继续获取到比自己小的一个节点并注册监听。
Curator实现分布式锁API
在Curator中有五种锁方案:
InterProcessSemaphoreMutex:分布式排它锁(非可重入锁)
InterProcessMutex:分布式可更入排它锁
InterProcessReadWriteLock:分布式读写锁
InterProcessMultiLock:将多个锁作为单个实体管理的容器
InterProcessSemaphoreV2:共享信号量
测试分布式锁抢票
一个实体类Ticket12306 一个启动类LockTest
package com.itheima.curator;
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 java.util.concurrent.TimeUnit;
public class Ticket12306 implements Runnable {
private int tickets = 100; //数据库的票数
private InterProcessMutex lock; //锁
public Ticket12306() {
RetryPolicy retry = new ExponentialBackoffRetry(3000, 10);
//2、第二种方式
CuratorFramework client = CuratorFrameworkFactory.builder()
.connectString("192.168.157.9:2181")
.sessionTimeoutMs(60 * 1000)
.connectionTimeoutMs(15 * 1000)
.retryPolicy(retry).build();
//开启连接
client.start();
lock = new InterProcessMutex(client, "/lock");
}
@Override
public void run() {
while (true){
//加锁
try {
lock.acquire(3, TimeUnit.SECONDS);
if (tickets>0){
System.out.println(Thread.currentThread()+":"+tickets);
Thread.sleep(100);
tickets--;
}else {
return;
}
} catch (Exception e) {
e.printStackTrace();
}finally {
//释放锁
try {
lock.release();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
/**
@Override
public void run() {
while (true) {
if (tickets > 0) {
System.out.println(Thread.currentThread() + ":" + tickets);
tickets--;
} else {
return;
}
}
}*/
}
lockTest
package com.itheima.curator;
public class LockTest {
public static void main(String[] args) {
Ticket12306 ticket12306 = new Ticket12306();
//创建客户端
Thread t1 = new Thread(ticket12306,"携程");
Thread t2 = new Thread(ticket12306,"飞猪");
t1.start();
t2.start();
}
}
Zookeeper集群搭建
Zookeeper集群介绍
Leader选举:
Serverid:服务器ID
比如有三台服务器,编号分别是1,2,3。编号越大在选择算法中的权重越大。
Zxid:数据ID
服务器中存放的最大数据ID.值越大说明数据越新在选举算法中数据越新权重越大。
在Leader选举的过程中,如果某台ZooKeeper获得了超过半数的选票,则此ZooKeeper就可以成为Leader了。
Zookeeper集群角色
在ZooKeeper集群服务中有三个角色
Leader领导者:
1.处理事务请求
2.集群内部各服务器的调度者
Follower 跟随者:
1.处理客户端非事务请求,转发事务请求给Leader服务器
2.参与Leader选举投票
Observer 观察者:
1.处理客户端非事务请求,转发事务请求给Leader服务器