订阅发布(配置中心)
watch机制
统一配置管理(disconf),一般有两种方式:pull和push,zookeeper使用的是两者相结合的方式,客户端向服务器端注册自己要关注的节点,一旦节点数据发生变化,那么服务器端向客户端发送watcher事件通知,客户端收到通知后,主动向服务器端获取最新的数据。
配置特点:数据量比较小、数据在运行时会发生动态变更、集群共享配置
分布式锁
1、redis:setnx,使用redis提供的命令实现
2、数据库:创建一个表,通过索引唯一的方式,比如一个表
create table(id,methodname…)在methodname增加唯一索引,多个应用访问统一节点时,先在表里insert一条数据,xxx,其他客户端再插入时,索引重复。当使用完后,delete掉。
mysql中的 for update可以行级锁,也称独占锁,效率比较低。
3、zookeeper:利用临时有序节点和watch机制
分布式锁是进程之间的控制
排它锁(写锁)
利用zookeeper同一目录下节点名称唯一性实现。
A、B、C同时往一个目录下写一个名称一样的临时接点,能创建成功的可以拿到锁。
共享锁(读锁)
利用有序临时节点,所有客户端往里面去写节点,每一个客户端写节点后,最小的节点有优先级去获取数据。通过顺序性去控制共享锁,共享锁里可以包含写和读。
package DistrubuteLock.javaapi;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.ZooDefs;
import org.apache.zookeeper.ZooKeeper;
import java.io.IOException;
import java.util.List;
import java.util.Random;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
public class DistrubuteLockDemo {
private static final String ROOT_LOCKS="/LOCKS";
private ZooKeeper zookeeper;
private int sessionTimeOut;//回话超时时间
private String lockId; //记录节点id
private static final byte[] data={1,2};
private CountDownLatch countDownLatch = new CountDownLatch(1);
public DistrubuteLockDemo() throws IOException, InterruptedException {
this.zookeeper = ZookeeperClient.getInstance();
this.sessionTimeOut = ZookeeperClient.getSessionTimeOut();
}
//获取锁的方法
public boolean lock() throws KeeperException, InterruptedException {
//每个客户端都会创建一个临时有序节点
lockId = zookeeper.create(ROOT_LOCKS+"/",data, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
System.out.println(Thread.currentThread().getName()+"成功创建了LOCK节点,节点ID为:["+lockId+"],开始去竞争锁。");
List<String> childrenNodes = zookeeper.getChildren(ROOT_LOCKS,true);
//从小到大排序
SortedSet<String> sorted = new TreeSet<>();
for (String children:childrenNodes) {
sorted.add(children);
}
String first = sorted.first();
if(lockId.equals(first)){
//表示当前就是最下的,意味着获取锁了
System.out.println(Thread.currentThread().getName()+"->成功获得锁,lock节点为:" +lockId);
return true;
}
SortedSet<String> lessThenLockId = sorted.headSet(lockId);
if(!lessThenLockId.isEmpty()){
String preLockId = lessThenLockId.last();
zookeeper.exists(preLockId,new LockWatcher(countDownLatch));
countDownLatch.await(sessionTimeOut, TimeUnit.MICROSECONDS);
//上面这段代码意味着回话超时,或者节点被删除,就可以获取锁
System.out.println(Thread.currentThread().getName()+"成功获取锁,LOCKID:"+lockId);
return true;
}
return false;
}
//释放锁操作
public boolean unlock() {
System.out.println(Thread.currentThread().getName()+"->开始释放锁:["+lockId+"]");
try {
zookeeper.delete(lockId,-1);
System.out.println("LOCKID:"+lockId+"成功释放。");
return true;
} catch (InterruptedException e) {
e.printStackTrace();
} catch (KeeperException e) {
e.printStackTrace();
}
return false;
}
public static void main(String[] args) {
CountDownLatch countDownLatch = new CountDownLatch(10);
Random random = new Random();
for (int i =0;i<10;i++){
new Thread(()->{
DistrubuteLockDemo lock = null;
try {
lock = new DistrubuteLockDemo();
countDownLatch.countDown();
countDownLatch.await();
lock.lock();
Thread.sleep(random.nextInt(500));
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (KeeperException e) {
e.printStackTrace();
}finally {
if(lock!=null){
lock.unlock();
}
}
}).start();
}
}
}
负载均衡
ID生成器
分布式队列
分布式队列:有先进先出、Barrier模式(围栏模式)。
先进先出
先进先出利用有序节点,和分布式锁原理一样,通过getChild获取节点下所有子元素,子节点就是要执行的任务,如果自己不是最小的节点,那么监控比自己小的上一个节点,否则处于等待。接收watch通知,重复该流程。
Barrier模式
在先进先出的基础上增加一个number作为触发条件。
统一命名服务
master选举
curator实现
LeaderLatch
写一个master
LeaderSelector
每一个应用写一个临时有序节点,根据最小节点来获取优先权
package MasterSlaveCurator;
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.LeaderSelectorListenerAdapter;
import org.apache.curator.retry.ExponentialBackoffRetry;
import java.util.concurrent.TimeUnit;
public class MasterSlaveCurator {
private final static String CONNECT_STRING = "192.168.36.128:2181,192.168.36.129:2181,192.168.36.130:2181";
public static void main(String[] args) {
CuratorFramework curatorFramework = CuratorFrameworkFactory.builder().connectString(CONNECT_STRING).
retryPolicy(new ExponentialBackoffRetry(1000, 3)).build();
LeaderSelector leaderSelector = new LeaderSelector(curatorFramework, CONNECT_STRING, new LeaderSelectorListenerAdapter() {
@Override
public void takeLeadership(CuratorFramework curatorFramework) throws Exception {
//获得leader成功
TimeUnit.SECONDS.sleep(1);
}
});
//自动选举
leaderSelector.autoRequeue();//自动争抢
leaderSelector.start();
}
}