SOA

来源:互联网 发布:淘宝热线电话 编辑:程序博客网 时间:2024/06/03 15:43

基于TCP的RPC

RPC的全称是Remote Process Call,即远程过程调用,拥有RMI、WebService等诸多成熟方案。

RPC将原来的本地调用转变为调用远端的服务器上的方法。RPC的实现包括客户端和服务端,即服务的调用方与服务的提供方。

对象序列化

无论何种类型数据,最终都需要转换成二进制流在网络上进行传输。

● 将对象转换为二进制流的过程叫对象序列化;
● 将二进制流恢复为对象的过程称为对象的反序列化。

基于TCP协议的RPC

基于Java的SocketAPI,我们能够实现一个简单RPC调用,包括了服务的接口及接口的远程实现,服务的消费者与远程的提供方。

这里写图片描述

服务接口和实现都非常简单,它提供一个SayHello方法,它有一个String类型的参数,通过该参数来识别究竟是返回hello还是byebye:

public interface SayHelloService{\    public String sayHello(String helloArg);}服务的实现:public class SayHelloServiceImpl implements SayHelloService{    public String sayHello(String helloArg){        if(helloArg.equals("hello")){            return "hello";        }else{            return "bye bye";        }    }}服务消费者Consumer类的部分代码://接口名称String interfacename = SayHelloService.class.getMame();//需要远程执行的方法Method method = SayHelloService.class.getMethod("sayHello",java.lang.String.class);//需要传递到远端的参数Object[] arguments = {"hello"};Socket socket = new Socket("127.0.0.1",1234);//将方法名称和参数传递到远端ObjectOutputStream output = new ObjectOutputStream(socket.getOutputStream());output.writeUTF(interfacename);//接口名称output.writeUTF(method.getName());//方法名称output.writeObject(method.getParameterTypes());output.writeObject(arguments);//从远端读取方法执行结果ObjectInputStream input = new objectInputStream(socket.getInputStream());Object result = input.readObject();

先取得接口的名称、需要调用的方法和需要传递的参数,并通过Socket将其发送到服务提供方,等待服务端相应结果。为便于演示,使用阻塞式I/O,实际生产环境往往使用非阻塞I/O。

服务提供者Provider类的部分关键代码:

