为什么要rpc技术?
主要实现系统的分布式,将各种不同应用分布在不同的机器上,当某台机器要调用某应用时,只需要去访问远端的机器,就可以得到相对应的服务。
所以:远端服务器提供服务;而客户端就像调用本地类一样的使用远端服务;一个基本的rpc框架应该有的目标:
- 分布式;
- 可扩展性;
没有实际的工程经历,暂时只能想到上面的两条。
那要达到上述的两点,系统的基本设计:
- 系统分为客户端和服务端,每台机器同时可以成为客户端和服务端;
- 服务端通过开放端口和暴露服务接口的方式,来响应来自客户端的访问;客户端可指定服务器ip地址,开放端口和服务接口来调用服务器的服务;
- 客户端通过socket将要调用的服务名称和相关的参数发送给服务端,而服务端接收到客户端的服务请求后,完成对应的服务,并且再将结果写回客户端;
- 方便扩展性:服务端的服务以类的方式提供(也即每个服务对应一个类),但为了达到服务端和客户端对具体服务实现的解耦,将服务进行抽象,即抽象出服务接口;
服务端的user case:
Framework.export(端口名,服务类名);
而客户端的user case:
Service gotservice = Framework.refer(服务器地址,端口名,服务类名);
result = gotservice.act();
如上的用例有启发性:
- 调用rpc的过程,在形式上与调用本地服务无差异;
- 第一步:获得远端服务类的引用;第二步:调用服务类的方法;
第一步中的服务类名也很好理解:因为同一种服务也可以多种接口,可以将多种接口存放在服务类中;
问题1:服务器端Framework.export()所谓的暴露某个接口,所谓的暴露到底什么意思?
问题2:客户端调用的第一步在干嘛?返回的到底是什么?第二步又是在干嘛?调用一个方法到底是什么意思?
问题3:已知服务端和客户端是通过socket连接的?那么如何断开这样的链接呢?
问题4:在设计过程中是否使用到阻塞语句?如果有,如何使用NIO来改善性能?
对于问题1:
所谓的暴露接口,代码中看就是如下的简单语句:
HelloService service = new HelloServiceImpl();
RpcFramework.export(service, 1234);
而export方法中主要使用反映技术,该技术中HelloService就只是作为一个object对象。具体使用过程中只有如下的代码:
Method method = service.getClass().getMethod(methodName, parameterTypes);
Object result = method.invoke(service, arguments);
上述代码需要注意其中并没有出现HelloService对象,这就意味着RpcFramework.export()中的代码不对服务类的具体实现依赖,这也就是reflect技术的优势。
问题2:客户端调用的第一步在干嘛?返回的到底是什么?第二步又是在干嘛?调用一个方法到底是什么意思?看看参考的客户端第一步调用:
HelloService service = RpcFramework.refer(HelloService.class, "127.0.0.1", 1234);
for (int i = 0; i < Integer.MAX_VALUE; i ++) {
String hello = service.hello("World" + i);
…
}
而此处的HelloService的定义如下:
public interface HelloService {
String hello(String name);
}
客服端调用过程中,也采用解耦的技术:即HelloService也属于接口。
第一步做的事情:获得服务器端接口的一个“代理“对象;
而第二步做的事情: service.hello("World" + i);
可以认为是对代理对象的一个操作,所有对代理对象的操作最终都会触发代理对象中的invoke方法,而invoke函数做的事情:将被调用的函数名,参数列表或者参数等信息发送到服务器,并且接收来自服务器端的结果。
注:此处发现自己对动态代理的理解还不够;感觉使用不纯熟;
问题3:已知服务端和客户端是通过socket连接的?那么如何断开这样的链接呢?
这个不是问题,客户端每次的invoke就是一次发送数据和接收处理后结果的过程,一次调用的结束,自然就会断开连接。
问题4:在设计过程中是否使用到阻塞语句?如果有,如何使用NIO来改善性能?
服务端的server.accept()属于阻塞语句,如何使用非阻塞技术来改进。
按照上述理解的原理:自己来写个简单的rpc框架。