如何构建一个简单的RPC调用
1、什么叫RPC?
RPC构成
- RPC Consumer
- RPC Provider
- ConfigServer
- 1、
Provider
启动ConfigServer
注册服务 - 2、
Consumer
启动ConfigServer
订阅服务, - 3、发起调用
Consumer
—>Provider
- 4、响应调用
Consumer
<—Provider
2、什么是 Netty
? https://netty.io/
3、现有的开源的项目是否使用了 Netty
?
- Dubbo
- Grpc
- Spark
- ….
4、RPC Provider
启动
Netty Server
方式启动Rpc
服务的注册
5、RPC Consumer
启动
Netty Client
方式启动RPC
泛化调用、通过字节码基于反射来实现远程调度Consumer
服务订阅- 启动时建立长连接
6、从第四可以看出,多个 Provider
是由一个 NettyServer
提供的,通过 HandlerMap
映射找到对应的 Ioc Bean
,完成服务调用
服务端
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 100)
.handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline p = ch.pipeline();
p.addLast(new RpcEncoder(RpcRequest.class));
p.addLast(new RpcDecoder(RpcResponse.class));
p.addLast(new RpcHandler());
}});
// Start the server.
ChannelFuture f = b.bind(PORT).sync();
// Wait until the server socket is closed.
f.channel().closeFuture().sync();
} finally {
// Shut down all event loops to terminate all threads.
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
BossGroup
-> 处理客户端的请求EventGroup
—> 处理IORead/Write
操作、执行任务系统Task、定时任务ChildChannelHandler
方式是对ChannelPipeline
的设置、ChannelPipeline
是相当于任务链的模式, 是一串ChannelHandler
的实例ChannelHandlerContext
是ChannelPipeline
和ChannelHandler
的关系- 每个链接对于
Sever
端都会创建一个Channel
,可以将Channel
理解为Connection
(其实真正的是Connection
属于Channel
的一部分) - 每个
Channel
都有一个自己的唯一的ChannelPipeline
操作,对于其他的Channel
的ChannelPipeline
是隔离的 RPC Handler
是我们对于自己的找寻RPC
服务处理的Handler
实现RPC Encoder
是我们对于自己的找寻RPC
序列化的编码的Handler
实现RPC Decoder
是我们对于自己的找寻RPC
序列化的解码的Handler
实现
客户端
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
b.group(group)
.channel(NioSocketChannel.class)
.option(ChannelOption.TCP_NODELAY, true)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline p = ch.pipeline();
p.addLast(new RpcEncoder(RpcResponse.class));
p.addLast(new RpcDecoder(RpcRequest.class));
p.addLast(new RpcClientHandler());
}});
// Start the client.
ChannelFuture f = b.connect(HOST, PORT).sync();
// Wait until the connection is closed.
f.channel().closeFuture().sync();
} finally {
// Shut down the event loop to terminate all threads.
group.shutdownGracefully();
}
7、RPC
序列化
- 二进制数据
- Hessian
- Avro
- ProtoBuffer (Protobuf)
- JSON
- XML
8、关于 RPC
的实现思考与技术讨论
- 业务方法、因为是收到请求消息而触发的后续动作调用,不做额外设置,肯定是使用的
WorkGroup
里面的线程操作的。 而作为业务层,不应该与底层关联,应该切割开来,势必会引入真的业务侧线程池。 那么如何引用、怎么引用?(关于 业务线程池 与WorkGroup
的EvenLoop
的思考 ) - 关于
RPC
调用大部分是同步的调用,而Netty
底层是完全异步事件机制,在RPC框架层面如何实现同步的调用方式的? - 基于
TCP
的长链接调用,在RPC
上你会想到其他的哪些东东? - 在此环境下,我没有介绍
RPC
服务于 IOC容器的结合,可以思考一下,如何做到 注解机制、JAVA CONFIG
机制、XML SCHEMA
机制来做?- GUICE
- SPRING
- SPI
- ….