分布式锁
分布式编程时,当遇到应用程序多机部署,于是当多个应用同时访问某一资源时,就需要某种机制去协调它们进行占用。例如,现在一台应用正在rebuild缓存内容,要临时锁住这个区域暂时不让其它应用进行访问;又比如调度程序每次只想一个任务被一台应用执行等等业务场景。
下面的程序会启动两个线程x1和x2去争夺锁,拿到锁的线程会占用10秒。运行多次可以观察到,有时是x1先拿到锁而x2等待,有时又会反过来。Curator会用我们提供的lock路径的结点作为全局锁,这个结点的数据类似这种格式:[_xxxxxx-lock-0000000005],每次获得锁时会生成这种串,释放锁时清空数据。
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.RetryNTimes;
import java.util.concurrent.TimeUnit;
/**
* @Title: Spring-distributed
* @Description:
* @author: liaryank
* @Date: 2020/5/7 1:32 下午
* @Version: 1.0
*/
public class CuratorLock {
/** Zookeeper info 可以写上端口如果是默认的不写也可以,写就就是192.168.3.32:2181,xxx*/
private static final String ZK_ADDRESS = "192.168.3.32,192.168.3.33,192.168.3.34";
private static final String ZK_LOCK_PATH = "/zklocktest";
public static void main(String[] args) throws InterruptedException {
// 1.Connect to zk
CuratorFramework client = CuratorFrameworkFactory.newClient(
ZK_ADDRESS,
//设置数量和释放时间
new RetryNTimes(10, 10000)
);
client.start();
System.out.println("zookeeper-client-start=>ok!");
Thread x1 = new Thread(() -> {
doWithLock(client);
}, "x1");
Thread x2 = new Thread(() -> {
doWithLock(client);
}, "x2");
t1.start();
t2.start();
}
private static void doWithLock(CuratorFramework client) {
InterProcessMutex lock = new InterProcessMutex(client, ZK_LOCK_PATH);
try {
if (lock.acquire(10 * 1000, TimeUnit.SECONDS)) {
System.out.println(Thread.currentThread().getName() + " holdlock");
Thread.sleep(5000L);
System.out.println(Thread.currentThread().getName() + " releaselock");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
lock.release();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
Leader选举
当集群里的某个服务宕机或故障时,我们可能要从follower结点里选出一个作为新的master,这时就需要能在分布式环境中自动协调的Leader选举方法。Curator提供了LeaderSelector监听器实现Leader选举功能。同时,只有一个Listener会进入takeLeadership()方法,说明它是当前的Leader。
当Listener从takeLeadership()退出时就说明它放弃了“Leader身份”,这时Curator会利用Zookeeper再从剩余的Listener中选出一个新的Leader。autoRequeue()方法使放弃Leadership的Listener有机会重新获得Leadership,如果不设置的话放弃了的Listener是不会再变成Leader的
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.leader.LeaderSelector;
import org.apache.curator.framework.recipes.leader.LeaderSelectorListener;
import org.apache.curator.framework.state.ConnectionState;
import org.apache.curator.retry.RetryNTimes;
import org.apache.curator.utils.EnsurePath;
/**
* @Title: Spring-distributed
* @Description:
* @author: liaryank
* @Date: 2020/5/7 3:50 下午
* @Version: 1.0
*/
public class CuratorLeader {
/** Zookeeper info 可以写上端口如果是默认的不写也可以*/
private static final String ZK_ADDRESS = "192.168.3.32,192.168.3.33,192.168.3.34";
private static final String ZK_PATH = "/zklocktest";
public static void main(String[] args) throws InterruptedException {
LeaderSelectorListener listener = new LeaderSelectorListener() {
@Override
public void takeLeadership(CuratorFramework client) throws Exception {
System.out.println(Thread.currentThread().getName() + " take=》leadership!");
Thread.sleep(5000L);
System.out.println(Thread.currentThread().getName() + " relinquish=》leadership!");
}
@Override
public void stateChanged(CuratorFramework client, ConnectionState state) {
}
};
new Thread(() -> {
registerListener(listener);
}).start();
new Thread(() -> {
registerListener(listener);
}).start();
new Thread(() -> {
registerListener(listener);
}).start();
Thread.sleep(Integer.MAX_VALUE);
}
private static void registerListener(LeaderSelectorListener listener) {
CuratorFramework client = CuratorFrameworkFactory.newClient(
ZK_ADDRESS,
new RetryNTimes(10, 10000)
);
client.start();
//Ensure path
try {
new EnsurePath(ZK_PATH).ensure(client.getZookeeperClient());
} catch (Exception e) {
e.printStackTrace();
}
//Register listener
LeaderSelector selector = new LeaderSelector(client, ZK_PATH, listener);
selector.autoRequeue();
selector.start();
}
}
就先写到这里~~~