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

posted @ 2020-07-09 10:40  演说家  阅读(390)  评论(0编辑  收藏  举报