zookeeper简单介绍及API使用

1.1 zookeeper简介

zookeeper是一个针对大型分布式系统的可靠的协调系统,提供的功能包括配置维护、名字服务、分布式同步、组服务等。zookeeper可以集群复制,集群间通过zab协议来保持数据的一致性。该协议包括两个阶段:leader election阶段和Atomic broadcas阶段。

leader election阶段:集群间选举出一个leader,其他的机器则称为follower,所有的写操作都被传送给leader,并通过broadcas将所有的更新告诉follower,当leader崩溃或leader失去大多数的follower时,需要重新选举出一个新的leader,让所有的服务器都恢复到一个正确的状态。当leader被选举出来且大多数服务器完成了和leader的状态同步后,leader election过程结束,进入Atomic broadcas阶段。

Atomic broadcas阶段:Atomic broadcas同步leader和follower之间的信息,保证二者具有相同的系统状态。

zookeeper的协作过程简化了松散耦合系统之间的交互,即使参与者彼此不知道对方的存在,也能够相互发现并且完成交互。

1.2 zookeeper API简单使用

可以认为zookeeper是一个小型的、精简的文件系统,它的每个节点称为znode,znode除了本身能够包含一部分数据之外,还能拥有子节点,当节点或子节点数据发生变化时,基于watcher机制,会发出相应的通知给订阅其状态变化的客户端。

1.2.1 zookeeper节点创建

maven项目中引入模块:

<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.6</version>
</dependency>

