一、可恢复的故障
1.网络异常
在生产中,可能因为网络问题导致发起请求后无法得到正确的响应,返回CONNECTIONLOSS返回码,此时应用程序应该先检查请求是否被成功执行,再选择如何处理
switch(Code.get(rc)){ case CONNECTIONLOSS: checkMaster(); return; case OK: isLeader = true; masterExists(); break; case NODEEXISTS: System.out.println("Leader was exists"); masterExists(); default: isLeader = false; }
上面代码表示当发生网络异常时,调用checkMaster()确认之前的请求是否被执行
switch(Code.get(rc)){ case CONNECTIONLOSS: checkMaster(); return; case NONODE: runForMaster(); return; case NODEEXISTS: logger.info("请求已被成功执行"); //doSomething(); }
返回NONODE:之前的请求没有被成功处理,需要重新调用并执行
返回NODEEXISTS:之前的请求已别成功处理,继续执行后续流程
2.资源开销过大导致会话超时
常常因为代码不合理、业务量太大、硬件资源不充足等原因交叉影响导致客户端或者服务端一直没有响应,服务端的会话被置为过期。
2.1客户端原因导致会话过期
出现客户端资源问题导致会话过期,拿主从模式来做解释,当执行任务的客户端出现问题导致会话过期,那么分配任务的主节点需要监听其生存状态,发现过期需具备任务重新分配能力。当客户端恢复过来想重新与ZK通信,ZK会告知其已经被置为过期会话,此时客户端会进行重连,但是会收到SESSIONEXPIRED错误码。
代码:
package zk_01.zookeeper.test;import java.io.IOException;import org.apache.log4j.Logger;import org.apache.zookeeper.AsyncCallback.StringCallback;import org.apache.zookeeper.KeeperException.Code;import org.apache.zookeeper.CreateMode;import org.apache.zookeeper.WatchedEvent;import org.apache.zookeeper.Watcher;import org.apache.zookeeper.ZooDefs;import org.apache.zookeeper.ZooKeeper;import zk_01.zookeeper.sample.MasterUnSyn;public class ClientTimeOut implements Watcher{ static Logger logger = Logger.getLogger(MasterUnSyn.class); ZooKeeper zk; String hostPort; public ClientTimeOut(String hostPort) { this.hostPort=hostPort; } void startZK() throws IOException{ zk = new ZooKeeper(hostPort,5000,this); } public void process(WatchedEvent event) { logger.info(event); } void createNode(String nodeName){ zk.create(nodeName, "myData".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL, createNodeCallback, null); } StringCallback createNodeCallback = new StringCallback(){ public void processResult(int rc, String path, Object ctx, String name) { switch(Code.get(rc)){ case CONNECTIONLOSS: logger.info("网络异常"); break; default: logger.info("code is:"+Code.get(rc)); } } }; public static void main(String[] args) { ClientTimeOut cto = new ClientTimeOut("10.40.20.181:2181"); try { cto.startZK(); Thread.sleep(40000); logger.info("--------------------start---------------"); cto.createNode("/testNode-2"); logger.info("--------------------end---------------"); } catch (IOException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } } }
详细测试方法如下:
1.运行代码
2.查看zk日志
3.在linux机器上添加iptables阻止zk客户端与zk服务端通信
五秒后再执行
4.查看zk日志
当ZK客户端和ZK服务端因为5秒内无法通信,ZK服务端将会话置为过期
当再次打开ZK客户端和ZK服务端通信后,客户端尝试重新建立链接,无法成功
5.查看ZK客户端返回的错误码
错误码为SESSIONEXPIRED
针对这种情况,代码需要重新建立新的链接,获取新的会话ID
public void processResult(int rc, String path, Object ctx, String name) { switch(Code.get(rc)){ case CONNECTIONLOSS: logger.info("网络异常"); break; case SESSIONEXPIRED: startZK(); break; default: logger.info("code is:"+Code.get(rc)); } }
2.2服务端原因导致会话过期
ZK通常是采用仲裁模式部署的,因此当ZK的LEADER发生崩溃,会有其他FOLLOWER成为新的LEADER,接管并掌控整个ZK集群。ZK客户端会自动重连到其他可用的集群,并重新注册监听,接收通知。
二、不可恢复的故障
这一块知识还需要继续学习。。。待补充