物流KA商家业务监控能力建设与实践
一、背景
在常规的运维及线上故障响应实践中,我们观察到系统监控指标(System-Level Metrics)的异常波动往往与业务监控指标(Business-Level Metrics)的异常呈现高度相关性。具体而言,当系统级监控指标出现异常时,业务级监控指标在绝大多数情况下亦会表现出异常状态。然而,反之则不然,即业务级监控指标的异常并不总是伴随着系统级监控指标的同步异常。
此种现象导致相关职能团队(包括研发、测试、运营等)在业务异常的感知上存在显著滞后性。具体表现为,业务异常的发现往往依赖于终端用户的事后反馈,而非通过实时监控体系的前置预警。这种滞后性可能意味着在问题被识别之前,业务已遭受大范围的负面影响,或已逼近其服务能力的临界阈值,从而对物流的运营稳定性和用户体验造成严重损害。
二、业务监控方案
通用数据监控流程如下图,从埋点输出数据,再到采集数据通过计算聚合得到各项指标,最后根据指标配置阈值进行告警规则设置和通过各类面板进行指标展示。

截止到目前集团内部DevOps平台建设过3个通用的业务监控应用,分别是UMP业务监控、PFinder业务监控和泰山业务监控,KA商家服务在这三个平台都有过一些案例实践,下面分别进行介绍。
2.1、UMP业务监控
UMP的业务监控建设的时间最早,现在也已下线。

但原有已接入的业务监控还在继续运营,比如KA商家服务的一个应用

关于这个应用基于UMP业务监控的实践场景可以参考《记一次大库大表的治理过程》的4.3章节。
2.2、PFinder业务监控
在快运导单业务流程中,一旦包裹数量超出设定阈值,相关订单便会自动迁移至单独的导单分组,由独立机器集群通过限流机制进行处理。在单子转移过程,基于PFinder的业务监控能力进行了埋点追踪,对事业部包裹数量进行统计,实时监控单位时间内的包裹总数,对触发阈值进行告警机制,提前感知系统压力,及时监控系统指标压力。
监控展示如下:

告警规则配置:

告警效果:

2.3、泰山业务监控
泰山业务监控是当前KA商家服务使用场景和业务覆盖最广的,也是本篇要重点介绍的业务监控平台,下面从统一日志格式、编码实践、数据可视化、业务监控告警和最佳实践分别进行介绍。
二、统一日志
2.1、日志格式
针对KA商家的业务特点和应用场景对日志的输出格式进行了统一规范;
|业务域|业务子域|业务场景|渠道来源|商家编码|青龙业主号或事业部编码|密度|结果(Y/N)|结果码|结果码描述|结果子码|结果子码描述|商家单号|订单号|运单号
2.2、举个例子
下面分别举一个业务成功和失败的例子,重点在于ECP、EBU、Y/N。
成功:
|订单域|销售出|下单|50|ECP|EBU|1|Y|200|success|200|success|T20240704000086|ESL1230989|JDV002323
失败:
|订单域|退供出|下单|70|ECP|EBU|1|N|4007|fail|3-01-11020|可销售库存不足|T20240704000086||
三、编码实践
3.1、log4j文件配置
在log4j的xml配置文件里,<Properties>通常都有patternLayout格式化输出的前缀,复用就可以
<property name="patternLayout">%d{yyyy-MM-dd HH:mm:ss.SSS}-%X{PFTID}-%-5p - [%t] %c -%m%n</property>
<Appenders>里添加RollingRandomAccessFile
<RollingRandomAccessFile name="businessFile" fileName="${log_path}/eclp-biz-eclp-isv-business.log"
filePattern="${log_path}/eclp-biz-eclp-isv-business-%i.log">
<PatternLayout charset="UTF-8" pattern="${patternLayout}"/>
<Policies>
<SizeBasedTriggeringPolicy size="1GB"/>
</Policies>
<DefaultRolloverStrategy max="5"/>
</RollingRandomAccessFile>
<Loggers>里设置AsyncLogger的AppenderRef
<AsyncLogger name="BusinessLogger" level="INFO" additivity="false" includeLocation="false">
<AppenderRef ref="businessFile"/>
</AsyncLogger>
3.2、业务日志打印
在代码需要业务监控日志埋点的类文件里定义业务日志Logger
/**
* 业务日志
*/
private static final Logger blogger = LoggerFactory.getLogger("BusinessLogger");
Logger打印日志
blogger.info("|订单域|销售出|下单|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}",
order.getSourceChannel(), order.getShopNo(), order.getDepartmentNo(), 1,
result, code, message, subCode, subMessage,
order.getIsvUUID(), context.getPin(), soNo);
业务逻辑埋点打印业务日志
protected void doProcess(ProcessorContext processorContext) throws Exception {
OrderContext context=buildOrderContext(processorContext);
try {
String soNo = isvSoReceiveService.transportOrder(context);
processorContext.setAttachment(IsvProcessorConstant.PRCS_RTN_ORD_TRANSPORT_SO_NO, soNo);
processorContext.setAttachment(IsvProcessorConstant.PRCS_RTN_SO_IS_REPEAT_ORDER, context.isRepeatOrder());
processorContext.setAttachment(IsvProcessorConstant.PRCS_RTN_ORD_CREATE_SUCC_MSG, context.getCache(CachedKeyConstants.ORDER_CREATE_SUCCESS_ATTACH_MSG, String.class));
processorContext.setBizNo1(soNo);
} catch (Exception e) {
printBusinessLog(context, e);
throw e;
}