咱们不生产数据,咱们只是数据的搬运工。
背景
- 现有零碎操作日志都扩散在各个域的零碎中,而且没有造成标准的零碎。导致排查线上问题全是去日志零碎各种搜,效率很低。
- 咱们针对零碎调用链路有 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<BizResult> parse(AccessLogData accessLogData) {
// 响应后果
String responseData = accessLogData.getResponseData()
// 执行工夫
String takeTime = accessLogData.getTakeTime()
// http 返回 code 码
String httpStatus = accessLogData.getHttpStatus()
// 获取 uid
String uid = AccessLogUtils.getUid(accessLogData)
List<String> applyNoList = this.analyzeApplyItemNo(responseData);
List<BizResult> 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<String> analyzeApplyItemNo(String responseData) {List<String> 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