一、基本功能

  实现服务端向ZooKeeper集群注册自己提供的服务,并且把自己的IP地址和服务端口创建到具体的服务目录下。客户端向ZooKeeper集群监听自己关注的RPC服务(例如:sayHello和天气服务), 监听服务目录下的IP地址列表变化。若要在自己的项目中使用,可以采用阿里的Dubbo分布式服务框架。 
  在WEB端展示可以访问的RPC服务,WEB端可以通过RPC客户端向制定IP地址的RPC服务器发出调用RPC服务,RPC服务端向客户端反馈提供的服务内容,WEB客户端展示内容。 
  只是展示动态RPC基本原理,真正的调用一般都是不是web端触发的,应该是RPC的客户端根据监听到的多个IP服务提供者,根据每个IP的负载情况,动态选择最优可用的RPC服务端并且调用服务。 
  我们提供2个基本RPC服务,网络及应用部署如图: 
   
最终

二、ZooKeeper介绍

ZooKeeper是一个开放源代码的分布式应用程序协调服务,由知名互联网公司雅虎创建,是Google的Chubby一个开源的实现,是HadoopHbase的重要组件。 ZooKeeper的目标就是封装好复杂易出错的关键服务,将简单易用的接口和性能高效、功能稳定的系统提供给用户。它是一个为分布式应用提供一致性服务的软件,以下是ZooKeeper典型的应用场景

  • 数据发布和订阅:就是发布者将数据发布到ZooKeeper的一个或一系列节点上,供订阅者进行数据订阅,进而达到动态获取数据的目的,实现配置信息的集中管理和数据的动态更新。
  • 负载均衡:用来对多个计算机、网络连接、CPU、磁盘驱动或其他资源进分配负载,已达到优化资源使用、最大化吞吐率、最下化响应和避免过载。
  • 命名服务:命名服务是分布式系统最基本的公共服务之一。在分布式系统中,被命名的实体通常可以就是集群中的机器、提供的服务地址或远程对象等–这些我们都可以统称它们的名称(Name),其中较常见的就是一些分布式服务框架(如RPC、RMI)中的服务地址列表,通过使用命名服务,客户端应用能够指定名字来获取资源的实体、服务地址和提供者的信息。
  • 集群管理:随着分布式系统规模的日益扩大,集群中的机器规模也随之变大、因此集群监控与集群控制就变得很重要。
  • 分布式锁:分布式锁就是控制分布式系统之间同步访问共享资源的一种方式。在分布式系统中,常常需要协调他们的动作。如果不同的系统或是同一个系统的不同主机之间共享了一个或一组资源,那么访问这些资源的时候,往往需要互斥来防止彼此干扰来保证一致性,在这种情况下,便需要使用到分布式锁。
  • 分布式队列:利用Zookeeper的功能我们也可以实现类似于ActiveMQ、Kafka和HornetQ等的消息中间件。

三、构建ZooKeeper集群机及RPC服务机

在Ubuntu 桌面系统下完成,利用Oracle下的虚拟机软件VirtualBox。虚拟出了5个Ubuntu 操作系统,3个 ZooKeeper机,分别是ZooKeeper-1,ZooKeeper-2,ZooKeeper-3个构建出一个 ZooKeeper集群。2各RPC服务机,把在宿主机编写好的程序,通过打包的方式,发布到RPC服务机的jetty下,提供RPC服务 。

四、配置ZooKeeper

从官方网站下载后,解压到了虚拟机的/work/目录下,将/work/zookeeper-3.4.8/conf/目录下的zoo_sample.cfg重新复制一份命名位zoo.cfg,打开zoo.cfg文件。  
 修改配置文件:

     tickTime=2000
ddataDir=/work/data/zookeeper
clientPort=2181
  Server.1=192.168.0.3:2888:3888
Server.2=192.168.0.4:2888:3888
Server.3=192.168.0.5:2888:3888
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

参数说明: 
tickTime: zookeeper中使用的基本时间单位, 毫秒值. 
dataDir: 数据和日志的目录. 可以是任意目录.此处我们配置到了/work/data/zookeeper 目录下 
     clientPort: 监听client连接的端口号. 
     Server.X=HOST/IP:port:port  
     Server.X :X是我们配置zookeeper集群服务每台机子的编号,需要在每台机子的/work/data/zookeeper/下创建myid文件,内容就是机子的编号。

五、启动、关闭

切换到/work/zookeeper-3.4.8/bin目录下 
1. 启动 
./zkServer.sh start

   ZooKeeper JMX enabled by default
  Using config: /work/zookeeper-3.4.8/bin/../conf/zoo.cfg
  Starting zookeeper ... STARTED
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3
  1. 验证 
    ./zkCli.sh
[zk: localhost:2181(CONNECTED) 0] 
  • 1
  • 1

进入ZooKeeper 客户端终端命令就说明ZooKeeper 启动成功了。 
3. 关闭 
./zkServer.sh stop

   ZooKeeper JMX enabled by default
  Using config: /work/tool/zookeeper-3.4.8/bin/../conf/zoo.cfg
  Stopping zookeeper ... STOPPED
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

