Skip to content

设计文档[已过时]

neoremind edited this page Aug 8, 2015 · 1 revision

文档已过时,仅供参考使用。

1 服务端

1.1 主要职责

  1. 启动servlet容器,索引服务bean,同时向zookeeper注册。
  2. 客户端请求服务时,根据请求协议的不同路由到不同的handler进行本地调用,handler负责解包,反序列化请求、调用本地方法,序列化返回,异常处理等。
  3. 浏览器发送GET请求时,返回可视化的配置页面。

1.2 Class diagram

BaseRpcServlet

保存了本spring容器内定义的提供RPC请求的bean,即服务提供者,同时进行服务索引,根据客户端发送请求指定的path路由到指定的提供者bean。在启动时调用SimpleZookeeperClient进行服务的注册。

NaviRpcServlet

负责处理服务调用者的请求,继承自BaseRpcServlet,实现servlet接口,关联NaviRpcRequest和NaviRpcResponse类型。

NaviRpcExporter

Spring容器内定义的bean,包括XML和注解方式暴露的bean都会以此种数据结构保存在本地服务索引中。

HandlerFactory

根据客户端调用传递的不同协议,见NaviProtocol,返回指定的handler进行处理。

NaviRpcHandler

Rpc处理接口,目前包括protostuff和protobuf两个实现,关联RequestDTO和ResponseDTO类型。

类图见下:

1.3 传输通道

Navi采用HTTP传输通道。底层采用HttpURLConnection来传输,摒弃掉了nio selector编程、netty、mina等框架是考虑到编程模型的简单,易于维护,使用servlet容器来提供请求-应答功能,极大的简化了编程的复杂性,提高未来的可维护性,部署容易,最重要的一点事,通过HTTP的keepalive机制保证了连接的复用性,利用JDK自带的底层池化技术来做复用,关于这部分可以参考oracle官网,截取部分特性说明,连接入口点击这里。

What is HTTP Persistent Connections?
HTTP persistent connections, also called HTTP keep-alive, or HTTP connection reuse, is the idea of using the same TCP connection to send and receive multiple HTTP requests/responses, as opposed to opening a new one for every single request/response pair. Using persistent connections is very important for improving HTTP performance.

There are several advantages of using persistent connections, including:
-Network friendly. Less network traffic due to fewer setting up and tearing down of TCP connections.
-Reduced latency on subsequent request. Due to avoidance of initial TCP handshake
-Long lasting connections allowing TCP sufficient time to determine the congestion state of the network, thus to react appropriately.

一个简单的通过socket和服务端通信的例子见,或者参考附录。

1.4 序列化协议

Google 的protobuf是一个优秀的序列化工具,跨语言、快速、序列化后体积小。

protobuf的一个缺点是需要数据结构的预编译过程,首先要编写.proto格式的配置文件,再通过protobuf提供的工具生成各种语言响应的代码。由于java具有反射和动态代码生成的能力,这个预编译过程不是必须的,可以在代码执行时来实现。protostuff就实现了上述功能。

protostuff基于Google protobuf,但是提供了更多的功能和更简易的用法。其中,protostuff-runtime实现了无需预编译对java bean进行protobuf序列化/反序列化的能力。

Navi采用protostuff-runtime序列化协议,其压缩比率、ser/deser的时间均在当下处于优势地位。

例如,创建一个对象,将其序列化成一个字节数组,然后再反序列化成一个对象各个协议的比较:

2 客户端

2.1 主要职责

1)根据XML或者注解配置,对客户端内部注入的服务接口进行JDK动态代理,实际执行bean为一个代理对象,负责RPC远程通讯。 2)客户端调用可以指定是否启用注册、序列化协议、软负载均衡策略、容错策略等。 3)进行实际调用时候底层封装RPC调用细节,利用URLConnection以及keepalive特性与服务端进行通信。 4)当启用zookeeper注册中心后,需订阅注册中心上的watched namespace,服务地址变更后得到通知,立即更新本地缓存的地址cache。

2.2 Class diagram

  1. NaviProxyFactoryBean 服务消费者利用XML或者注解方式将本地的bean用此类来做代理,当调用接口定义方法时,进行JDK代理调用。同时该类中的属性,可以按客户端需求设置,包括
  • 是否启用zookeeper服务注册查找远程服务地址
private String serviceRootPath;
  • 调用的接口定义
private Class<?> serviceInterface;
  • 序列化协议定义,包括PROTOSTUFF和PROTOBUF两个
private NaviProtocol protocol
  • 容错机制,包括FAILOVER重试和FAILFAST错误立即退出两种
private NaviFailStrategy failStrategy
  • 软负载均衡配置,包括RANDOM和ROUND ROBIN两种策略
private NaviSelectorStrategy selectorStrategy
  1. NaviInvocationProxy 实现了InvocationHandler接口,该类直接负责真正的代理方法执行。

  2. InvocationFactory 该工厂用来构造NaviServiceInvoker对象,该对象通过不同的序列化协议定义,返回指定的Rpc调用代理,包括ProtostuffRpcProxy和ProtobufRpcProxy,二者负责底层的消息发送接收,抛出运行时异常供上层使用。

  3. SelectorFactory 上面构造的RpcProxy具体的调用需要包装在容错机制下面,包括失败处理策略、软负载均衡策略,软负载均衡策略下设两个实现类NaviRandomServiceSelector,NaviRoundRobinServiceSelector。

类图见下:

2.3 Sequence diagram