- 浏览: 191998 次
- 性别:
- 来自: 上海
文章分类
最新评论
远程服务调用框架设计与实现
远程服务调用框架设计与实现
Auther: cenwenchu
Email: wenchu.cenwc@alibaba-inc.com
Version: 0.1
Date: <chsdate style="BACKGROUND-POSITION: left bottom; BACKGROUND-IMAGE: url(res://ietag.dll/#34/#1001); BACKGROUND-REPEAT: repeat-x" tabindex="" w:st="on" isrocdate="False" islunardate="False" day="22" month="6" year="2007">2007-6-22</chsdate>
SVN: http://svn.alibaba-inc.com/repos/opentech/sandbox/remoting/trunk
目的
为远程服务调用提供统一的框架,该框架集中解决远程调用过程中的三方面问题:
a. 应用透明性:应用的接口和实现不依赖于框架的实现。框架可以透明的切换各种远程调用技术,而上层应用的接口和实现不用做任何调整。
b. 安全性:安全性主要包括两个方面:身份及签名验证(防篡改伪造);数据传输保密性(防监听);IP认证。
c. 调用频度控制:为保证服务可用,需要对于调用频度根据一定的规则进行控制。
实现技术
由于调用双方都是基于Java的应用,实现技术上建议采用基于Spring的Remoting框架,这样可以实现应用透明性,接口开发人员不用考虑远程调用等与业务无关的技术细节。基于Spring框架并进行扩展,我们可以在框架层次实现安全性和调用频度限制。
由于调用双方不在一个局域网环境内,因此在具体通讯协议上,最佳选择即为Http。因此我们推荐的实现技术包括:Spring Remoting + Spring HttpInvoker,以及Spring Remoting + Hessian。
安全性包括身份验证和数据传输安全两个方面,身份验证可以根据调用双方的信任程度以及性能要求确定采用对称加密或者非对称加密,当前提供了三种验证措施,用户名加密认证,IP认证,以及消息数字摘要加密验证,该验证可以在Spring Remoting基础上进行扩展。数据传输安全则主要是担心数据在传输过程中被截获,对于基于Http的传输,使用Https即可(无需在框架或者应用层支持)。
调用频度控制,则可以应用AOP技术,对于调用进行截获和统计,根据一定的规则,判断调用是否符合控制策略。
接口定义和实现规范
接口定义和实现为简单的POJI和POJO即可,不过为了满足远程调用的需要,需要保证所有参数和返回值都是可序列化的,另外,鉴于部分远程调用技术的序列化机制的特殊性(例如Hessian),数据类型应尽可能简单。此外,基于性能考虑,远程接口调用方式适用于中低频度的小数据量的调用,对于大批量数据同步或者相当高频度的调用,远程接口调用方式并不合适。
设计实现
基本类图
<shapetype id="_x0000_t75" stroked="f" filled="f" path=" m@4@5 l@4@11@9@11@9@5 xe" o:preferrelative="t" o:spt="75" coordsize="21600,21600"><stroke joinstyle="miter"></stroke><formulas><f eqn="if lineDrawn pixelLineWidth 0 "></f><f eqn="sum @0 1 0 "></f><f eqn="sum 0 0 @1 "></f><f eqn="prod @2 1 2 "></f><f eqn="prod @3 21600 pixelWidth "></f><f eqn="prod @3 21600 pixelHeight "></f><f eqn="sum @0 0 1 "></f><f eqn="prod @6 1 2 "></f><f eqn="prod @7 21600 pixelWidth "></f><f eqn="sum @8 21600 0 "></f><f eqn="prod @7 21600 pixelHeight "></f><f eqn="sum @10 21600 0 "></f></formulas><path o:connecttype="rect" gradientshapeok="t" o:extrusionok="f"></path><lock aspectratio="t" v:ext="edit"></lock></shapetype><shape id="_x0000_i1026" style="WIDTH: 414.75pt; HEIGHT: 387.75pt" coordsize="21600,21600" type="#_x0000_t75"><imagedata o:title="" src="D68C4E15.files/image001.emz"></imagedata></shape>
图1 远程服务发布类结构图
针对Hessian和HttpInvoker两种远程服务调用的方式封装了对于安全控制的两个安全发布类,具体的安全配置以及安全操作都在RemoteContractTemplate中,这样可以方便扩展任何安全的需求变更,并且对原有任何的Exporter做了安全切面处理,防止过度耦合。
<shape id="_x0000_i1027" style="WIDTH: 414.75pt; HEIGHT: 336.75pt" coordsize="21600,21600" type="#_x0000_t75"><imagedata o:title="" src="D68C4E15.files/image003.emz"></imagedata></shape>
图 2 远程服务调用类结构图
远程服务调用对于不同的方法调用需要不同的定制,这里针对Hessian和HttpInvoker采用了替换植入内部处理类的方式,Hessian植入了新的HessianProxyFactory用来生成新的HessianProxy来植入安全机制,HttpInvokerFactoryBean植入了新的HttpInvokerRequestExecutor来植入安全机制,同样安全配置以及操作都封装在RemoteContractTemplate中,集中控制和配置,方便扩展和管理。
基本流程图
<shape id="_x0000_s2196" style="WIDTH: 375.8pt; HEIGHT: 636.9pt; mso-position-horizontal-relative: char; mso-position-vertical-relative: line" coordsize="21600,21600" type="#_x0000_t75"><imagedata o:title="flow" src="D68C4E15.files/image005.jpg"></imagedata><wrap type="none"></wrap><anchorlock></anchorlock></shape>
图 3 基本流程图
如上图所示,用户发起请求调用远程服务,首先是创建远程服务代理,然后通过植入安全信息将请求发送到远程服务发布处理类中,首先检查安全信息,如果通过安全检测就进入方法调用拦截器中检验类似于频率之类的限制过程中,通过拦截器的检测就可以调用真正的远程服务,并且获得结果,将结果返回并封装安全信息返回给服务调用代理,代理首先检测是否有合法的安全信息,如果通过安全信息认证,将结果返回给客户端。
具体的配置和使用
这里通过一个Demo来说明如何使用这个远程服务调用框架。
假定一个售票管理服务要发布,售票管理服务结构图如下:
<shape id="_x0000_i1028" style="WIDTH: 291pt; HEIGHT: 237.75pt" coordsize="21600,21600" type="#_x0000_t75"><imagedata o:title="" src="D68C4E15.files/image007.emz"></imagedata></shape>
图 4 售票管理服务结构图
服务类接口为TicketManage,实现类是TicketManageImpl。测试调用类为TicketManageClient。接口和接口的实现类就是按照普通的Java规范来实现即可,TicketManageClient根据你选择不同的服务调用方式来编写代码,这里用到了Hessian和HttpInvoker两种方式,代码如下:
public static void main(String[] args)
{
ApplicationContext ctx = new ClassPathXmlApplicationContext("ticket.xml");
TicketManage ticketManage = (TicketManage)ctx.getBean("ticketService");//hession调用的配置
Ticket ticket = ticketManage.buyTicket(20);
System.out.println("ticket seat: " + ticket.getSeat());
int returncost = ticketManage.returnTicket(ticket);
System.out.println("return ticket, get back cost :" + returncost);
TicketManage httpTicketManage = (TicketManage)ctx.getBean("ticketHttpService");//HttpInvoke调用的配置
ticket = httpTicketManage.buyTicket(30);
System.out.println("ticket seat: " + ticket.getSeat());
returncost = httpTicketManage.returnTicket(ticket);
System.out.println("return ticket, get back cost :" + returncost);
}
ticket.xml是客户端的spring配置文件,具体的内容如下:
<?xml version="1.0" encoding="GB2312"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans default-autowire="byName">
<!—- 安全模版配置类,参数在后面会有详细解释 -->
<bean id="remoteContractTemplate" class="com.alibaba.common.remoting.util.RemoteContractTemplate" init-method="init">
<property name="encryptKeyPath" value="file:c://key.ky" />
<property name="decryptKeyPath" value="file:c://key.ky" />
<property name="algonrithm" value="RSA"/>
<property name="needMD" value="true"/>
<property name="needUserAuth" value="true"/>
<property name="user">
<list>
<value>taobao</value>
<value>zhifubao</value>
<value>b2b</value>
</list>
</property>
<property name="owner" value="alisoft"/>
<property name="connectTimeout" value="6"/>
<property name="readTimeout" value="0"/>
<property name="needIPAuth" value="true"/>
<property name="ipList">
<list>
<value><chsdate w:st="on" isrocdate="False" islunardate="False" day="30" month="12" year="1899">10.0.26</chsdate>.23</value>
<value><chsdate w:st="on" isrocdate="False" islunardate="False" day="30" month="12" year="1899">10.0.0</chsdate>.42</value>
</list>
</property>
</bean>
<!—- 需要植入到HttpInvokerProxyFactoryBean的安全请求处理类 -->
<bean id="securityHttpInvokerRequestExecutor" class="com.alibaba.common.remoting.http.SecurityHttpInvokerRequestExecutor">
<property name="remoteContractTemplate" ref="remoteContractTemplate" />
</bean>
<!—- 发布服务的Bean -->
<bean id="ticketHttpService" class="org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean">
<property name="serviceUrl" value="http://localhost:80/remote-examples/remote/TicketHttpService"/>
<property name="serviceInterface" value="com.alibaba.common.remoting.test.TicketManage"/>
<property name="httpInvokerRequestExecutor" ref="securityHttpInvokerRequestExecutor"/>
</bean>
<!—- Hessian的安全代理工厂类Bean -->
<bean id="securityHessianProxyFactory" class="com.alibaba.common.remoting.hessian.SecurityHessianProxyFactory">
<property name="remoteContractTemplate" ref="remoteContractTemplate" />
</bean>
<bean id="ticketService" class="org.springframework.remoting.caucho.HessianProxyFactoryBean">
<property name="serviceUrl" value="http://localhost:80/remote-examples/remote/TicketService"/>
<property name="serviceInterface" value="com.alibaba.common.remoting.test.TicketManage"/>
<property name="proxyFactory" ref="securityHessianProxyFactory"/>
</bean>
</beans>
上面的xml中蓝色的内容需要根据具体的情况作修改,黑色的内容则不需要修改。
安全模版配置类参数具体说明:下面是代码中的说明,大家一看就应该明白了
private String encryptKeyPath;//encryptKey的路径
private String decryptKeyPath;//decryptKey的路径
private Key encryptKey;//根据encryptKey的路径生成的key
private Key decryptKey;//根据decryptKey的路径生成的key
private String algonrithm;//算法
private String needMD;//是否需要MD校验
private String needUserAuth;//是否需要加密
private List<String> user;//允许对方访问或者返回结果的用户名
private String owner;//自己的签名
private byte[] encrypted;//加密后的用户签名,一次加密,多次使用,增加性能提升
private String encoding = "GB2312";//编码方式,加密和md的内容的编码方式
private String needIPAuth;//是否需要IP认证
private List<String> ipList;//允许访问的ip列表
private int readTimeout = 0;// 读取数据超时时间设置,单位秒
private int connectTimeout = 0;// 连接超时时间设置,单位秒
客户端设置好以后,就需要设置服务端了:
服务端很简单首先是类似于Spring的Hessian和HttpInvoker调用的配置一样,在WEB-INF/lib下面放入toolkit-sandbox-remoting.jar以及其它以来的jar,然后配置web.xml,增加如下内容(这都是spring mvc框架的配置,大家可以参考spring来配置):
<servlet>
<servlet-name>remote</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>remote</servlet-name>
<url-pattern>/remote/*</url-pattern>
</servlet-mapping>
然后在WEB-INF下面新建remote-servlet.xml,如果要换名称,需要在上面的配置文件配置。
remote-servlet.xml内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:sca="http://www.springframework.org/schema/sca"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:osgi="http://www.springframework.org/schema/osgi"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/sca http://www.springframework.org/schema/sca/spring-sca.xsd http://www.springframework.org/schema/osgi http://www.springframework.org/schema/osgi/spring-osgi.xsd" default-autowire="byName">
<bean id="ticketManageTarget" class="com.alibaba.common.remoting.test.TicketManageImpl" />
<bean id="ticketManage" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces" value="com.alibaba.common.remoting.test.TicketManage" />
<property name="target"><ref local="ticketManageTarget" /></property>
<!—- 拦截器bean -->
<property name="interceptorNames">
<list>
<value>remoteMethodInterceptor</value>
</list>
</property>
</bean>
<bean id="remoteMethodInterceptor" class="com.alibaba.common.remoting.interceptor.RemoteCounterInterceptor" >
<property name="valve" value="20"/><!—- 阀值代表次数 -->
<property name="policy" value="hour"/><!—- 策略,当前提供hour,day,month三种 -->
<!—- 上面的配置代表了每小时不能超过20次的访问 -->
</bean>
<bean id="remoteContractTemplate" class="com.alibaba.common.remoting.util.RemoteContractTemplate" init-method="init">
<property name="encryptKeyPath" value="file:c://key.ky" />
<property name="decryptKeyPath" value="file:c://key.ky" />
<property name="algonrithm" value="RSA"/>
<property name="needMD" value="true"/>
<property name="needUserAuth" value="true"/>
<property name="user">
<list>
<value>alisoft</value>
<value>zhifubao</value>
<value>b2b</value>
</list>
</property>
<property name="owner" value="taobao"/>
<property name="connectTimeout" value="6"/>
<property name="readTimeout" value="0"/>
</bean>
<!—- HttpService发布Bean,植入了安全策略配置模版 -->
<bean name="/TicketHttpService" class="com.alibaba.common.remoting.http.SecurityHttpInvokerServiceExporter">
<property name="service" ref="ticketManage"/>
<property name="serviceInterface" value="com.alibaba.common.remoting.test.TicketManage"/>
<property name="remoteContractTemplate" ref="remoteContractTemplate" />
</bean>
<!—- Hessian服务发布Bean,植入了安全策略配置模版 -->
<bean name="/TicketService" class="org.springframework.remoting.caucho.SecurityHessianServiceExporter">
<property name="service" ref="ticketManage"/>
<property name="serviceInterface" value="com.alibaba.common.remoting.test.TicketManage"/>
<property name="remoteContractTemplate" ref="remoteContractTemplate" />
</bean>
</beans>
最后需要做的就是生成key,当前key的算法有两种,对称加密和非对称加密,分别用AES算法和RSA算法,注意一旦产生了Key文件,双方就要使用相同的key文件,同一个用户加解密的key文件可以不一致,但是双方的解密和加密文件必须配对使用。
产生key文件的方法如下:
将toolkit-sandbox-remoting.jar所在的位置配置到classpath中,然后通过命令行执行。
生成对称加密key文件命令为:
Java com.alibaba.common.remoting.cryption.KeyGenTool genkey 文件目录 文件名
生成非对称加密key文件命令为:
Java com.alibaba.common.remoting.cryption.KeyGenTool genkeypair 文件目录 文件名
这样你分别会在文件目录中找到对应得文件,后缀名为.ky
相关推荐
基于NIO的远程调用框架的设计与实现 master
#资源达人分享计划#
基于Java的源码-brap(Java远程调用框架 BRAP).zip
基于Java的实例源码-brap(Java远程调用框架 BRAP).zip
基于Java的实例开发源码-brap(Java远程调用框架 BRAP).zip
基于java aio 的RPC 远程调用框架 组件介绍 Serializer 序列化和反序列的工具类,项目的实现为基于Gson的序列化工具 IOHandler 从Channel中读取数据并交由Serializer处理的类,本身是异步读取数据 在读取数据时 提供...
该框架提供了一种简单而高效的方式来实现跨平台的远程过程调用。 描述: 这个博客资源详细介绍了如何使用Sanic框架构建一个强大而灵活的jsRpc框架,以便在不同的前端和后端应用之间进行远程过程调用。jsRpc是一种...
节点远程服务调用。相比于传统基于Java序列化+BIO(同步阻塞IO)的通信框架,性能提升了8倍多。 事实上,我对这个数据并不感到惊讶,根据我5年多的NIO编程经验,通过选择合适的NIO框架,加上高性能的压缩二进制编...
适合学习/练手、毕业设计、课程设计、期末/期中/大作业、工程实训、相关项目/竞赛学习等。 项目资源具有较高的学习借鉴价值,也可直接拿来修改复现。可以在这些基础上学习借鉴进行修改和扩展,实现其它功能。 可下载...
RPC(Remote Procedure Call )——远程过程调用,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。RPC协议假定某些传输协议的存在,如TCP或UDP,为通信程序之间携带信息数据。在OSI...
本文将XMPP协议、H.264技术以及Z-Wave无线传感器网络技术相结合,构建具备远程监控技术的智能家居系统,且在XMPP协议框架的基础上实现P2P数据传输。整个系统由设备端、客户端和Openfire服务器三部分构成。系统中传输...
运用面向对象思想和面向服务设计思想完成系统的框架设计,研究以 Zookeeper 作为 Dubbo 服务的注册中心来实现远程服务的调用,并配合使用 Nginx 负载均衡来实现后台服务器的合理调度、研究利用 Mycat 数据库中间件...
基于分布式设计思想, 采用Dubbo框架将二维码支付的业务处理划分为多个服务注册在Zookeeper集群上, 由网关模块作为服务的消费者通过远程方法调用获取相应交易的服务。联机模块的业 务处理采用控制层,业务逻辑处理...
该框架实现了同一台机器的不同进程之间或不同机器之间的服务调用。它适用于将单体架构系统拆….zip 适合学习/练手、毕业设计、课程设计、期末/期中/大作业、工程实训、相关项目/竞赛学习等。 项目资源具有较高的学习...
RPC 指的是远程调用协议,也就是说两个服务器交互数据。 2.Dubbo的由来? 互联网的快速发展,Web应用程序的规模不断扩大,一般会经历如下四个发展阶段。 Dubbo的主要应用场景? 透明化的远程方法调用,就像调用本地...
具体参考博客《【远程调用框架】如何实现一个简单的RPC框架(五)优化三:软负载中心设计与实现》http://blog.csdn.net/u013177446/article/details/70677800
面向接口代理的高性能RPC调用:提供高性能的基于代理的远程调用能力,服务以接口为粒度,为开发 者屏蔽远程调用底层细节。 智能负载均衡:内置多种负载均衡策略,智能感知下游节点健康状况,显著减少调用延迟,提高...
DUBBO是一个分布式服务框架,致力于提供高性能和透明化的RPC远程服务调用方案,是阿里巴巴SOA服务化治理方案的核心框架,每天为2,000+个服务提供3,000,000,000+次访问量支持,并被广泛应用于阿里巴巴集团的各成员...
rpc_ts:TypeScript中的远程过程调用变得简单 :crossed_fingers: rpc_ts是用于在TypeScript中进行类型安全的的框架。 它不使用诸如或类:服务全部使用功能强大的TypeScript类型系统定义。 此方法特别适合于缩短依赖...
skynet_fly是基于skynet扩展的可以快速开发web,游戏,和需要rpc调用的框架。 使用skynet_fly的好处: * 支持不停服更新。 * 一键生成skynet的配置文件和skynet_fly的配置文件以及配套shell脚本。 * 对匹配房间类...