代码:
https://github.com/singgel/RPC-SkillTree
interceptor原理:
一个小例子:https://github.com/singgel/java-base/tree/master/java-intercept
ClientInterceptor:
https://github.com/singgel/SpringBoot-Templates
根据文档描述,作用在传输channel和本地存根stub之间,用于:
-
-
- 向标头元数据添加凭据
- 记录和监控呼叫行为
- 请求和响应重写
-
1.针对客户端调用前的拦截
(ClientCall是针对客户端要调用的方法的)
ClientCall该抽象类就是用来调用远程方法的,实现了发送消息和接收消息的功能,该接口由两个泛型ReqT和ReqT,分别对应着请求发送的信息,和请求收到的回复.
ClientCall抽象类主要有两个部分组成,一是public abstract static class Listener<T>用于监听服务端回复的消息,另一部分是针对客户端请求调用的一系列过程,如下代码流程所示:
该类中方法都是抽象方法,规定了整个调用顺序,如下:
|
在ClientCall的子类中有ForwardingClientCall<ReqT, RespT>,该类用于包装ClientCall,然后实现委托嵌套调用,里面方法都如下代码所示:
|
之所以要实现ClientInterceptor接口,因为Channel本身也是可以嵌套的类,所以创建ClientCall也是被一层一层的调用.
2.对于客户端收到的回复拦截
通过ClientCall的静态内部类Listener来实现,该Listener也是可以嵌套的,其内有如下方法:
|
ServerInterceptor:
https://github.com/singgel/SpringBoot-Templates
ServerCall是针对ClientCall的
根据文档描述,作用在client过来的请求被ServerCallHandler分发之前,用于:
-
-
- 执行有效的身份验证凭据
- 记录和监控呼叫行为
- 将呼叫委托给其他服务器
-
1.针对客户端调用前的拦截
(ServerCall是针对ClientCall的,与client方向刚好相反)
ServerCall该抽象类就是用来调用远程方法的,实现了发送消息和接收消息的功能,该接口由两个泛型ReqT和ReqT,分别对应着请求发送的信息,和请求收到的回复.
ServerCall抽象类主要有两个部分组成,一是public abstract static class Listener<T>用于监听客户端发送过来的消息,另一部分是针对客户端回复调用的一系列过程,如下代码流程所示:
该类中方法都是抽象方法,规定了整个调用顺序,如下:
|
通过ClientCall的静态内部类Listener来实现,该Listener也是可以嵌套的,其内有如下方法:
|
2.对于服务端的回复拦截
在ServerCall的子类中有ForwardingServerCall<ReqT, RespT>,该类用于包装ServerCall,然后实现委托嵌套调用,里面方法都如下代码所示:
|
处理流程:
(本图的流程是将server的异常捕获后,封装为StatusRuntimeException传递)
issues参考:
client:
https://github.com/grpc/grpc-java/issues/2145
https://grpc.github.io/grpc-java/javadoc/io/grpc/ClientCall.Listener.html
server:
https://github.com/grpc/grpc-java/issues/5489
https://grpc.github.io/grpc-java/javadoc/io/grpc/ServerCall.Listener.html
exception部分:
https://github.com/grpc/grpc-java/issues/1552
https://github.com/grpc/grpc-java/issues/3434
解决:
目前日志记录下:
接口方法、请求源、响应时间、traceId(traceId由xueqiu-toolbox的IDBox获取)
异常是方法的在onHalfClose()方法中捕获,因为异常的发生将会导致channel直接调用cancel,导致channel关闭:
server端异常是由grpc的java框架封装好的Status类,将异常向client端传递(由Status的枚举Code类中INTERNAL(13)标记)
client端将server的异常信息接收到,也和server一样全部记录,前后由traceId形成一条完整链路
client:
server:
备注:
之所以将server端的异常封装,是为了保证整个traceing链路完整,本次的修改目前主要是为了支持当前版本没有traceing工具时的临时策略(为此采用了Status传递方式)
方法:
代码修改依据于interceptor原理和Issues参考:
主要实现:
ClientInterceptor:
重写sendMessage和onMessage方法,在发送和接收处做记录(可用作网络问题诊断)
重写onClose方法,解析Status类,记录trace的log日志
ServerInterceptor:
重写onMessage和sendMessage方法,在发送和接收端做记录(可用作网络问题的诊断)
重写onHalfClose方法,拦截channel关闭,捕获server异常信息
压测记录:
本机压测环境:
-Xmx4g
-Xms4g
-Xmn1g
-Xss256k
-XX:+CMSClassUnloadingEnabled
-XX:PermSize=256M
-XX:MaxPermSize=512M
-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps
-XX:+PrintGCDateStamps
-XX:+UseG1GC
参考资料:
https://skyao.io/learning-grpc/grpc/source_navigating.html
https://moeyui.cn/%E5%BC%80%E5%8F%91/d1717587.html
http://doc.oschina.net/grpc?t=60134