RPC接口设计的一些想法

191226-head-rpc

RPC 项目结构

RPC项目一般会包含两个模块(module),xx-rpcxx-server(可能命名上有所不同),以demo项目为例:

1
2
3
4
5
6
7
8
9
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>1.0</version>
<packaging>pom</packaging>

<modules>
<module>demo-rpc</module>
<module>demo-server</module>
</modules>

其中demo-rpc定义了对外暴露的接口和对象,最终会被打成jar提供给外部使用;而demo-server即为一个独立的服务,依赖demo-rpc并实现对应的接口。

RPC 接口设计的一些想法

单参数接口

接口使用单参数,会解决一部分RPC接口重载的问题。单参数扩展性强,如需要添加查询属性,只需修改查询请求对象,而无需新增请求接口。

如我们会经常看到这种接口:

1
2
3
4
5
6
public interface ExampleService{
// 除列表查询外,用户查询,分页查询等也是如此
List<Example> list(String param1, String param2);
List<Example> list(int param3);
List<Example> list(String param1, String param2, int param3);
}

如果我们换成单参数接口:

1
2
3
4
5
public interface ExampleService{
Example get(Query query);
List<Example> list(ListQuery query);
Page<Example> page(PageQuery query);
}

单参数可以统一继承AbstractQueryRequest对象,我们可以在AbstractQueryRequest中定义一些公共属性,如clientIprequestId等,同时更方便的做统一日志记录等操作。

接口异常设计

接口异常设计在于如何通过区分出系统异常与业务异常,系统异常通过对客户端抛出Exception,由客户端处理;业务异常可以封装一个Response对象,一般其中定义了是否成功以及错误信息等:

1
2
3
public interface ExampleService {
RpcResponse op() throws ExampleException;
}

异常与熔断

RPC接口调用失败是常态,所以一般不会直接让客户端直接调用RPC接口,而会在RPC接口上封装一层,用来熔断,降级等(如使用Hystrix):

1
2
3
4
5
6
7
8
9
10
public class ExampleServiceProxy {

@Resource
private ExampleService exampleService;

@HystrixCommand(fallbackMethod = "opFallback")
public void op() throws ModuleAException {
exampleService.op();
}
}

参考

设计 RPC 接口时,你有考虑过这些吗?
远程接口设计经验分享
RPC调用接口设计