1. HA介绍
HA即High Available,高可用系统,一般来说高可用的概念比较广泛
要真正做到高可用还需要在部署的物理服务器所在位置有要求,高可用总是相对的
比如部署在不同机架上的不同服务器上,可以防止机架断电导致服务器均不可用,但对机房整体故障无法做到高可用
部署在不同机房,可以防止单机房故障,但是如果机房在同一个地区有可能会因为地区网络故障,大面积长期停电而导致服务器无法高可用
部署在不同地区,可以防止单地区故障,但是比如战争导致的多地区断电断网又会导致无服务可用
综上所述,高可用总是相对的,一般来说程序层面的高可用,指一主多从程序,在主系统出现问题时,从系统会变更为主系统提供服务,在下线主机恢复后会自动成为从机等待提供服务
2. zk实现HA原理
首先由于zk是分布式的本身就支持HA
我们可以利用zk的临时节点来作为主节点的标记,成功建立Znode的主机为master
3. 使用zk实现
3.1. 服务端实现
@Component
public class Server implements CommandLineRunner, InitializingBean, ApplicationListener<WebServerInitializedEvent> {
private int port;
private ZooKeeper zk;
@Override
public void run(String... args) throws Exception {
tryToMaster();
}
private void tryToMaster() throws Exception{
InetAddress address = InetAddress.getLocalHost();
String ipPort = address.getHostAddress()+":"+port; //返回IP地址
System.out.println("服务地址"+ipPort);
try{
zk.create("/service", "service".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
}catch (Exception e){
}
try {
zk.create("/service/master", ipPort.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
System.out.println("我成为主节点了");
}catch (Exception e){
// 尝试成为主节点失败 监听节点状态
System.out.println("我是从节点");
zk.exists("/service/master",event->{
System.out.println("ddd");
if(event.getType()== Watcher.Event.EventType.NodeDeleted){
try {
tryToMaster();
}catch (Exception e1){
}
}
});
}
}
@Override
public void afterPropertiesSet() throws Exception {
zk = new ZooKeeper("127.0.0.1:2181", 5000, new Watcher() {
@Override
public void process(WatchedEvent watchedEvent) {
System.out.println("连接成功 ");
}
}, true);
}
@Override
public void onApplicationEvent(WebServerInitializedEvent event) {
this.port = event.getWebServer().getPort();
}
}
3.2. 客户端实现
ublic class Application implements InitializingBean {
private ZooKeeper zk;
@GetMapping("/hello")
public Object hello(){
Stat stat = new Stat();
try {
byte[] data = zk.getData("/service/master", false, stat);
String ipPort = new String(data);
System.out.println(ipPort);
//根据ipPort调用服务器 返回服务器调用结果
return ipPort;
} catch (KeeperException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
public static void main(String[] args) {
SpringApplication.run(Application.class,args);
}
@Override
public void afterPropertiesSet() throws Exception {
zk = new ZooKeeper("127.0.0.1:2181", 5000, new Watcher() {
@Override
public void process(WatchedEvent watchedEvent) {
System.out.println("连接成功 ");
}
}, true);
}
}
用户访问客户端,客户端去zk中获取当前激活的服务器ip端口,然后调用接口把结果返回给用户