gRPC Server 端请求处理流程
文章目录
初始化
- 创建并启动 ServerTransport
在 Server 启动的时候,最终调用 NettyServer
的 start()
方法,为 ServerBootstrap
添加了 ChannelInitializer
,最终,当有新的连接建立时,会由 NettyServerHandler
调用该类的 initChannel
方法,初始化一个 NettyServerTransport
- io.grpc.netty.NettyServer#start
在初始化 Netty Channel 时,会先创建 NettyServerTransport
,然后调用监听器的 Transport
创建事件,添加一个超时取消任务;
然后会调用 Transport
的 start
方法启动 Transport
b.childHandler(new ChannelInitializer<Channel>() {
@Override
public void initChannel(Channel ch) {
// 构建基于 Netty 的 ServerTransport
NettyServerTransport transport = new NettyServerTransport(/*...*/);
ServerTransportListener transportListener;
synchronized (NettyServer.this) {
// 调用监听器回调,Transport 创建事件
transportListener = listener.transportCreated(transport);
}
// 启动监听器
transport.start(transportListener);
ChannelFutureListener loopReleaser = new LoopReleaser();
channelDone.addListener(loopReleaser);
ch.closeFuture().addListener(loopReleaser);
}
});
- io.grpc.netty.NettyServerTransport#start
在启动 Transport
时,会为当前的 Transport
创建一个处理器,并绑定到 Netty 的 Channel 中
public void start(ServerTransportListener listener) {
this.listener = listener;
// 为 pipeline 创建 Netty Handler
grpcHandler = createHandler(listener, channelUnused);
// 创建 Handler
ChannelHandler negotiationHandler = protocolNegotiator.newHandler(grpcHandler);
ChannelHandler bufferingHandler = new WriteBufferingAndExceptionHandler(negotiationHandler);
// 添加监听器
ChannelFutureListener terminationNotifier = new TerminationNotifier();
channelUnused.addListener(terminationNotifier);
channel.closeFuture().addListener(terminationNotifier);
channel.pipeline().addLast(bufferingHandler);
}
处理请求
当 Server 与 Client 的连接建立成功之后,可以开始处理请求
请求整体处理流程
- 读取
Settings
帧,触发Transport
ready
事件 - 读取
Header
帧,触发FrameListener#onHeadersRead
事件- 由
NettyServerHandler
处理- 根据
Header
里面的信息,获取相应的方法 - 将 HTTP 流转换为
NettyServerStream
- 触发
Transport#streamCreated
事件- 检查编解码、解压缩等信息,创建可取消的上下文
- 初始化流监听器
- 提交
StreamCreated
任务
- 触发
NettyServerStream.TransportState#onStreamAllocated
事件- 提交
OnReady
任务
- 提交
- 根据
- 由
- 执行
StreamCreated
任务- 根据方法名查找方法定义
- 调用
startCall
开始处理- 遍历拦截器,使用拦截器包装方法处理器
- 调用
startWrappedCall
处理- 创建
ServerCallImpl
实例 - 通过方法定义的请求处理器
startCall
方法处理- 创建响应观察器
ServerCallStreamObserverImpl
实例 - 调用
call.request()
获取指定数量的消息- 提交
RequestRunnable
任务获取指定数量的消息
- 提交
- 创建调用监听器
UnaryServerCallListener
- 创建响应观察器
- 创建
ServerStreamListenerImpl
流监听器实例
- 创建
- 执行
OnReady
任务- 调用
UnaryServerCallListener#onReady
处理Ready
事件- 修改
ready
状态 - 如果有
onReadyHandler
任务,则执行
- 修改
- 调用
- 执行
RequestRunnable
任务- 要求指定数量的消息
- 修改等待投递的消息数量
- 调用
deliver
方法投递- 如果有待投递的消息,根据类型进行投递
- 当消息类型是消息体时,处理消息体
- 读取消息体的流
- 调用
MessageFramer.Listener#messagesAvailable
事件,通知新的消息 - 提交
MessagesAvailable
任务
- 当消息类型是消息体时,处理消息体
- 如果有待投递的消息,根据类型进行投递
- 调用
MessageDeframer#close
方法关闭帧- 调用流监听器半关闭事件
- 提交
HalfClosed
任务
- 执行
MessagesAvailable
任务 - 从
MessageProducer
中获取消息,解析为请求对象 - 调用
SeverCall.Listener#onMessage
方法处理消息- 将
request
对象赋值给相应的对象,该对象会在halfClose
时处理
- 将
- 执行
HalfClosed
任务- 调用
invoke
方法,处理业务逻辑- 根据方法 ID,使用相应的实现调用业务逻辑
- 调用
StreamObserver#onNext
发送响应- 发送响应
Header
- 设置编码和压缩的请求头
- 写入
Header
- 发送响应
body
- 将响应对象序列化为流
- 写入响应
- 清空缓存
- 发送响应
- 调用
StreamObserver#onComplete
完成请求- 使用
OK
状态关闭调用- 修改关闭状态
- 调用流关闭事件
- 关闭帧
- 将响应状态加入响应元数据中
- 修改
TransportState
的状态 - 写入响应元数据,发送给客户端
- 使用
- 调用
- 根据方法 ID,使用相应的实现调用业务逻辑
- 冻结响应
- 如果
ready
状态,再次执行onReady
事件 - 当流关闭时,调用
TransportState#complete
事件- 关闭监听器
- 提交
Closed
任务
- 执行
Closed
任务- 调用
stream#complete
事件 - 取消上下文
- 调用
- 调用
1. 读取 Settings 帧
- io.grpc.netty.NettyServerHandler.FrameListener#onSettingsRead
当读取到 Settings 帧时,会调用 onSettingsRead 方法,同时会同时 Transport 监听器 ready 事件
public void onSettingsRead(ChannelHandlerContext ctx, Http2Settings settings) {
if (firstSettings) {
firstSettings = false;
// 通知 Transport ready
attributes = transportListener.transportReady(negotiationAttributes);
}
}
- io.grpc.internal.ServerImpl.ServerTransportListenerImpl#transportReady
会通知 Transport Ready 事件,会遍历 ServerTransportFilter
通知,默认没有 ServerTransportFilter
的实现
public Attributes transportReady(Attributes attributes) {
// 如果有握手超时回调,则取消
handshakeTimeoutFuture.cancel(false);
handshakeTimeoutFuture = null;
// 遍历 TransportFilter,通知 ready 事件并获取 attributes
for (ServerTransportFilter filter : transportFilters) {
attributes = Preconditions.checkNotNull(filter.transportReady(attributes), "Filter %s returned null", filter);
}
this.attributes = attributes;
return attributes;
}
2. 接收 header
当 Server 接收到 Client 发送的 header 后,经过 Netty 处理,最终调用 onHeadersRead
开始处理流
- io.grpc.netty.shaded.io.grpc.netty.NettyServerHandler.FrameListener#onHeadersRead
接收 header 帧
public void onHeadersRead(ChannelHandlerContext ctx, int streamId, Http2Headers headers, int streamDependency, short weight, boolean exclusive, int padding, boolean endStream) throws Http2Exception {
if (NettyServerHandler.this.keepAliveManager != null) {
NettyServerHandler.this.keepAliveManager.onDataReceived();
}
NettyServerHandler.this.onHeadersRead(ctx, streamId, headers);
}
- io.grpc.netty.NettyServerHandler.FrameListener#onHeadersRead
开始处理 header
public void onHeadersRead(ChannelHandlerContext ctx,
int streamId,
Http2Headers headers,
int streamDependency,
short weight,
boolean exclusive,
int padding,
boolean endStream) throws Http2Exception {
if (keepAliveManager != null) {
keepAliveManager.onDataReceived();
}
// 最终会创建流并出发流创建事件
NettyServerHandler.this.onHeadersRead(ctx, streamId, headers);
}
- io.grpc.netty.NettyServerHandler#onHeadersRead
会根据请求的 Header 信息,查找服务和方法,校验请求类型,请求方法,传输编码等内容;然后根据 HTTP2 流 Id,获取对应的流,将其转换为 NettyServerStream
;调用 Transport
的 onStreamCreated
事件
向线程池中提交 StreamCreated
,然后调用 onStreamAllocated
方法通知流 StreamListener
的onReady
事件提交OnReady
任务
private void onHeadersRead(ChannelHandlerContext ctx, int streamId, Http2Headers headers) throws Http2Exception {
try {
// 删除斜杠获取方法限定名称
CharSequence path = headers.path();
// 方法限定名,即包含服务名和方法名
String method = path.subSequence(1, path.length()).toString();
// 获取 HTTP 流
Http2Stream http2Stream = requireHttp2Stream(streamId);
// 将 header 转为 metadata
Metadata metadata = Utils.convertHeaders(headers);
// 创建支持统计的上下文
StatsTraceContext statsTraceCtx = StatsTraceContext.newServerContext(streamTracerFactories, method, metadata);
// 创建流的声明
NettyServerStream.TransportState state = new NettyServerStream.TransportState(
this,
ctx.channel().eventLoop(),
http2Stream,
maxMessageSize,
statsTraceCtx,
transportTracer,
method);
try {
// 获取请求的 authority
String authority = getOrUpdateAuthority((AsciiString) headers.authority());
// 创建 Server 端的流
NettyServerStream stream = new NettyServerStream(ctx.channel(),
state,
attributes,
authority,
statsTraceCtx,
transportTracer);
// 触发监听器,通知流创建事件,查找相应处理器,开始处理流,会提交 StreamCreated 任务到线程池中
transportListener.streamCreated(stream, method, metadata);
// 会提交 OnReady 任务到线程池中,通知 Stream Ready
state.onStreamAllocated();
http2Stream.setProperty(streamKey, state);
}
} catch (Exception e) {
logger.log(Level.WARNING, "Exception in onHeadersRead()", e);
throw newStreamException(streamId, e);
}
}
3. 流创建事件
transportListener.streamCreated(stream, method, metadata);
- io.grpc.internal.ServerImpl.ServerTransportListenerImpl#streamCreated
检查并初始化流的编解码,解压缩等信息;创建可需取消的上下文,选择要执行的线程池,初始化流监听器,最终提交流创建任务
private void streamCreatedInternal(final ServerStream stream,
final String methodName,
final Metadata headers,
final Tag tag) {
final Executor wrappedExecutor;
if (executor == directExecutor()) {
wrappedExecutor = new