订单哨兵OrderSentinel平台介绍

OrderSentinel是什么?

订单哨兵是一个异步数据变更信息采集框架,致力于通过全异步旁路采集技术,构建无侵入高扩展的实时数据变更记录体系,为客服判责、业务审计等提供底层能力支撑,其他各领域的数据变更采集需求可快速接入。

1.1.背景

随着交易业务快速发展,交易量日趋庞大,但是对于每笔订单信息的变化,没有一个统一的记录,无法准确和高效的知道一笔订单:谁在什么时刻,把订单信息从什么改成了什么? 这部分能力的缺失对于客服判责也是一个较大的压力,然而传统数据变更追踪方案上的因强耦合低扩展性核心链路侵入性 等问题,难以支撑高效、稳定的全局数据治理需求,订单哨兵平台应运而生。

1.2.设计理念

在设计之初,我们在数据的采集与构建方面,面临两大挑战:

与核心链路解耦: 订单信息的变更都是在核心操作中完成的,如何在不影响核心操作链路的情况下获取这些变更数据?

高扩展性: 履约、工单、资金等领域将来也会有信息变更记录的需求,如何能让他们也能快速接入?

初期我们考虑了多种方案:

方案概述 系统耦合程度 核心服务影响程度 扩展性 实现难度
一、传统方案: 直接在核心操作中组装变更信息并记录 极高 极差
二、核心链路异步处理: 封装一个SDK,核心服务引入这个SDK,在订单信息变更时,调用SDK异步构建信息变更记录并发送kafka,核心服务中要实现信息构建逻辑。
三、全旁路异步处理: 监听核心操作中的binlog变更 无耦合 无影响 较高

可以看到,方案一二均不能很好的满足我们的设计理念和目标,只是按照普通的功能需求去设计,实现难度较低。但是为了追求完美的设计方案,我们选择了死磕方案三。

2.设计概述

2.1.实现难点

通过binlog监听信息的变更,是一个很好的异步方案,但是在我们交易的场景下,一次用户/司机操作中会修改多张表的数据:

例如用户修改货物资料信息,货物资料信息、操作人信息都记录在了不同的表,而且货物资料是先软删除,再插入新的记录。

如何将这一系列的binlog数据变更进行串联和聚合,是一个困扰我们比较久的问题:

但是最终,我们借助滑动窗口 这个思想,再结合流式数据处理,寻找到了一个较为完美的解决方案:基于事件驱动的滑动窗口

2.2.方案细节

2.2.1.事件窗口

核心概念

  • 数据事件: 一条表维度的数据变更通知,包含数据库记录中每个字段变更前、变更后、变更类型的信息。
  • 事件窗口: 在一个操作流程中,产生的所有相关联的数据事件的抽象区间,由数据事件驱动每个窗口的生命周期,一个数据事件可以关联到多个窗口(一个操作同时变更多种订单信息的场景)。
  • Session: 在一个窗口区间中暂存的数据,也可以理解为窗口在数据层的体现。

如上图所示,我们通过在一个数据流中去构建虚拟的事件窗口,每一个窗口包含实际业务操作中所有的数据事件信息,通过一个唯一key关联,通过流中的数据事件驱动窗口的打开和关闭,当窗口关闭时,就可以对窗口内的数据进行校验以及构建完整的订单变更信息。

2.2.2.Transformer设计

基于此我们选择使用Kafka Stream作为基础组件,用以支持流式数据处理,好处是天然与kafka兼容,无需额外的服务端组件。但是Kafka Stream提供的流处理功能,不支持以事件驱动,窗口聚合操作都是基于时间窗口的,因此我们需要重新实现一个Kafka Transformer的逻辑,去支持事件窗口。

核心流程
事件窗口管理

每个窗口配置对应一个实际业务场景操作全部的数据事件信息,每接受一个数据事件,会根据配置信息去匹配对应的事件节点,然后驱动窗口状态的流转。

窗口配置: 主要包含窗口的场景、开始事件判断、结束事件判断、事件节点列表、超时事件等配置,新增一个操作场景需要提供这些信息。

事件节点配置: 主要包含节点名称、库名、表名、变更类型(插入、更新)、字段匹配逻辑配置,一个窗口内会包含多个这样的点配置。

窗口key的识别:

每个窗口都有一个唯一标识,例如在交易订单场景下,是由订单号串联一系列事件的,因此订单号+场景,就是窗口的key,例如某个数据事件匹配到某个窗口内的事件节点,会将订单号+匹配到的窗口场景作为key

核心操作均有分布式锁,不会出现不同操作并发的情况,cdc也能严格保证顺序,且最后在窗口关闭之前,会进行数据合法性的校验,确保是完整的一次信息变更操作。

session管理

窗口的session是通过kafka stream的StateStore API实现的。几种存储方案对比如下:

