一、为什么要纠结「业务埋点」和「全自动探针」的平衡?
1.1 全自动探针的「省心」和「别扭」
现在用SkyWalking这类分布式追踪工具,大多是直接挂Agent就完事——系统会自动记录每个请求的链路:从用户发起,到接口、数据库、第三方服务的每一步耗时,相当于给请求拍了全程录像,不用手动埋一行代码,省了好多事。但问题是,自动探针只会记录通用信息:比如接口路径、HTTP状态码、请求总耗时,不会带你的业务细节:比如这个请求是给哪个订单用的?是微信支付还是支付宝?排查问题时,就像看录像只看到了“人走了一段路”,不知道这个人要去哪、为啥走慢了,还是不够顺手。
1.2 手动自定义埋点的「灵活」和「麻烦」
手动补业务埋点的好处是:想加啥加啥,比如给订单接口加个“订单ID”标签,查问题时搜这个标签就能直接定位对应链路。但坏处也明显:每个要加的地方都要写代码,比如给每个业务方法都加埋点,漏了一个就少了关键信息,改需求时还要跟着改埋点,太耗精力。这时候就需要找个中间地带:不用全自动,也不用全手动,用自定义Span和标签把业务细节补到自动探针的链路里。
二、用SkyWalking自定义Span和标签:怎么补「业务细节」
2.1 先搞懂核心工具(以Java Spring Boot为例,单一技术栈)
我们就用最常用的Spring Boot + SkyWalking Agent来演示,整个过程不用复杂配置,只需用SkyWalking提供的轻量API,不用重写任何业务逻辑。首先明确技术栈:Java + Spring Boot 2.7 + SkyWalking Agent 8.15,全程只用到SkyWalking的Tag和TraceContext工具类,没有额外依赖。
直接上示例代码,注释里会讲每一步的作用:
// Java: Spring Boot + SkyWalking 自定义标签示例
import org.apache.skywalking.apm.toolkit.trace.Tag;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class OrderController {
// 下单接口,自动探针会默认记录这个接口的链路,我们只加业务细节标签
@PostMapping("/api/order/submit")
public String submitOrder(@RequestBody OrderRequest orderReq) {
// 给当前Span(也就是这个接口的时间节点)加业务标签,这些标签会同步到SkyWalking后台
// 标签命名用「业务.模块.属性」的格式,避免混乱,比如「business.order.pay_type」
Tag.tag("business.order.id", orderReq.getOrderId()); // 订单ID,排查问题必须
Tag.tag("business.order.pay_type", String.valueOf(orderReq.getPayType())); // 支付方式,统计用
Tag.tag("business.order.amount", String.valueOf(orderReq.getTotalAmount())); // 订单金额,异常报警用
// 模拟下单核心逻辑,不用改任何代码,标签会绑定到当前请求的链路里
processOrderLogic(orderReq);
return "订单提交成功";
}
private void processOrderLogic(OrderRequest req) {
// 内部方法里也可以加标签,属于同一个Trace(链路),不用额外传ID
Tag.tag("business.order.stage", "inventory_deduct"); // 标记到了扣库存步骤
// 实际业务:调用库存服务、用户积分等
}
// 简化的请求类,实际项目里会有getter/setter,这里为了示例简洁
static class OrderRequest {
private String orderId;
private Integer payType; // 1=微信支付,2=支付宝
private Long totalAmount;
public String getOrderId() { return orderId; }
public Integer getPayType() { return payType; }
public Long getTotalAmount() { return totalAmount; }
}
}
这段代码做的就是:用SkyWalking的Tag工具类,给自动生成的链路节点加了业务专属的标签,不用手动埋任何Span,完全是“补细节”,而不是“重写链路”。
2.2 自定义Span vs 自定义标签:别搞混
很多人会把这两个概念弄混:简单说,Span是链路里的「时间节点」,比如“接口调用”“数据库查询”都是Span;标签是Span上的「备注信息」,就像给这个节点加的便签。大部分业务场景下,给已有Span加标签就够了,不用额外新增Span——只有当你要单独统计某个“异步操作”(比如订单提交后发通知)时,才需要新建自定义Span,平时用标签就足够灵活。
三、必须加自定义Span/标签的3个典型场景
3.1 场景1:排查业务失败时,1秒定位根因
比如用户反馈“微信支付的订单一直没到账”,自动探针的链路只会显示“/api/order/submit 超时”,但不知道是哪个订单的问题。加了business.order.id标签后,直接在SkyWalking后台搜这个订单ID,就能看到整个链路里哪个节点卡了——是微信支付调用超时?还是订单服务参数错误?不用翻几万行日志,这就是标签的核心价值。
3.2 场景2:统计特定业务的性能,不用自己挖数据
公司要统计“微信支付订单的平均耗时”,如果没有自定义标签,要自己在日志里 grep 「payType=1」的请求,再算耗时,太麻烦。用了business.order.pay_type标签后,SkyWalking后台直接就能按这个维度筛选,一键拿到微信支付的平均耗时、错误率,不用写任何监控脚本。
3.3 场景3:链路里区分不同业务模块,避免混乱
如果一个请求同时涉及“用户中心”“订单服务”“积分系统”,自动探针的Span都是通用名称,很难区分。加个business.order.module标签,就能在链路里一眼看到哪个节点属于订单模块,哪个属于积分模块,排查跨模块调用的问题时,不用再费劲猜。
四、平衡的关键:什么时候用自动,什么时候用自定义
4.1 全自动探针的适用场景
自动探针的优势是“通用信息全记录”,这些信息完全不用手动加:比如接口路径、HTTP状态码、请求总耗时、数据库调用耗时、MQ发送记录等。这些都是每个请求必然有的信息,自动探针已经做的很好,强行重复埋点会增加代码量,还可能重复计数。
4.2 手动自定义的触发条件
只有满足两个条件才需要加自定义Span/标签:第一,这个信息是业务专属(不同公司/项目的业务不一样,自动探针没法预定义);第二,这个信息是排查/统计必须用的,加了能帮你省时间。比如订单ID是每个业务都有的,而且排查问题必须,所以要加;而“请求时间”是通用信息,自动已经有了,不用再加。
4.3 平衡的优缺点:只加有用的,别过度
优点:减少80%的排查时间,SkyWalking后台的链路信息直接能满足业务需求,不用自己写工具挖数据;性能影响极小,SkyWalking的Tag方法是轻量级API,几乎不会增加服务开销。缺点:如果乱加标签,比如每个请求加“当前时间”“服务器IP”这类无用信息,会增加SkyWalking的存储成本,后台筛选也会变卡,所以要遵循“够用就好”的原则,只加业务必须的标签。
五、踩过的坑:这些注意事项别忽视
5.1 异步方法里别直接用Tag,要绑定上下文
如果把自定义逻辑放到异步线程里(比如用CompletableFuture),直接加Tag会把标签打在异步线程的Span上,而不是原来的请求Span,相当于把便签贴错了地方。正确做法是用SkyWalking提供的ContextRunnable绑定上下文,示例如下:
// 错误做法:异步方法直接加Tag,上下文丢失
CompletableFuture.runAsync(() -> {
Tag.tag("business.order.notify", "send_alert"); // 标签属于异步线程,不是原请求链路
});
// 正确做法:用SkyWalking的ContextRunnable绑定上下文
import org.apache.skywalking.apm.toolkit.concurrency.ContextRunnable;
CompletableFuture.runAsync(new ContextRunnable(() -> {
Tag.tag("business.order.notify", "send_alert"); // 标签会绑定到原请求链路,正确
}));
5.2 标签的key要统一,别乱起名
比如有的地方用“orderId”,有的用“order_id”,有的用“business.order.id”,SkyWalking后台会把这些当成三个不同的维度,统计和筛选会出错。最好提前定好公司级的标签命名规范,比如统一用「业务.模块.属性」的格式,像示例里的business.order.id,一目了然。
5.3 别过度自定义Span,会把链路搞乱
很多人会觉得“加更多Span更细”,但其实大部分场景下,给现有Span加标签就够了,自定义Span只会让链路变的很长,看起来很乱。只有当你要单独统计某个和主业务链路分离的操作(比如第三方支付回调、异步发通知)时,才需要新增自定义Span,平时不用加太多。
六、总结
其实业务埋点和自动探针的平衡,本质是:用自动探针做「通用信息的基础埋点」,用自定义Span和标签做「业务细节的补充」,不用为了省事全靠自动探针,也不用为了精准全手动埋点。SkyWalking的工具已经把这个平衡做的很轻量,你只要记住:只加业务必须的标签,只在需要单独统计的地方加自定义Span,就能兼顾省心和精准,排查问题、统计性能时都会事半功倍。
Comments