【得物技术】交易轨迹系统
我们不生产数据,我们只是数据的搬运工。
背景
-
现有系统操作日志都分散在各个域的系统中,而且没有形成规范的系统。导致排查线上问题全是去日志系统各种搜,效率很低。
-
我们针对系统调用链路有trace串联,跨域查问题很爽。但是我们对单据纬度没有trace串联,单据流转对于我们来说是黑盒。
-
开发人员对自己的功能线上情况不清楚,比如:每天卖家发货量多少?不清楚;成功率多少?不清楚;平均响应多少?不清楚;针对当前量,我们是不是需要做一些优化?其实有时候并不是不去关注,只是没有一个很直观的系统去很直观的呈现出来。
-
为了解决上述问题,交易轨迹系统就应运而生了。
实现思路
怎样去埋数据?
1. 方案一:手动埋点(不推荐)
对现有系统侵入性较高,而且埋点对系统稳定性有一定的影响,不到万不得已不推荐。但是我们提供了这项功能。支持三种接入方式,feign、dubbo和rocketmq。
2. 方案二:日志清洗(推荐)
怎样对现有系统不改造,利用现有的资源去寻找事件action?我们发现access.log可以完美的利用起来。但是有一些超时任务和mq触发的任务没有access.log,现阶段需要考虑其他方式接入。后续我们考虑提供公共工具,将mq和超时任务触发的动作,写入access.log并提供全套的清洗入库套件。
3. 方案三:binlog(不推荐)
为什么不推荐,因为binlog拉取不到入参出参,对排查问题没有太大的作用。但是有一点优势很明显,我们可以追踪前后两次的表更。比如:修改地址(A地址->B地址)
怎样去数据清洗?
1. 功能独立
和业务系统隔离,独立一套系统去做数据清洗
2. 实时生效
利用groovy脚本做清洗逻辑,脚本写好后保存实时生效。
3. 数据扩展
日志里面的数据不满足埋点需求,我们提供了dubbo和feign的扩展,可以去业务系统查询数据
4. 批量操作支持
批量操作会涉及到多个单号的流转,脚本默认返回List,对多个单号进行埋点,支持一次解析,多条数据落库
5. 主子单号支持
(同理批量操作)
6. 日志太复杂?解析费劲?
针对日志分析,我们提供的公共的数据获取工具,直接调用方法即可
例子(寄售申请):
package com.shizhuang.duapp.trade.script.biz.deposit.js import com.alibaba.fastjson.JSONArray import com.alibaba.fastjson.JSONObject import com.google.common.collect.Lists import com.shizhuang.duapp.trade.cycle.api.resultdata.BizResult import com.shizhuang.duapp.trade.cycle.api.script.AccessLogToBizResultBaseScript import com.shizhuang.duapp.trade.cycle.api.sourcedata.AccessLogData import com.shizhuang.duapp.trade.cycle.api.util.AccessLogUtils /** * @program: trade-cycle-center * * @author: 小猪佩奇* * @create: 2020-11-20 17:08 * */ class ConsignApplyCreate2BizResult extends AccessLogToBizResultBaseScript { List parse(AccessLogData accessLogData) { // 响应结果 String responseData = accessLogData.getResponseData() // 执行时间 String takeTime = accessLogData.getTakeTime() // http 返回code码 String httpStatus = accessLogData.getHttpStatus() // 获取uid String uid = AccessLogUtils.getUid(accessLogData) List applyNoList = this.analyzeApplyItemNo(responseData); List bizResultList = Lists.newArrayList(); for (applyItemNo in applyNoList) { BizResult result = new BizResult() result.setOperatorId(uid) result.setOperationBizNo(applyItemNo) result.setOperationTime(accessLogData.getOperationTime()) result.setOperationSubType("app寄售申请") result.setOperationTrace(accessLogData.getOperationTrace()) result.setOperationCostTime(Long.valueOf(takeTime)) result.setOperationResult("200" == httpStatus ? 0 : 1) //result.setOperationExtend() result.setOperationDetailReq(accessLogData.getPayload()) result.setOperationDetailResp(accessLogData.getResponseData()) bizResultList.add(result); } return bizResultList; } /** * 分析单号 * @param responseData * @return */ List analyzeApplyItemNo(String responseData) { List list = Lists.newArrayList() JSONObject jsonObject = JSONObject.parseObject(responseData) JSONObject data = jsonObject.getJSONObject("data") JSONObject applyProduct = data.getJSONObject("applyProduct") if (Objects.isNull(applyProduct)) { return list } JSONArray applyItems = applyProduct.getJSONArray("applyItems") if (Objects.nonNull(applyItems)) { for (Object applyItem : applyItems) { JSONObject parseObject = JSONObject.parseObject(applyItem.toString()) String applyItemNo = parseObject.getString("applyItemNo"); list.add(applyItemNo); } } return list } }
怎样去做数据呈现?
1. 单据纬度

寄存单交易轨迹

客服工单轨迹
查询时段段内,单据的流转轨迹(支持跨域跨系统展示)。根据来源数据和结果数据,排查问题根源。如需查看详细日志,可以根据traceId去日志系统去查看详细trace日志。
2. 人纬度
统计时间段内用户的操作行为,方便排查某个时间段内用户的操作。
怎样自定义图形化?
TDengine时序数据库存储的存储的数据都是带有时间戳的,且本身很好地支持时间维度的聚合,正好可以结合grafana对操作日志中的数据进行分析,展示各类业务运转的情况。
系统接入
access log方式接入
-
下载脚本项目,编写脚本代码
-
新增事件脚本类,将脚本代码配置到交易轨迹系统
-
添加路由规则,关联事件和脚本
rocketMq方式接入
mq接入方式和rpc方式相同,各业务系统把数据封装好,通过硬编码的方式将数据发送到mq,轨迹系统订阅消息进行数据清洗并持久化。有时候获取事件不是很方便,通过mq的方式接入也未尝不是一种好的方式。
扩展
-
在存储上我们支持跨度一年的轨迹查询,在存储上已经做过优化,接入方可以不考虑存储问题。
-
在和财务系统、客服系统的对接中。我们发现还有更多的方向去扩展功能,不仅仅是局限于交易轨迹。
-
财务系统需要记录和第三方交互的请求报文,排查问题的时候直接通过单号快速查询第三方报文。
-
客服系统需要记录客服会话的生命周期,通过会话id可以直观的查看会话链路。并且可以通过客服id可以快速统计客服的接入量统计。
-
后续会加强图形化的功能和简易数据分析的能力
-
理论上我们只提供了一种存储能力,规范了数据存储的格式。具体怎样使用,使用方可以自定义。
-
最后打个广告,欢迎大家接入。
文/得物技术 Ambition