StateStore存储方案 描述 备注
内存存储(默认支持) 实现简单,开箱即用,但是可能存在内存溢出风险 需要结合changelog使用(Stream实例启动和停止时的状态恢复),但是changelog的可自定义程度也不高
RocksDB(默认支持) 磁盘存储方案,但是我们的服务都是容器化部署方案,使用磁盘存储不太合理
Redis 缓存数据库,适合短期数据存储,且天然支持超时逻辑,但是存在服务端不可用的风险
关系型数据库 数据稳定性较高,实现逻辑稍复杂,额外资源开销较大
  1. 经过综合成本及稳定性方面的综合考虑,最终默认选用Redis实现状态的存储和session管理,因为在我们哨兵平台的建设需求层面,能容忍小概率的数据丢失,且代码实现和存储成本都较低。
  2. 但是,我们仍然支持存储方案的扩展,对于有高数据保障的场景,我们留出一定的扩展性,可以基于事件场景混合使用不同的session存储方案。
高数据稳定性场景下的保障方案
  • 窗口状态管理:使用MySQL关系型数据库实现,记录每一个事件节点的信息以及窗口状态,支持重试。
  • 超时控制:定时任务轮询扫描数据库,根据时间寻找出超时的窗口,并交由超时处理器处理,需要注意的细节是,为了避免kafka消息延迟等问题导致的超时判断不准确,不应使用当前系统时间进行判断,应该使用事件产生时间和Stream流的时间进行比较,增强抗消息延迟能力,确保都是基于事件产生的时间进行判断,是实际的事件超时。

Kafka Stream提供了流时间获取的API: org.apache.kafka.streams.processor.PunctuationType#STREAM_TIME,默认为流中处理的最新一条数据的产生时间戳,即当某一条事件产生的时间 减去超时时间已经小于了窗口打开的事件时间,才认为是超时。

2.2.3.采集结果存储

订单哨兵平台的结果存储也与主流程进行了解耦,Stream任务在处理完一个窗口数据口,异步发送kafka消息,交易资源服务使用Hbase 进行存储,其他消费需求方也可消费订单信息变更的消息。

Hbase优点是支持海量数据存储,且字段扩展性强,存储结构如下:

  1. 基于存储成本、可维护性、性能等方面的综合考虑目前仅存储变化的数据,而不是全量数据。
  2. 由于选择HBase存储,支持动态列,后续如有必要可随时支持全量数据的存储。
描述 存储格式示例
订单号 "284xxxxxxxxx"
子订单号 "49xxxxxx"
操作人id "110xxxxxx"
操作人角色 "ENTITY_USER"
变更前信息 "[{"id":"1","name":"带雨布"}]"
变更后信息 "[{"id":"9","name":"三不超--大车"},{"id":"11","name":"有禁区"},{"id":"10","name":"随时装"},{"id":"14","name":"需清点"}]"
变更场景 FREIGHT_SUB_ORDER_DRIVER_PICK_UP_CONDITION_MODIFY
事件产生事件(binlog时间) "2024-11-26 17:56:03.871"
事件处理事件(kafka stream任务处理的起始时间) "2024-11-26 17:56:04.162"
记录创建事件 "2024-11-26 17:56:04.163"

操作记录展示:

3.总结

  • 系统稳定性: 上线近半年零故障运行,订单信息操作记录采集平稳采集,核心链路资源消耗为0。
  • 运营提效: 为客服判责场景提效、减少成本。
  • 生态赋能: 提供了一套信息变更记录采集的解决方案,也完善了交易的底层基础设施。

订单哨兵将持续探索AI驱动的智能异常检测与跨业务链路的因果推理能力,进一步释放数据变更的深层价值,为业务决策与系统优化提供前瞻性洞察。

作为公司中台化领域的核心技术团队,交易中台研发团队始终以架构抽象与模式创新为驱动,持续沉淀可复用业务能力,通过技术中台化建设支撑业务快速迭代,在平台化演进道路上砥砺前行🎯。

相关推荐
春天姐姐18 分钟前
vue知识点总结 依赖注入 动态组件 异步加载
前端·javascript·vue.js
豌豆花下猫36 分钟前
Python 3.14 新特性盘点,更新了些什么?
后端·python·ai
caihuayuan51 小时前
Vue生命周期&脚手架工程&Element-UI
java·大数据·spring boot·后端·课程设计
Pop–2 小时前
Vue3 el-tree:全选时只返回父节点,半选只返回勾选中的节点(省-市区-县-镇-乡-村-街道)
开发语言·javascript·vue.js
滿2 小时前
Vue3 + Element Plus 动态表单实现
javascript·vue.js·elementui
阿金要当大魔王~~2 小时前
面试问题(连载。。。。)
前端·javascript·vue.js
yuanyxh2 小时前
commonmark.js 源码阅读(一) - Block Parser
开发语言·前端·javascript
进取星辰2 小时前
22、城堡防御工事——React 19 错误边界与监控
开发语言·前端·javascript
ドロロ8063 小时前
element-plus点击重置表单,却没有进行重置操作
javascript·vue.js·elementui
明月与玄武4 小时前
Spring Boot中的拦截器!
java·spring boot·后端