传统编码方式转 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 实例