ServerSocket server = new ServerSocket(1234);while(true){    Socket socket = server.accept();    //读取服务信息    ObjectInputStream input = new ObjectInputStream(socket.getInputStream());    String interfacename = input.readUTF();//接口名称    String methodName = input.readUTF();//方法名称    Class<?>[] parameterTypes = (Class<?>[])input.readObject();//参数类型    Object[] arguments = (Object[])input.readObject();//参数对象    //执行调用    Class serviceinterfaceclass = Class.forName(interfacename);//得到接口的class    Object service = services.get(interfacename);/取得服务实现的对象    Method method = serviceinterfaceclass.getMethod(methodName,parameterTypes);//获得要调用的方法    Object result = method.invoke(service,arguments);    ObjectOutputStream output = new ObjectOutputStream(socket.getOutputStream());    output.writeObject(result);}

服务提供端事先将服务实例化后放在services这个Map中,通过一个while循环,不断地接收新到来的请求,得到所需要的参数,包括接口名称。方法名称、参数类型和参数,通过Java的反射取得接口需要调用的方法,执行后将结果返回给服务的消费者。

基于HTTP协议的RPC

基于TCP实现的RPC,处于协议栈下层,能够更灵活对协议字段进行定制,减少网络传输字节数,
降低网络开销,提高性能,但是由于更多关注底层复杂细节,实现代价较高,且由于所定义协议自身局限性,难以得到平台厂商和开源社区的支持。

● 数据传输格式一般以JSON或XML形式。

RESTful和RPC

现在有两种主流的URL链接风格,一种是RPC风格,另一种是REST风格。

● RPC风格URL比较好理解,直接在HTTP请求的参数中标明需要远程调用的服务接口名称、服务需要的参数即可。
● Restful风格其中的一个思想是,通过HTTP请求对应的POST、GET、PUT、DELETE方法,来完成对应的CRUD操作。

服务化的演变

公共的业务被拆分出来,形成可共用的服务,最大程度地保障代码和逻辑的复用,避免重复建设,这种设计被称为SOA(Service-Oriented Architecture)。

SOA架构中,服务消费者通过服务名称,在众多服务中找到要调用的服务的地址列表,称为服务的路由。

这里写图片描述

对于负载较高的服务来说,往往对应着由多台服务器组成的集群。请求到来后,为了将请求均衡分配到后端服务器,负载均衡程序将从服务对应的地址列表中,通过相应的负载均衡算法和规则,选取一台服务器进行访问,这个过程称为服务的负载均衡。

这里写图片描述

当服务越来越多,依赖单一硬件负载均衡设备或者使用Nginx等软件方案进行路由和负载均衡调度,单点故障问题也开始凸显,一旦服务路由或者负载均衡服务器宕机,依赖它的所有服务奖失效。

这时,需要一个能动态注册和获取服务信息的地方,来统一管理服务名称和其对应的服务器列表信息,称之为服务配置中心。服务提供者在启动时,将其提供的服务名称。服务器地址注册到服务配置中心,服务消费者通过服务配置中心来获取需要调用的服务器机器列表,通过相应负载均衡算法,选取其中一台服务器进行调用。当服务器宕机或者下线,相应机器需要能动态从服务配置中心里移除,并通知相应的服务消费者。这个过程中,服务消费者只有在第一次调用服务时需要查询服务配置中心,然后将查询到的信息缓存到本地,后面的调用直接使用本地缓存的服务地址列表信息,而不需要重新发起请求到服务配置中心去获取相应的服务地址列表。直到服务地址列表发生变更。这种无中心化的结构解决了之前负载均衡设备所导致的单点故障问题,并且减轻了服务配置中心的压力。

基于ZooKeeper的持久和非持久节点,我们能够近乎实时感知到后端服务器的状态(上下线、宕机)。通过集群间zab协议,使得服务配置信息能够保持一致。

负载均衡算法

服务消费者从服务配置中心获取到服务地址列表后,需要选取其中一台来发起RPC调用。如何选择,则取决于具体负载均衡算法,常见的负载均衡算法包括轮询、随机、源地址哈希、加权轮询、加权随机、最小连接等。

ZooKeeper

功能介绍

它是一个针对大型分布式系统的可靠协调系统,就是为用户的分布式应用程序提供协调服务。

分布式协调服务
● 管理(存储、读取)用户提交的数据(状态数据,非业务数据);
● 并为数据提供监听服务;

应用场景

● 分布式锁;
● 配置管理;

集群管理

zookeeper的主从是通过选举投票生成的,而非配置。(Leader来负责管理集群)

Zookeeper是可以集群复制的,集群间通过Zab(Zookeeper Atomic Broadcast)协议来保持数据的一致性。该协议包括两个阶段:leader election阶段和Atomic broadcas阶段。集群中将选举出一个leader,其他的机器则称为follower,所有写操作都被传送给leader,并通过broadcas将所有更新告诉follower。当leader崩溃或者leader失去大多数follower时,需要重新选举出一个新的leader,让所有服务器都恢复到一个正确状态。当leader被选举出来,且大多数服务器完成了leader状态同步后,leader election过程就结束了,将进入Atomic broadcas过程。Atomic broadcas同步leader和follower之间的信息,保证leader和follower具有相同系统状态。

zookeeper客户端端口2181、leader/follower通信端口2888、选举投票通信端口3888。

只要有半数以上节点存活,zk就能正常服务。(zk节点数是奇数)

● zookeeper是java程序,所以依赖JDK环境。

● zookeeper集群搭建完成就可以启动客户端,客户端可以连接除leader外的所有节点,建立长连接,客户端任何修改信息都会同步到server上,由leader同步到各个节点。

● zookeeper的核心其实类似一个精简的文件系统,提供一些简单的操作和一些附加的抽象(例如znode的排序与watch)。

ZooKeeper API的使用

Zookeeper实现了一个层次命名空间的数据模型,也可以认为它是一个小型、精简的文件系统。它的每个节点称为znode,znode除了本身能够包含一部分数据之外,还能够拥有子节点。

当节点上的数据发生变化,或者其子节点发生变化时,基于watcher机制,会发出相应通知给订阅其状态变化的客户端。需要注意,Zookeeper的watcher是一次性的,也就是说,每次在处理完状态变化事件后,需要重新注册watcher,这个特性也使得在处理事件和重新加上watcher这段时间发生的阶段状态变化将无法被感知。

Zookeeper的第三方客户端工具包zkClient,解决了Zookeeper的watcher一次性注册问题,将znode的事件重新定义为子节点的变化、数据的变化、连接及状态的变化三类,由zkClient统一将watcher的WatchedEvent转换到以上三种情况去处理,watcher执行后重新读取数据的同时,再注册相同的watcher。

服务配置中心的节点

这里写图片描述

服务配置中心的节点树分成三层结构,最上面一层为根节点,用来聚集服务节点,通过它可以查询到所有的服务,而服务名称节点挂载的是服务提供者的服务器地址,服务消费者通过负载均衡算法来选择其中一个地址发起远程调用,根节点和服务名称采用的是Zookeeper的持久节点,而服务提供者的地址节点,则采用非持久节点,一旦服务器下线,节点就随之消失。

当服务规模变大,也要了解服务的调用情况(消费者情况),并以此作为服务扩容或下线的依据。

这里写图片描述

上图增加了一层,用来表示节点类型,每个服务包含有两种节点类型,即consumer和provider。当服务消费者启动时,即在服务配置中心里,在其所调用的所有服务的consumer节点下增加自己的机器地址。

HTTP服务网关

gateway接受各种HTTP请求,完成相应的权限与完全校验。当校验通过后,根据传入的服务名称,到服务配置中心找到相应的服务名称节点,并加载对应服务提供者的地址列表,通过负载均衡算法,选取机器发起远程调用,将客户端参数传递到后端服务器。

● 解决安全问题,拦截和过滤恶意请求
● 路由和负载均衡

这里写图片描述

当然这里gateway的高可用和可扩展就成为了重点:

这里写图片描述

0 0
原创粉丝点击