六、利用Thrift提供RPC服务

  1. 定义Weather.thrift文件
namespace java com.rpc.weather
       service weather{
  string getWeather(1:string city)
  } 
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4
  1. 生成JAVA文件接口 
    在windows环境下使用 Thrift 工具编译 .thrift文件,就会生成相应的 .java 文件。该文件包含了在 .thrift 文件中描述的服务类的接口定义,即 .Iface 接口,以及服务调用的底层通信细节。命令如下: thrift.exe -r -gen java  weather.thrift。该命令会自动生产相应的JAVA文件 

    gen-java目录就是生成好代码的地方
  2. 实现RPC接口功能 
    weather的接口实现比较复杂,在这里我们用简单些Hello来说明,道理是一样的。Hello接口的实现: hello只是一个简单的反馈功能,它把客户端传递过来的参数经过简单的组合一起反馈给RPC的客户端,本例只是简单展示了一下RPC服务处理能力,实现上面已经生产好的Hello.Iface 接口。代码如下:
public class HelloServiceImpl implements com.rpc.sayhello.Hello.Iface {
public String helloString(String para) throws TException {
System.out.println("helloString be calling");
return "你好:" + para + ",欢迎来到"+GetIP.IP()+"服务器!";
}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

七、RPC服务注册

我们在ZooKeeper注册了2个服务(2个ZNode节点),分别是sayHello及Weather。用2个IP提供RPC的服务。目录结构如图-: 
 
在Zookeeper的每个节点,都可以分为持久节点和临时节点 持久节点是指一旦这个节点被创建了,除非主动进行删除操作,否则这个节点将一直保存在ZooKeeper中.而临时节点就不一样了,它的生命周期和客户端回话绑定,一旦客户端回话失效,那么这个客户端创建的所有临时节点都会被移除。ZooKeeper主要是利用了“心跳检测”功能,它会定时向各个服务提供者发送一个请求,如果长期没有响应,服务中心就认为该服务提供者已经“挂了”,并将其剔除。注意临时节点下不可以在创建任何节点。

注册天气服务的主要代码:

private void createServerHost()  {
Stat stat = zookeeper.exists(WeatherConstants.RPCNAME + "/" + GetIP.IP() + ":" + WeatherConstants.WeahterPort,false);//检查节点是否存在
if (stat == null) {
      // 这里是临时的节点,会因服务器的宕机、网络失效而消失
path = zookeeper.create(WeatherConstants.RPCNAME + "/" + GetIP.IP() + ":" +   WeatherConstants.WeahterPort, "".getBytes(),Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);//创建节点 
}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

八、RPC客戶端服务监听

Watcher(事件监听器),是ZooKeeper的一个很重要的特性。ZooKeeper允许用户在指定的节点上注册一些Watcher,并且在一些特定的事件触发的时候,ZooKeeper服务器会将事件通知到感兴趣的客户端。利用Watcher监听2个服务节点下的IP变化,一旦我们监听的服务下的节点有变化(增加或减少)ZooKeeper就会向我们注册的监听类发送“NodeChildrenChanged”事件,我们就可以在此时更新地址列表变化,从而进行更新。 
需要注意的是ZooKeeper服务器在向客户端发送Watcher的通知的时候,仅仅只会发出一个通知,而不会把节点的变化情况发送给客户端,客户端需要自己重新获取。另外,由于Watcher通知是一次性的,一旦触发一次通知后,该Watcher就失效了,因此客户端需要反复注册Watcher。

监听服务列表的变化 
在监听WatchWeather类内我们定义了一个weatherlist的数组列表,用来存储提供天气的所有RPC服务的地址和端口。 
通过zookeeper.getChildren获取在zookeeper注册的所有提供天气的IP地址。并且注册了在这个节点下的监听类。

    weatherlist = zookeeper.getChildren(WeatherConstants.RPCNAME, this);
    //在监听的WatchWeather实现Watcher接口的process方法:
    public void process(WatchedEvent event) {
if (EventType.NodeChildrenChanged == event.getType()) {  
  weatherlist = zookeeper.getChildren(WeatherConstants.RPCNAME, this);
     }  
}
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

只要我们监听的节点下有变动就会接受到NodeChildrenChanged 事件,在这里我们再次获取了节点下的最新IP地址列表,并且重新注册了监听类。

九、调用RPC服务

public class CallWeatherRPC {
public String callWeather(String ip, int port, String city) {
String retString = null;
TTransport transport = new TSocket(ip, port);
transport.open();
TProtocol protocol = new TBinaryProtocol(transport);
weather.Client client = new weather.Client(protocol);//weather为定义接口实现的文件
retString = client.getWeather(city);//调用RPC服务
transport.close();
return retString;
}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

此处是使用了Thrift的客户端调用RPC服务端的相应程序,主要特点是IP地址不固定,可以有多地址可以调用。

基于ZooKeeper和Thrift构建动态RPC调用的更多相关文章

  1. 《精通并发与Netty》学习笔记(07 - 基于Thrift实现Java与Python的RPC调用)

    上节我们介绍了基于Thrift实现java与java的RPC调用,本节我们基于Thrift实现Java与Python的RPC调用 首先,修改data.thirft文件,将命名空间由java改为py n ...

  2. [转载] 基于zookeeper、连接池、Failover/LoadBalance等改造Thrift 服务化

    转载自http://blog.csdn.net/zhu_tianwei/article/details/44115667 http://blog.csdn.net/column/details/sli ...

  3. Thrift 基于zookeeper改造模式

    对于Thrift服务化的改造,主要是客户端,可以从如下几个方面进行: 1.服务端的服务注册,客户端自动发现,无需手工修改配置,这里我们使用zookeeper,但由于zookeeper本身提供的客户端使 ...

  4. 基于zookeeper、连接池、Failover/LoadBalance等改造Thrift 服务化

    对于Thrift服务化的改造,主要是客户端,可以从如下几个方面进行: 1.服务端的服务注册,客户端自动发现,无需手工修改配置,这里我们使用zookeeper,但由于zookeeper本身提供的客户端使 ...

  5. 基于Apache Zookeeper手写实现动态配置中心(纯代码实践)

    相信大家都知道,每个项目中会有一些配置信息放在一个独立的properties文件中,比如application.properties.这个文件中会放一些常量的配置,比如数据库连接信息.线程池大小.限流 ...

  6. 通过dubbo暴露接口调用方法,及基于zookeeper的dubbo涉及配置文件

    现在很流行的Dubbo很多朋友都听说过吧,最近我也在看这方面的东西,分享先我的心得笔记. 先说说我们团队要做的项目框架,很简单重在实现基于zookeeper的dubbo注册. 框架:springmvc ...

  7. 基于ZooKeeper的分布式Session实现(转)

    1.   认识ZooKeeper ZooKeeper—— “动物园管理员”.动物园里当然有好多的动物,游客可以根据动物园提供的向导图到不同的场馆观赏各种类型的动物,而不是像走在原始丛林里,心惊胆颤的被 ...

  8. 基于ZooKeeper的分布式Session实现

    1.   认识ZooKeeper ZooKeeper—— “动物园管理员”.动物园里当然有好多的动物,游客可以根据动物园提供的向导图到不同的场馆观赏各种类型的动物,而不是像走在原始丛林里,心惊胆颤的被 ...

  9. 简易的RPC调用框架(大神写的)

    RPC,即 Remote Procedure Call(远程过程调用),说得通俗一点就是:调用远程计算机上的服务,就像调用本地服务一样. RPC 可基于 HTTP 或 TCP 协议,Web Servi ...

随机推荐

  1. [LeetCode] 374. Guess Number Higher or Lower_Easy tag: Binary Search

    We are playing the Guess Game. The game is as follows: I pick a number from 1 to n. You have to gues ...

  2. python class 2

    //test.py 1 class Employee: 2         'all employee' 3         empCount = 0 4         def __init__(s ...

  3. Window.sessionStorage - Web API 接口参考 | MDN

    参考:https://developer.mozilla.org/zh-CN/docs/Web/API/Window/sessionStorage sessionStorage 属性允许你访问一个 s ...

  4. [提权] 脏牛漏洞 Dirty COW CVE-2016-5195 2.6.22 < 3.9 (x86/x64)

    /* * (un)comment correct payload first (x86 or x64)! * * $ gcc cowroot.c -o cowroot -pthread * $ ./c ...

  5. C++调用openssl库生成RSA加密秘钥对

    直接上代码.默认生成的是pkcs#1格式 // ---- rsa非对称加解密 ---- // #define KEY_LENGTH 1024 // 密钥长度 #define PUB_KEY_FILE ...

  6. 让bat以管理员权限运行

    有的电脑是非管理员登录,运行程序时,需要提示是否运行运行.解决方法如下: @ echo off % % ver|find "5.">nul&&goto :Ad ...

  7. 第四章 HTML5概述

    HTML5概述1.HTML5优势:解决跨浏览器问题:部分代替原来的js更明确地语义支持:不再单纯使用div增强WEB应用程序地功能:拖拽API等 2.HTML5语法改变标签不再区分大小写元素可以省略结 ...

  8. base64的编码

    计算机中的数据一般是由ascii编码,来存储的, 0---31以及127,表示的是控制字符: 32-126表示的是字符,包括空格,阿拉伯数字,大小写字母: 之后的128个字符,是不可见的字符, 在网络 ...

  9. sublime text3 增加代码片段(snipper)

    有时候编写代码时有些代码片段经常会用到,如果能将这些代码片段整理,再在需要的时候通过某些条件触发,那无疑是非常方便的! 创建方法:工具->插件开发->新建代码片段 默认产生的内容是: &l ...

  10. Vue系列之 => vue组件创建

    创建方式 一 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UT ...