传统编码方式转 gRPC 注意事项
# 赋值编码:
1.pbBuilder 设置值时不能为 null
2.pb 定义的类是不可变类,赋值时需要使用 Builder 模式,且每次 builder 都会 new 一个新对象,所以赋值时需要特别留意
3.pbData.setList(),原有 list 属性不会被覆盖,需要手动清除 pbData.clean()
4.entity A 与 pb 类互相拷贝属性时,如果 A 中包含类 B 是不会拷贝的,需要手动处理
5.Controller 接口参数使用 pbBuilder 类模式才能接收到值
# 业务影响:
1.pb 属性都会有默认值,所以业务字段上0,空字符串这些判断处理时需要特别处理
# 框架整合
1.整合 skywalking 时,因为异步调用原因,客户端不能透传 traceId 到服务端,导致服务端日志文件不能输出 traceId,目前采用 grpc 客户端、服务端拦截 + MDC 方式处理
@Component
public class GrpcClientLogInterceptor implements ClientInterceptor {
private static final Logger LOGGER = LoggerFactory.getLogger(GrpcClientLogInterceptor.class);
@Override
public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(MethodDescriptor<ReqT, RespT> method, CallOptions callOptions, Channel next) {
return new ForwardingClientCall.SimpleForwardingClientCall<ReqT, RespT>(next.newCall(method, callOptions)) {
@Override
public void start(Listener<RespT> responseListener, Metadata headers) {
String traceId = MDC.get(LogConstants.MDC_GRPC_TRACE_KEY);
if (StringUtils.isBlank(traceId)) {
traceId = UuidUtils.randomUUIDStr32();
LOGGER.debug("调用方法前未获取 traceId,生成新的 traceId:[{}],methodName:[{}]", traceId, method.getFullMethodName());
}
headers.put(LogConstants.REQUEST_KEY, traceId);
super.start(responseListener, headers);
}
};
}
}
@Component
public class GrpcServerLogInterceptor implements ServerInterceptor {
private static final Logger LOGGER = LoggerFactory.getLogger(GrpcServerLogInterceptor.class);
@Override
public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(ServerCall<ReqT, RespT> serverCall, Metadata metadata,
ServerCallHandler<ReqT, RespT> serverCallHandler) {
final long startTime = System.currentTimeMillis();
String fullMethodName = serverCall.getMethodDescriptor().getFullMethodName();
String traceId = metadata.get(LogConstants.REQUEST_KEY);
if (StringUtils.isBlank(traceId)) {
traceId = UuidUtils.randomUUIDStr32();
LOGGER.debug("调用方法前未获取 traceId,生成新的 traceId: [{}],methodName:[{}]", traceId, fullMethodName);
}
MDC.put(LogConstants.MDC_GRPC_TRACE_KEY, traceId);
LOGGER.debug("server recive traceId: {}", traceId);
LOGGER.debug("Before request [method={}]", fullMethodName);
LOGGER.debug("GRPC Metadata: {}", metadata);
ForwardingServerCall.SimpleForwardingServerCall<ReqT, RespT> serverCall1 =
new ForwardingServerCall.SimpleForwardingServerCall(serverCall) {
@Override
public void sendMessage(Object message) {
super.sendMessage(message);
}
};
ServerCall.Listener<ReqT> listener = serverCallHandler.startCall(serverCall1, metadata);
final String finalTraceId = traceId;
return new ForwardingServerCallListener.SimpleForwardingServerCallListener<ReqT>(listener) {
@Override
public void onMessage(ReqT message) {
LOGGER.debug("GRPC Request: {}", message);
super.onMessage(message);
}
@Override
public void onComplete() {
LOGGER.debug("After request [method={}],grpc request elapsed time:{}ms.", fullMethodName, (System.currentTimeMillis() - startTime));
super.onComplete();
MDC.remove(LogConstants.MDC_GRPC_TRACE_KEY);
LOGGER.debug("After request [method={}], 删除 MDC 中 traceId [{}].", fullMethodName, finalTraceId);
}
};
}
}
public class LogConstants {
// grpc head key
public static final String GRPC_REQUEST_ID = "request-id-bin";
public static final String UTF_8 = "UTF-8";
public static final String MDC_GRPC_TRACE_KEY = "GTID";
/**
* 公共 key,透传 traceid 时的 key
*/
public static final Metadata.Key<String> REQUEST_KEY = Metadata.Key.of(GRPC_REQUEST_ID,
new Metadata.BinaryMarshaller<String>() {
@Override
public byte[] toBytes(String value) {
try {
return value.getBytes(UTF_8);
} catch (UnsupportedEncodingException e) {
return null;
}
}
@Override
public String parseBytes(byte[] serialized) {
try {
return new String(serialized, UTF_8);
} catch (UnsupportedEncodingException e) {
return null;
}
}
});
}
2.Quartz 框架整合 skywalking,不能输出 traceId,处理方案同上面
3.Qrartz 框架的 Job 类因为是采用 AdaptableJobFactory.createJobInstance 方式生成示例,导致不能直接注入 grpc 服务类。
解决方案:业务处理放入到 Spring bean 业务类中,再依赖注入到 Job 实例

浙公网安备 33010602011771号