Skip to content

LuckyZhanJava/slow-rpc

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

6 Commits
 
 
 
 
 
 

Repository files navigation

slow rpc:一个简单的rpc实现

1.简单实现

总的来说一个rpc实现和kafka的api实现类似,为每个调用包含一个唯一id,然后序列化调用参数为byte[],把idbyte[]组成通用request,服务端接收request后解析id和参数byte[],根据id查找方法,然后调用方法,最后序列化返回值后转为response写回客户端。

在这个基础上做一些改动就可以实现简单的rpc框架。

  1. 首先要用到Proxy.newProxyInstance(...)为接口生成代理,在InvocationHandler中可以拿到调用的methodargs
  2. method生成唯一id供服务端匹配,使用:interfaceName + methodName + parameterTypes可以确保id唯一。
  3. 序列化methodidargs组成request发送请求。
  4. 服务端解析id查找method,使用args调用方法,产生返回值,以response的形式写回。
  5. 客户端读取response并解析返回值,返回给方法调用即可。

这里在请求和响应部分做了改动。

使用已有的HttpClient库可以轻易实现http协议的requstresponse,但是支持其他类似Dubbo的协议并不容易。

使用netty可以轻松实现新的协议,可以采用类似HttpClient的实现,每次请求创建或者从连接池中取出一个channel,然后执行写入request,一直等到channel读取到一个完整的响应关闭或者释放channel,这样就产生了一个问题,慢连接或者慢方法调用会导致channel频繁创建。

所以这里采用多个调用复用单个channel的实现,因为channel.write总是在eventloop中线性的执行,多个request对象被一个挨一个的写出,然后服务端处理request再把response一个一个的写回即可。在服务端串行调用方法的效率不高,如果改为线程池并发调用则response的写回顺序可能和request的写出顺序不同,为了匹配requestresponse,这里对request进行唯一seqNumber标识,response写回时携带seqNumber即可。

具体实现如下:

  1. 每个request对象都包含一个负责保存响应值的CompletableFuture对象,每次写出request,以seqNumber为key保存requestMap<Long,Request> map中。
  2. client.write(request)调用channel.write(request),然后返回request包含的CompletableFuture对象。
  3. channel.read(...)读取到response对象时,根据responseseqNumber取出匹配的request对象,然后填充CompletableFuture即可。

2.负载均衡,熔断等等支持

这部分的实现主要是依赖Eureka等已有的实现。

整体的实现类似FilterChain,在调用链的末端是实际调用,在调用过程中,可以修改向下传递的参数来控制最后的调用,也可以直接返回结果中断后续的调用。前者通过修改向下传递的server来实现负载均衡,后者则可以在出现熔断时中止调用直接返回错误。

About

slow-rpc

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages