二零二三年一月第一周技术周报

时间进入二零二三年,今年是将一个辛苦的一年。今年将面临几方面的挑战,一个是将原先部署在物理服务器上的数据都迁移上云。然后就是,加快培养几个团队新人,让他们尽快承接目前的主要业务所涉及的服务,并且要求能够独立解决用户问题并对服务做出优化。这样我就能将一些工作转交到他们名下,专注今年预估耗时较长的重要目标。还有就是,个人的在技术和其他方面学习也到了一个攻坚阶段,这些方面决定了我未来7~8年的人生方向。

这一周,我的主要的精力在几个服务的日志框架与日志追踪的设计与规范上。首先是解决日志追踪的问题,为了能够跨服务地对调用过程中产生的日志进行统一的追踪,需要现将TraceId统一。但是目前这几个服务TraceId的类型层次不齐,有使用Long类型的也有用字符串的。并且,这些服务所使用的语言和技术栈也不一致。直接使用一些标准的分布式追踪框架中的TraceId应该无法支持所有服务目前的情况,只能用在一些技术栈比较新的服务上。

所以,从兼容性与改造的简洁性考虑,准备采用自定义生成的Long类型的数值作为TraceId并且限定位数为16位。前四位以99开头,作为统一TraceId的特征,然后剩余两位标识服务。接下来4位为当前的微秒数,最后的8位为两组四位随机数拼接。虽然说这种TraceId并不能保证唯一性,但是在当前这种情况下是足够用的。如果服务为Java技术栈,生成TraceId需要充分考虑到线程竞争的情况,最好为每个线程分配一个随机数发生器。或者,直接使用TreadLocal。

Java服务在处理请求时,会提取请求中的TraceId。如果TraceId是99开头的,就不生成新的TraceId了。如果不是的话,按照上述方式产生TracId并存储于MDC中。当遇到异步执行的时候,需要注意拷贝MDC中的内容到旁线程,不然会丢失追踪信息。当需要调用下游服务时,需要将存储的TaceId传递给下游服务。最后,当请求处理完毕时,需要清空MDC,防止污染下一个请求的追踪信息。