本节在《负载均衡》的基础上利用zookeeper实现服务注册与发现,ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,是Google的Chubby一个开源的实现,是Hadoop和Hbase的重要组件。它是一个为分布式应用提供一致性服务的软件,提供的功能包括:配置维护、域名服务、分布式同步、组服务等。
基本思路就是把服务注册到zookeeper上,代理连接到zookeeper监控这些注册的服务,一旦这些服务出现变化(新增,故障,下线)就动态的构造连接池list:
这里使用的ZooKeeper的版本是3.4.10,直接在官网下载zookeeper-3.4.10.tar.gz解压就好了,把conf目录下的zoo_sample.cfg改名字为zoo.cfg,到bin目录下双击zkServer.cmd就可以启动ZooKeeper了。
首先在TestServer.java上加上向zookeeper注册的代码,EPHEMERAL表示临时性结点,一旦TestServer挂了,就和zookeeper失去了心跳,zookeeper会自动的把对应的结点删除,而PERSISTENT表示持久。
//创建一个与ZooKeeper服务器的连接 ZooKeeper zk = new ZooKeeper("localhost:2181", 5000, null); Stat stat = zk.exists("/thriftServer", false); if (stat == null) { //不存在就创建根节点 zk.create("/thriftServer", null, Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); } //创建一个子节点 zk.create("/thriftServer/localhost:" + port, "someData".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
然后在ThirftProxy.java上加上如下代码,大概逻辑是启动代理时调用zk()连接到zookeeper取得注册的服务列表并构造对应的连接池list,并且向zookeeper注册了一个监听器myWatcher,myWatcher监听到NodeChildrenChanged事件时,也就是服务列表发生了变化(新增或者删除),就新增或者删除对应的连接池,使得连接池列表poolFactorys始终对应zookeeper上注册的可用的服务列表。
private static void zk() throws Exception { MyWatcher myWatcher = new MyWatcher(); zk = new ZooKeeper("localhost:2181", 5000, myWatcher); List<String> servers = zk.getChildren("/thriftServer", true); System.out.println("zk-servers=" + servers); for (String server : servers) { addServer(server); } } private static void addServer(String server) { String[] serverArr = server.split(":"); String ip = serverArr[0]; int port = Integer.parseInt(serverArr[1]); GenericObjectPoolConfig config = new GenericObjectPoolConfig(); //链接池中最大连接数,默认为8 config.setMaxTotal(2); //当连接池资源耗尽时,调用者最大阻塞的时间,超时将跑出异常。单位:毫秒;默认为-1,表示永不超时 config.setMaxWaitMillis(3000); ConnectionPoolFactory poolFactory = new ConnectionPoolFactory(config, ip, port); poolFactorys.add(poolFactory); } static class MyWatcher implements Watcher { @Override public void process(WatchedEvent event) { System.out.println("已经触发了" + event.getType() + "事件!"); //子节点变动:新增或删除 if (event.getType() == EventType.NodeChildrenChanged) { try { List<String> servers = zk.getChildren("/thriftServer", true); for (String server : servers) { boolean isFind = false; for (ConnectionPoolFactory poolFactory : poolFactorys) { if ( server.equals(poolFactory.toString()) ) { isFind = true; break; } } if (!isFind) { System.out.println("上线" + server); addServer(server); //新增服务 } } for (int i = 0; i < poolFactorys.size(); i++) { ConnectionPoolFactory poolFactory = poolFactorys.get(i); boolean isFind = false; for (String server : servers) { if ( poolFactory.toString().equals(server) ) { isFind = true; break; } } if (!isFind) { //下线服务 System.out.println("下线" + poolFactory); poolFactory.close(); poolFactorys.remove(i); poolFactory = null; } } } catch (Exception e) { e.printStackTrace(); } } } }
启动zookeeper,TestServer(改变端口多启动几个) ,ThirftProxy,TestClient,测试结果符合预期。测试时可以用一个第三方工具ZooInspector查看zookeeper上的数据,比较方便,ZooInspector下载地址:https://issues.apache.org/jira/secure/attachment/12436620/ZooInspector.zip。
工程结构图:
推荐一些比较好的Zookeeper文章:
1 分布式服务框架Zookeeper https://www.ibm.com/developerworks/cn/opensource/os-cn-zookeeper/。
2 ZooKeeper学习 http://www.cnblogs.com/wuxl360/category/874409.html。
补充:
(1) 整理了一下代码, 开源在GitHub:https://github.com/halloffamezwx/thriftjsoa。
(2) 图中的proxy是存在单点故障的问题的,可以优化一下,增加多台proxy,利用zk的EPHEMERAL_SEQUENTIAL临时顺序节点来进行proxy的Master选举,编号最小的节点将在选举中获胜,获得锁成为主节点,保证系统中每时每刻只有一个proxy(Master)为分布式系统提供服务。
感谢阅读,附件是整个eclipse工程。
相关推荐
NULL 博文链接:https://zhuwx.iteye.com/blog/2368356
NULL 博文链接:https://zhuwx.iteye.com/blog/2371657
NULL 博文链接:https://zhuwx.iteye.com/blog/2374326
Apache Thrift is an open source cross language serialization and RPC framework. With support for over 15 programming languages, Apache Thrift can play an important role in a range of distributed ...
NULL 博文链接:https://zhuwx.iteye.com/blog/2347581
服务治理框架,一般存在与RPC的上一层,用来在大量RPC服务至上,协调客户端和服务器的调用工作。这个示例工程和我的博客《架构设计:系统间通信(13)——RPC实例Apache Thrift 下篇》...
Make applications cross-communicate using Apache Thrift! About This Book Leverage Apache Thrift to enable applications written in different programming languages (Java, C++, Python, PHP, Ruby, and so...
基于Thrift、zookeeper的rpc实现 基于注解配置ThriftService、ThriftReference 基于权重的简单负载均衡 使用TMultiplexedProcessor发布多个服务
本例改编自Apache Thrift教程: http://mikecvet.wordpress.com/2010/05/13/apache-thrift-tutorial-the-sequel/ http://chanian.com/2010/05/13/thrift-tutorial-a-php-client/ 原教程使用的是c++ server和...
详细介绍了Apache Thrift在Ubuntu以及Windows下基于C++和Java语言的安装和运行。附有小例子,亲自测试通过。所述方法网上应该有教程,但大多零散不统一或者不完整,因此本人整理了一份,特来分享。
Learning Apache Thrift
Apache Thrift——可伸缩的跨语言服务开发框架
1.服务端的服务注册,客户端自动发现,无需手工修改配置,这里我们使用zookeeper,但由于zookeeper本身提供的客户端使用较为复杂,因此采用curator-recipes工具类进行处理服务的注册与发现。 2.客户端使用连接池对...
第二部分-编程Apache Thrift 本部分深入研究Apache Thrift框架的每一层,详细检查传输,协议,类型,服务,服务器和Apache Thrift接口定义语言。 这些章节中的示例使用C ++,Java和Python作为演示语言。 C ++示例...
基于RPC技术的java开发,可用于分布式系统开发,高性能高可用。
FacebookThrift最初是紧跟Apache Thrift发行的,但现在朝着新的方向发展。 特别是,编译器是从头开始重写的,新的实现具有完全异步的Thrift服务器。 在了解有关这些改进的。 您还可以在原始的Facebook Code 了解...
Apache Thrift Java实战源码,包含了客户端和服务端源码,客户端和服务端是分开的,如果需要放到一个工程,直接把Client.java文件复制到服务端运行即可。
NULL 博文链接:https://kingxss.iteye.com/blog/1413696
使用Apache thrift通信框架编写的一个实例,以及提供开发中使用thrift所需的jar包