创建zookeeper对象和节点:

     public static void main(String[] args) throws Exception {
/*
* 127.0.0.1:2181:服务器地址
* 10:超时时间
* watcher:若包含boolean watch的读方法中传入true,则将默认watcher注册为所关注事件的watcher
* 若传入false,则不注册任何watcher。此处暂且定为空
*/
ZooKeeper zookeeper = new ZooKeeper("127.0.0.1:2181", 10, null);
/*
* 若创建的节点已经存在,则会抛出异常
* /root:节点路径 ; root data:路径包含的字节数据
* Ids.OPEN_ACL_UNSAFE:访问权限
* CreateMode.PERSISTENT:节点类型
*/
zookeeper.create("/root", "root data".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
/*
* 设置节点数据
* -1:版本号;若匹配不到响应的节点则会抛出异常
*/
zookeeper.setData("/root", "hello".getBytes(), -1);
/*
* 读取节点数据
* stat是节点状态参数,读取时会传出该节点当前状态信息
*/
Stat stat = new Stat();
byte[] data = zookeeper.getData("/root", false, stat);
System.out.println(new String(data));
/*
* 添加子节点,若父节点不存在会抛出异常
*/
zookeeper.create("/root/child", "child data".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
/*
* 判断节点是否存在,不存在则返回的stat为null
*/
Stat existsStat = zookeeper.exists("/root/child", false);
System.out.println(existsStat);
/*
* /root/child:删除节点路径
* -1:节点的版本号;若设置为-1,则匹配所有版本,zookeeper会比较删除的版本和服务器版本是否一致,不一致会抛出异常
*/
zookeeper.delete("/root/child", -1);
}

实际运行中最常出现这个错误:

Exception in thread "main" org.apache.zookeeper.KeeperException$ConnectionLossException: KeeperErrorCode = ConnectionLoss for /root
at org.apache.zookeeper.KeeperException.create(KeeperException.java:90)
at org.apache.zookeeper.KeeperException.create(KeeperException.java:42)
at org.apache.zookeeper.ZooKeeper.create(ZooKeeper.java:643)
at com.project.soa.zookeeper.ZookeeperDemo.main(ZookeeperDemo.java:12)

这是因为还未连接上zookeeper就开始添加、删除节点等操作,为避免这种情况发生,可以在做操作时对连接状态做判断:

 ZooKeeper zookeeper = new ZooKeeper("127.0.0.1:2181", 10, null);
if (zookeeper.getState() == States.CONNECTED) { }

1.2.2 watcher的实现

节点的状态发生变化,可以通过zookeeper的watcher机制让客户端取得通知。watcher的实现较为简单,只需实现org.apache.ZooKeeper.Watcher接口即可,其中节点的状态变化包含以下几种状态:

注意:watcher机制是一次性的,每次处理完状态变化事件之后需重新注册watcher。这也导致在处理事件和重新加上watcher这段时间发生的节点状态无法被感知。

1.2.3 zkClient的使用

zkClient解决了watcher的一次性注册问题,将znode的事件重新定义为子节点的变化、数据的变化、连接及状态的变化三类,watcher执行后重新读取数据的同时再注册相同的watcher。在异常发生时zkClient会自动创建新的zookeeper实例进行重连,此时原来的watcher节点都将失效,可在zkClient定义的连接状态变化的接口中进行相应处理。同时zkClient还提供了序列化和反序列化接口ZkSerializer,简化了znode上对象的存储。

maven中引入zkClient模块:

<dependency>
<groupId>com.github.sgroschupf</groupId>
<artifactId>zkclient</artifactId>
<version>0.1</version>
</dependency> 简单事例:
     public static void main(String[] args) {
ZkClient zkClient = new ZkClient("192.168.146.132:2181");
String path = "/root";
zkClient.createPersistent(path);
zkClient.create(path + "/child", "znode child", CreateMode.EPHEMERAL);
List<String> children = zkClient.getChildren(path);
System.out.println(children);
int countChildren = zkClient.countChildren(path);
System.out.println(countChildren);
System.out.println(zkClient.exists(path));
zkClient.writeData(path + "/child", "hello everyone");
Object data = zkClient.readData(path + "/child");
System.out.println(data);
zkClient.delete(path + "/child"); //订阅数据的变化
zkClient.subscribeDataChanges(path, new IZkDataListener() { public void handleDataDeleted(String arg0) throws Exception { } public void handleDataChange(String arg0, Object arg1) throws Exception { }
}); //订阅子节点的变化
zkClient.subscribeChildChanges(path, new IZkChildListener() { public void handleChildChange(String arg0, List<String> arg1) throws Exception { }
}); zkClient.subscribeStateChanges(new IZkStateListener() { public void handleStateChanged(KeeperState arg0) throws Exception { } public void handleNewSession() throws Exception {
// 在这里可以进行异常发生时节点失效的容错处理 }
});
}

1.2.4 路由和负载均衡

当服务规模变大时,服务之间的依赖变得十分复杂,这时我们不仅需要了解服务提供方,还需要了解服务消费方以了解服务的调用情况,可以以此作为服务扩容或下线的依据。

服务消费者获取服务提供者地址列表的部分代码为:

     List<String> serverList;

     public List<String> getServerList() {
serverList = new ArrayList<String>();
String serviceName = "server - A";
String serviceString = "127.0.0.1:2181";
String path = "/config/" + serviceName;
ZkClient zkClient = new ZkClient(serviceString);
if (zkClient.exists(path)) {//服务存在则取地址列表
serverList = zkClient.getChildren(path);
} else {
throw new RuntimeException();
}
// 注册监听事件
zkClient.subscribeChildChanges(path, new IZkChildListener() { public void handleChildChange(String s, List<String> list) throws Exception {
serverList = list;
}
});
return serverList;
}

先取得服务上所注册的包含服务提供者地址的子节点,取得服务器地址列表后便可根据负载均衡算法选取调用服务器,服务器列表还存在本地以降低网络开销。注册监听器来感知服务器上线、下线和宕机事件,若发生节点改动,则将监听方法中取得的最新子节点赋给当前的serverList。

服务提供者向zookeeper注册服务:

         String path = "/config";
String serverList = "127.0.0.1:2181";
String serverName = "server";
ZkClient zkClient = new ZkClient(serverList);
if (!zkClient.exists(path)) {
zkClient.createPersistent(path);//创建根节点
}
if (zkClient.exists(path + "/" + serverName)) {
zkClient.createPersistent(path + "/" + serverName);//创建服务节点
}
//注册当前服务器
InetAddress addr = InetAddress.getLocalHost();
//取得本机ip
String ip = addr.getHostAddress().toString();
//创建当前服务器节点
zkClient.createPersistent(path + "/" + serverName + "/" + ip);

这样只有当配置信息更新时服务消费者才会去获取最新的服务地址列表,其他时候使用本地缓存即可,这样能大大降低配置中心的压力。

1.3 HTTP服务网关

移动互联网的崛起出现了多平台的现状,同样的功能厂商需根据不同平台开发不同的APP,使得开发成本增高。而由于客户端APP、第三方ISV(独立软件开发商)应用都必须经过公共网络来发起客户端请求,网关(gateway)作用得以凸显。gateway接收外部各种APP的请求,经过一系列权限与安全校验等,根据服务名到对应配置中心选取服务器列表,再由负载均衡算法选取一台服务器进行调用,将结果返回给客户端。

gateway可以拦截一系列恶意请求,而且能使不同的平台共用重复的逻辑,降低开发和运维成本。但由于gateway是整个网络的核心节点,一旦失效,依赖它的所有外部APP都将无法使用,因此在设计之初应该考虑到系统流量的监控和容量的规划,以便在达到峰值时能够快速进行系统扩容。

上图是一种网关集群的架构方案,一组对等的服务器组成网关集群接收外部HTTP请求,当流量达到警戒值,能方便地增加机器进行扩容。网关前有两台负载均衡设备负责对网关集群进行负载均衡,设备间进行心跳检测,一旦其中一台宕机,另一台则变更自己的地址接管宕机设备,平时这两台机器均对外提供服务。

面向服务的体系架构 SOA(三) --- Zookeeper API、zkClient API的使用的更多相关文章

  1. 面向服务的体系架构SOA

    面向服务的体系架构SOA 序言 在.Net的世界中,一提及SOA,大家想到的应该是Web Service,WCF,还有人或许也会在.NET MVC中的Web API上做上标记,然后泛泛其谈! 的确,微 ...

  2. 说说面向服务的体系架构SOA

    序言 在.Net的世界中,一提及SOA,大家想到的应该是Web Service,WCF,还有人或许也会在.NET MVC中的Web API上做上标记,然后泛泛其谈! 的确,微软的这些技术也确实推动着面 ...

  3. 面向服务的体系架构 SOA(二) --- 服务的路由和负载均衡

    2. 服务的路由和负载均衡 1.2.1 服务化的演变 SOA设计思想:分布式应用架构体系对于业务逻辑复用的需求十分强烈,上层业务都想借用已有的底层服务来快速搭建更多.更丰富的应用,降低新业务开展的人力 ...

  4. 分布式架构设计(一) --- 面向服务的体系架构 SOA

    1.1 基于TCP协议的RPC 1.1.1 RPC名词解释 RPC的全称是Remote Process Call,即远程过程调用,RPC的实现包括客户端和服务端,即服务调用方和服务提供方.服务调用方发 ...

  5. SOA——面向服务的体系架构

    上一篇博文中提到了"紧耦合"的现象.怎样解决?SOA.採用面向服务的体系架构. 一.What? SOA=Service-oriented Architecture面向服务的体系结构 ...

  6. 面向服务的体系架构(SOA)

    面向服务的体系架构(SOA) 1.面向服务的体系架构(SOA) 面向服务的架构(service-oriented architecture)是Gartner于2O世纪9O年代中期提出的面向服务架构的概 ...

  7. 大型分布式架构设计与实现-第一章SOA(面向服务的体系架构)

    拜读了大型分布式架构设计与实现,觉得该书作为入门不错,但内容过于简单,描述过于琐碎,小节之间连续性不强,不适合深入钻研学习.但为了更多的希望向架构师行业靠拢的工程师学习需要,本博客将对上书进行简化讲解 ...

  8. 设计模式之 SOA面向服务的体系

    SOA英文直译是,面向服务的体系结构. SOA是一种设计方法,其中包含多个服务,而服务之间通过配合最终会提供一系列功能.一个服务通常以独立的形式存在于操作系统进程中. 想要看到更多玮哥的学习笔记.考试 ...

  9. 微服务指南走北(三):Restful API 设计简述

    API的定义取决于选择的IPC通信方式,假设是消息机制(如 AMQP 或者 STOMP).API则由消息频道(channel)和消息类型.假设是使用HTTP机制,则是基于请求/响应(调用http的ur ...

随机推荐

  1. Java版2048

    功能要求:2048的基本界面,能够实现2048的游戏功能. 总思路:两个类:Game和GameListener. Game负责界面的实现和paint方法的重写 GameListener负责实现键盘和鼠 ...

  2. MFC: 获得关机消息;阻止Windows关机

    WM_QUERYENDSESSION消息是Windows向你询问Windows能否关闭,WM_ENDSESSION消息表示提示你Windows即将关闭.故当应用程序退出时, WM_QUERYENDSE ...

  3. R语言︱噪声数据处理、数据分组——分箱法(离散化、等级化)

    每每以为攀得众山小,可.每每又切实来到起点,大牛们,缓缓脚步来俺笔记葩分享一下吧,please~ --------------------------- 分箱法在实际案例操作过程中较为常见,能够将一些 ...

  4. 【mysql】phpMyadmin上传文件限制

    在使用phpMyadmin导入数据库的时候,因为脚本在上传的时候响应时间过长,导致大于2M的数据偶尔会导入失败.而且大多数默认设置,只能导入2M的数据. 遇到这种情况, 我们可以修改php.ini以及 ...

  5. Excel 2010高级应用-折线图(二)

    在Excel中画折线图,具体操作过程如下: 1.新建一个excel文件,双击打开 2.单击"插入",找到折线图,单击下拉框 3.在折线框下方,新建数据源 4.鼠标右键,选择&quo ...

  6. Windows控制台下绘制简单图形

    最近接触到一个很有意思的问题,如何在Windows控制台下画图,翻遍了C的头文件也没找到画图的函数,好吧,那就用Windows提供的API函数吧,看来想移植是没戏了.先画一个简单的图,类似心电图那种吧 ...

  7. 错误代码: 1449 The user specified as a definer ('root'@'%') does not exist

    1. 错误描述 1 queries executed, 0 success, 1 errors, 0 warnings 查询:call analyse_use('20150501','20150601 ...

  8. NVIDIA Geforce GT 730 OpenGL 图形显示异常花屏

    原因:C盘空间爆表,用dism++清理.结果用力过猛,清完后程序里的图形直接马赛克了... 上个图感受一下吧... 嘿别说,还有那么点艺术风! 别闹了,这个问题很严重,很严肃好不好! 因为程序和数据都 ...

  9. tomcat原理(二)

    一.打包JavaWeb应用 在Java中,使用"jar"命令来对将JavaWeb应用打包成一个War包,jar命令的用法如下:

  10. 用python帮朋友刷帖

    0x0前言: 答应了一个朋友帮他刷贴,自己用python写了一个脚本刷. 虽然行为不好..但是缺钱用... 0x01准备: splinter模块: chrome浏览器驱动 0x02开始: 1.进入百度 ...