由grpc的interceptor的trace log理解client和server端处理流程

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/singgel/article/details/90897557

代码:

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>用于监听服务端回复的消息,另一部分是针对客户端请求调用的一系列过程,如下代码流程所示:

该类中方法都是抽象方法,规定了整个调用顺序,如下:

call = channel.newCall(unaryMethod, callOptions);

call.start(listener, headers);

call.sendMessage(message);//消息发送

call.halfClose();//请求端关闭发送通道

call.request(1);

// wait for listener.onMessage()


在ClientCall的子类中有ForwardingClientCall<ReqT, RespT>,该类用于包装ClientCall,然后实现委托嵌套调用,里面方法都如下代码所示:

@Override

public void start(Listener<RespT> responseListener, Metadata headers) {

    delegate().start(responseListener, headers);

}

@Override

public void request(int numMessages) {

    delegate().request(numMessages);

}

之所以要实现ClientInterceptor接口,因为Channel本身也是可以嵌套的类,所以创建ClientCall也是被一层一层的调用.

2.对于客户端收到的回复拦截

通过ClientCall的静态内部类Listener来实现,该Listener也是可以嵌套的,其内有如下方法:

public void onHeaders(Metadata headers) {}

public void onMessage(T message) {}//消息正常到达

public void onClose(Status status, Metadata trailers) {}//消息通道关闭

public void onReady() {}

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>用于监听客户端发送过来的消息,另一部分是针对客户端回复调用的一系列过程,如下代码流程所示:

该类中方法都是抽象方法,规定了整个调用顺序,如下:

// wait for listener.onMessage()

call = channel.newCall(call, headers, next);

call.sendMessage(message);

call.sendHeaders(headers);

call.close(status, trailers);}//消息通道关闭

next.start(call, headers)

通过ClientCall的静态内部类Listener来实现,该Listener也是可以嵌套的,其内有如下方法:

public void onMessage(T message) {}//请求消息到达

public void onHalfClose() {}//发送端关闭连接的发送通道

public void onCancel() {}

public void onComplete() {}

public void onReady() {}

2.对于服务端的回复拦截

在ServerCall的子类中有ForwardingServerCall<ReqT, RespT>,该类用于包装ServerCall,然后实现委托嵌套调用,里面方法都如下代码所示:

public void sendMessage(RespT message) {}//消息发送

public void request(int numMessages) {}

处理流程:

(本图的流程是将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://stackoverflow.com/questions/39797142/how-to-add-global-exception-interceptor-in-grpc-server?noredirect=1&lq=1

https://moeyui.cn/%E5%BC%80%E5%8F%91/d1717587.html

http://doc.oschina.net/grpc?t=60134

https://juejin.im/entry/59bb30f76fb9a00a616f1b73

https://yq.aliyun.com/articles/679654

猜你喜欢

转载自blog.csdn.net/singgel/article/details/90897557