首先谈谈rpc的实现方式。
就底层实现方式来说,有同步和异步两种方式:
[list]
[*] 1. 同步调用:client发送一次rpc请求到server,在server返回结果之前,在client和server之间建立的connection一直被本次调用hold住,如果有其他的调用想使用此connection发送新的rpc请求,则必须等待。client端接收到server的返回结果之后,释放connection的占用,本次调用结束。
[*] 2. 异步调用:client发送一次rpc请求到server,client只向对应的connection写入请求即可,之后并不hold住connection;其他后续的调用可以继续向相同的connection里写入rpc的调用请求。当server返回结果,client读取每次rpc的对应调用结果。
[/list]
上层对rpc调用的暴露的封装接口,可以是同步和异步的两种方式:
[list]
[*] 1. 同步调用:底层可以是同步方式或者异步的实现方式。这里值得一提的是,底层实现是异步方式,但是对外暴露的封装接口是可以转化成同步的方式的(就是一个简单的技巧而已wait—notify)
[*] 2. 异步方式:底层的实现方式一般也是异步方式。当然底层的实现也是同步,只不多这个时候上层要做额外的异步封装。
[/list]
表 1 rpc调用的处理方式
[table]
|底层实现方式|暴露的接口|处理结果的方式|
|同步|同步|直接读取结果|
|异步|同步|wait-notify处理结果|
|异步|异步|注册回调函数|
[/table]
通过阅读hadoop的rpc实现代码,可以知道,其采用的是底层使用异步发送数据;上层以同步方式暴露接口。因此,有几个问题需要处理(其实,一般的网络调用,也就这些问题):
[list]
[*] 1.怎么标识同一个请求,即服务器返回的结果必须与请求对应起来(切记,这很重要,如果请求1得到请求2的结果,如果服务器没有对这种异常进行处理的话,整个client-server的通信就乱套了,这种情况在实际开发中还真遇到过)。
[*] 2.怎么处理超时情况,一般而言,client-server之间的通信,发送一个请求后,若sever没有返回结果,不会无限制的等待下去,因此都会设置一个超时时间,进行超时处理;
[*] 3.怎么处理异常情况,比如网络出现问题时,connection其实已经失效,这时候读写数据都会发生错误。
[/list]
解决方案:
[list]
[*] 1. 标识同一个请求(call),这很简单,只要保证同一个connection内,给其分配一个惟一id作为标识即可,可根据id找到对应的call
[*] 2.超时也很简单,在创建连接的时候,设置超时时间即可,当超时时,可以标记此次操作失败,但是不一定需要关闭连接;
[*] 3.当网络出现异常时,读写出现错误时,则需要关闭掉连接,处理所有的还没有收到结果的请求。
[/list]
上面都是从client的角度来看的,但是server端来看处理,处理如何呢?
server的处理方式, 我已经在[url]http://jimmee.iteye.com/blog/673212[/url],[url]http://jimmee.iteye.com/blog/765267[/url] 分析过使用每种方式处理请求的问题。
这里再对nio的reactor模式提一下:
[img]http://dl.iteye.com/upload/attachment/572627/40d6dbcb-3081-3690-bacf-e7e6d9f75e91.jpg[/img]
具体的处理方式:
[list]
[*] 1.一个线程来处理所有连接(使用一个Selector)
[*] 2.一组线程来读取已经建立连接的数据(多个Selector,这里的线程数一般和cpu的核数相当);
[*] 3.一个线程池(这个线程池大小可以根据业务需求进行设置)
[*] 4.一个线程处理所有的连接的数据的写操作(一个Selector)
[/list]
就底层实现方式来说,有同步和异步两种方式:
[list]
[*] 1. 同步调用:client发送一次rpc请求到server,在server返回结果之前,在client和server之间建立的connection一直被本次调用hold住,如果有其他的调用想使用此connection发送新的rpc请求,则必须等待。client端接收到server的返回结果之后,释放connection的占用,本次调用结束。
[*] 2. 异步调用:client发送一次rpc请求到server,client只向对应的connection写入请求即可,之后并不hold住connection;其他后续的调用可以继续向相同的connection里写入rpc的调用请求。当server返回结果,client读取每次rpc的对应调用结果。
[/list]
上层对rpc调用的暴露的封装接口,可以是同步和异步的两种方式:
[list]
[*] 1. 同步调用:底层可以是同步方式或者异步的实现方式。这里值得一提的是,底层实现是异步方式,但是对外暴露的封装接口是可以转化成同步的方式的(就是一个简单的技巧而已wait—notify)
[*] 2. 异步方式:底层的实现方式一般也是异步方式。当然底层的实现也是同步,只不多这个时候上层要做额外的异步封装。
[/list]
表 1 rpc调用的处理方式
[table]
|底层实现方式|暴露的接口|处理结果的方式|
|同步|同步|直接读取结果|
|异步|同步|wait-notify处理结果|
|异步|异步|注册回调函数|
[/table]
通过阅读hadoop的rpc实现代码,可以知道,其采用的是底层使用异步发送数据;上层以同步方式暴露接口。因此,有几个问题需要处理(其实,一般的网络调用,也就这些问题):
[list]
[*] 1.怎么标识同一个请求,即服务器返回的结果必须与请求对应起来(切记,这很重要,如果请求1得到请求2的结果,如果服务器没有对这种异常进行处理的话,整个client-server的通信就乱套了,这种情况在实际开发中还真遇到过)。
[*] 2.怎么处理超时情况,一般而言,client-server之间的通信,发送一个请求后,若sever没有返回结果,不会无限制的等待下去,因此都会设置一个超时时间,进行超时处理;
[*] 3.怎么处理异常情况,比如网络出现问题时,connection其实已经失效,这时候读写数据都会发生错误。
[/list]
解决方案:
[list]
[*] 1. 标识同一个请求(call),这很简单,只要保证同一个connection内,给其分配一个惟一id作为标识即可,可根据id找到对应的call
[*] 2.超时也很简单,在创建连接的时候,设置超时时间即可,当超时时,可以标记此次操作失败,但是不一定需要关闭连接;
[*] 3.当网络出现异常时,读写出现错误时,则需要关闭掉连接,处理所有的还没有收到结果的请求。
[/list]
上面都是从client的角度来看的,但是server端来看处理,处理如何呢?
server的处理方式, 我已经在[url]http://jimmee.iteye.com/blog/673212[/url],[url]http://jimmee.iteye.com/blog/765267[/url] 分析过使用每种方式处理请求的问题。
这里再对nio的reactor模式提一下:
[img]http://dl.iteye.com/upload/attachment/572627/40d6dbcb-3081-3690-bacf-e7e6d9f75e91.jpg[/img]
具体的处理方式:
[list]
[*] 1.一个线程来处理所有连接(使用一个Selector)
[*] 2.一组线程来读取已经建立连接的数据(多个Selector,这里的线程数一般和cpu的核数相当);
[*] 3.一个线程池(这个线程池大小可以根据业务需求进行设置)
[*] 4.一个线程处理所有的连接的数据的写操作(一个Selector)
[/list]