以问答形式,抽象中台领域框架

春哥叨叨

共 8746字,需浏览 18分钟

 ·

2021-05-23 20:06

写在前面

答案是由问题驱动产生的,我们既然想落地一个框架、系统,必然需要回答很多问题,这样既可以保证最终方案对现在问题是有收益的,也可以保证落地路径的一致性,防止跑偏。通过一步步回答中台领域框架究竟解决了哪些问题,推动框架落地。


业务的个性化需求来源于哪些方面?

主要用于满足不同用户在价格/体验等方面的差异化诉求。

比如网约车场景下,不同用户有不同的诉求,价格敏感性用户关注于定价,着急用车用户关注于应答率,对出行有体验需求用户关注于履约体验。所以网约车平台会提供不同用车品类服务(出租车、快车、专车等)提供这种差异化服务。

个性化业务在系统中应以什么样方式承接,减少对系统的侵入?

可以参考电商场景下品类的概念,以品类承接业务个性化诉求,将个性化元素抽象成一个个二元组,进行组合编排,这样会发现这些品类的大流程是类似的,在一些细节上有差异,解决好这些差异点,就可以解决个性化业务。

多品类及个性化需求落在系统中,应注意哪些点?

首先需要有一套通用的框架承接这些能力/概念/代码等,目的是降低这些概念落到各个系统中后的理解的歧义和实现的差异,以至于导致了概念/理解/实现上的不统一,反而增加了未来系统扩展性和实现复杂度。框架需要兼顾比如业务的隔离/部署的隔离/流程的复用/个性化逻辑的隔离等。

中台型系统为什么是“大中台小前台”这种模式呢?

这种中台模式主要是由业务流量分配模式决定的,比如电商场景下,包括订单服务、收银台服务、商品服务、营销服务、订单服务等。每一个领域下的流量都可以在自己的领域服务内形成闭环,以解决各自领域下的个性化运营问题。但是流程流量需要串联多个领域服务,这里拦截之后剩下的一般是通用流量。而中台本着“业务复用、快速赋能”这个目的,他出现在通用流量的串联层价值更大。

一旦这个中台系统想以整体的电商能力赋能于新的电商场景时,就形成了这种“大中台小前台”的模式。前台各地独立闭环,实现不同电商场景要求,中台提供电商标准的基础能力。

所以流量分配模式的表现是:多业务(多品类、多场景)前台流量接入,转化到统一的(标准的、有限的)业务中台中实现,以基础平台进行支撑。

一套通用的框架系统应该怎么落地呢?

首先平台框架集成的是一个个的独立领域对外提供的原子性接口或者服务能力,领域能力以API的形式提供。框架层基于这些API打造一个所谓的中台框架,结合配置化/领域化等概念,串联多个流程,实现中台能力。其实背后代表的是一个业务的流量模式调度与拦截。

如何基于业务特点分析框架结构?

技术是服务于业务的,尽管我们有了通用、抽象的技术解决方案,不代表这个方案在自己所服务的场景下一定好用。归根结底还是需要结合自己业务特点进行抽象、概况。

比如网约车场景下主要解决的是司、乘两端的撮合。

业务运营场景如下:

用户进入APP -> 平台提供多品类给到用户 -> 用户选择目标出现品类 -> 品类流量流入前台业务层 -> 前台业务层进行该品类特有业务处理 -> 流量进入通用中台层 -> 经由基础服务实现数据落地

如图:

通过这幅图可以看到,一些产品需求的边界在哪里了,如果是业务的个性化运营诉求,只需要在前台业务api里面消化掉就ok了。比如某些品类的某些地区下线、不同地区春节服务费提升等个性化需求,背后可能涉及到自己品类服务下的计算的闭环,而对中台服务的调用需要进行去躁。

但随着业务进入存量阶段,类似于千人前面的个性化需求会非常多,如果在前台业务完全去做这些事情,前台系统势必变得越来越臃肿、复杂度变高、迭代效率低。

这个时候一般会伴随着一次“前台搬家”动作,就是将品类下的服务下沉到中台的通用逻辑里面,中台框架提供差异化定制机制,前台业务做非常“薄”的一层定制。这样就可以在隔离与复用层面做到比较好的兼顾。

这种差异化定制,如何体现在前台业务和中台框架的衔接上呢?

前面说过了,前台业务主要解决的是进入这个品类下的流量的治理。中台系统解决的是流程编排层面的治理,在核心流程上提供扩展与定制机制,这部分是和前台衔接的。

  1. 流量染色:识别和定义接入流量中的品类、场景、功能,并转义标识为统一的业务特征。

  2. 流程串接:根据不同事件/请求按照相应的逻辑和流程调用下游服务,以完成具体的功能。

  3. 数据渲染:将处理结果数据按不同的端或品类/场景要求渲染成对应的数据视图。

关键词:识别、串联、编排、调用、渲染。

如何理解复用与隔离?

复用是为了提效,更高级别的复用,业务价值就越高,效率也就越高。隔离是为了稳定,减少某一品类下业务迭代与代码变更对于其他品类的影响,同时变更后可以低成本测试回归,最小半径交付。

做好这两点不太容易,比如复用需要回答复用什么?复用到什么级别?怎么实现复用?对于隔离需要回答,我们究竟要隔离什么?怎么实现隔离呢?

提高复用与隔离大家最常听到的就是配置化、标准化、插件化等概念,那他们的目的究竟是什么呢?

配置化某种程度上建立在对于某个领域标准服务的描述完善之上,我们有了完整性的产品描述,就可以抽象出独立元素的概念,配置化解决的是对于这么多元素组成的N元祖之间的编排与优先级冲突的解决。通过插件化机制,解决不同BU或业务线之间的代码,实现真正的逻辑“硬”隔离,写在同一个类里面的代码,不觉得你可以很好控制扩展性和稳定性。

有了产品标准化能力描述及插件化的个性化业务规则,在配置流量特征分发,就可以控制线上流量进入特定的配置规则就插件包下的代码逻辑了。

当然参考这种模式,落地时还是需要做本地化实现的,比如对于配置化的实现,需要有一套抽象方法,帮助实现功能抽象。

插件的扩展性上,需要关注于开放粒度、定义的明确性、插入点的稳定性、长期的扩展与维护等,看看是否真正对于稳定性和扩展性及清晰的语义定义有帮助。

如何实现价值最合理的复用,进而吃到复用的红利?

做好这样一个中台框架系统就需要回到之前文章多次提到的运营流程大图上了,看看我们的核心流程是由哪些较细粒度流程组成的。

上图可以看到,最上层是抽象的核心流程,下面是各个领域服务,以领域化方式闭环每个环节内的能力、数据、职能。DDD的好处之前介绍很多了,就不赘述了,总体上通过分治实现了复杂业务的治理,整体复杂度降低、可控,提高了需求交付效率。

而针对于流程层也有一些可以提效、提高稳定性的方法。其实流程层是对于原子能力的编排,这种原子性既不是越粗或者越细,而应该结合业务特点,以业务原子组件提供。

也就是以领域化服务至上的能力,进行原子组件化的封装,以两层抽象实现复用性。同时提高了扩展性和开发效率。

随着业务发展系统将会面对进一步腐化的问题,应该如何提前避免?

刚才提到的解决方案是以领域化、组件化方式实现了业务的原子复用,吃到了一部分技术红利。但是都是在做擦屁股的事情,也就是解决我们遇得到的问题,是否可以走在业务前面去看看,可以前置做一些事情,解决未来可预见的问题呢?

解决这种问题,抽象的方法论依然是“分治”。

最上层是业务的流程抽象,所有的个性化运营治理措施都可能发送在这里,所以这一层是易变的。其他的品类、配置平台、领域服务都是偏稳定的,这里是不易变的。所以我们只需要解决这个易变层的问题就ok了。

所以这部分可以分成两层:一层串联核心流程状态流转;一层完成各个垂类功能个性化需求的组件串联;

流程层识别垂类流量,在每个流程节点下调用接口执行,对上层解决与端上的交互协议,对下层执行不同品类的个性化抽象的step。

组件层里面的每个组件由于是对于能力的抽象,很多垂类的这类能力都会到达某个组件上,同一个组件可以以策略模式+配置的方式实现不同垂类的个性化支持。如果某一个品类在某个组件能力上有巨大的差异,我们就不用寄希望于通过现有组件实现了,可以完全实现一个独立的、新的组件做支撑,等哪一天发展合适了,在打散到存量组件里面

  • 流程编排中心:不同品类、场景下,对于接口流程环节进行编排;

  • 特征平台:统一管控业务特征,保持业务描述统一;

  • 品类配置中心:从品类出发,集成不同能力、行为,加速品类描述完整性与整体交付上线;

这么多复杂概念,如何实现全域业务的标准化适配落地实现?

如前面所说,这么多概念,每个人理解会不同,每个系统实现会不同,所以需要提供统一的框架,集成这些能力,以sdk方式交给各个系统,将能力集成进来。

最近看了一个滴滴实现的方式,整体看下来和我之前的想法和思路差不多,虽然概念上有些许差异,但核心抽象路径与实现路径上差异不大。还有他是基于php和golang场景实现的。我的主要思路是基于java实现的,可以很好复用到java生态下的一些解决方案。

概念包括:InputSource、Transport、TransportFactor、StepRuntime、Step、Ability等。

  • Transport:Transport作为流程承载器,提供了一个base的基础流程实现,不同品类可继承BaseTransport,然后可以针对差异的流程环节step进行重载,但整个流程是由流程驱动引擎调度,各品类保持一致。

  • Ability:ability是能力组件,组件内部提供了一组通用的mode,不同品类场景通过配置化方式复用这些mode,同时也向业务开放了定制mode的机制,业务可以通过使用biz定制自己独有的mode,挂载到ability下,实现差异化功能。

总结来说:transport是偏流程;ability是偏组件;

很多集成能力,不需要特别完美的配置化实现。可以提供一个DSL做好配置化编排即可:

// 配置文件,管理流程环节,以及提供给不同品类注册各自transport
{
"name": "ConfirmOrder,
// 流程定义
"
transports": {
"
default": "\\DuKang\\Transport\\ConfirmOrderaseTransport",
"
express": "\\DuKang\\Express\\Transport\\ConfirmOrderExpressTransport",
"
luxury": "\\DuKang\\Luxury\\Transport\\ConfirmOrderLuxuryTransport",
"
taxi": "\\DuKang\\Taxi\\Transport\\ConfirmOrderTaxiTransport",
},
// 能力定义
"
steps": [
{
"
step_id": "fetchInfoStep",
"
description": "获取基本信息"
},
{
"
step_id": "confirmTravelStep",
"
description": "确认行程信息"
},
{
"
step_id": "confirmBillStep",
"
description": "确认计价信息"
},
{
"
step_id": "checkStep",
"
description": "成单检查"
},
{
"
step_id": "fillOrderDetailStep",
"
description": "订单维度填充"
},
{
"
step_id": "sendOrderCommandStep",
"
description": "订单处理操作"
},
{
"
step_id": "sendDriverCommandStep",
"
description": "司机处理操作"
},
{
"
step_id": "sendSchedulingCommandStep",
"
description": "调度处理操作"
},
{
"
step_id": "buildResponseStep",
"
description": "构建响应"
},
{
"
step_id": "asyncOperationStep",
"
description": "异步操作"
},
{
"
step_id": "writeLogStep",
"
description": "日志处理"
}
]
}

// dukang框架核心执行过程
try {
// 加载并解析接口配置,包括BizConfig、StepConfig
$oBizConf = BizConfig::load($sConfigStr);

// 获取输入源数据,包括Request和基础数据获取
$oInputSource = new ConfirmOrdernputSource();

// 构造StepRuntime
$oStepRuntime = new ConfirmOrdertepRuntime($oInputSource);

// 将接口配置对象、StepRuntime放入流程调度器
$oFlowScheduler = new FlowScheduler($oBizConf, $oStepRuntime);

// 初始化传输器路由因子
$oTransportSelectFactor = new ConfirmOrderTransportSelectFactor($oInputSource);

if($oFlowScheduler->selectTransport($oTransportSelectFactor))
{
// 执行流程调度
$oFlowScheduler->run();
}
// 异常处理原则:接口外层只处理DuKangException和Exception,Step或者Ability处理异常则先处理逻辑再抛异常
} catch (DuKangException $e) {
$aResp = [
'errno' => $e->getCode(),
'errmsg' => $e->getMessage(),
];
echo json_encode($aResp);
} catch (\Exception $e) {
$aResp = [
'errno' => $e->getCode(),
'errmsg' => $e->getMessage(),
];
echo json_encode($aResp);
}

Transport - 业务承载器

针对不同品类通过抽象得来的流程,每一个垂类业务必有其承载的流程和执行顺序。

  • BaseTransport 通用流程,每一个业务身份下有且只有一个BaseTransport

  • XxxTransport 覆盖不同运品类的差异化流程,垂类下差异化XxxTransport必须继承自BaseTransport,任一Transport至少包含一个Step,Transport <=> [N]Step (N >= 1)

Step - 流程环节

垂类下抽象出来流程的流程环节,每个Step是某一段业务功能的具体实现。

Step是大粒度差异化代码实现的有效手段, 可通过Override Step实现差异化,Step间的通信通过统一运行时数据总线StepRuntime串联,理论上可实现热拔插。

如图:

  1. 业务流程驱动型接口:以串联各个处理流程为主

  2. 数据驱动型接口:以构建业务特征数据为主

StepRuntime - 运行时数据总线

流程串联在运行时承载数据的总线,StepRuntime只能作为Ability的输入,不能在Ability及下层逻辑中对StepRuntime的业务特征和数据进行修改。

InputSource - 输入源

外部输入数据源,是TransportFactor的上游输入,用于屏蔽、解耦内外部执行环境差异化,隔离外部入参。进入Step之后具有只读属性,被StepRuntime引用,后续业务逻辑不可修改其包含的所有特征及数据内容。

Transport Factor - 传输器因子

业务传输器Transport决策因子,不同垂类可以采取不同的因子进行Transport决策,比如订单的product_id、司机的car_level,可选择端来源(渠道)作为决策因子,如滴滴出行app、开放平台、礼橙专车app等,Factor必须是确定可选择的几类因子,不能由RD同学自由编写,同类业务接口原则上TransportFactor要尽量保持一致,提供元数据。

Ability - 能力组件

以特征数据为视角,对聚焦业务进行提炼和抽象,形成能力组件,面向可复用设计,面向可扩展差异化设计,一般由独立微服务承载。

业务特征概念

业务表达:播单计划 = sStartAddDuseTime +bIsDelayBroadcast + bIsRepeatAssign+iBroadcastAssignType + $iBroadcastExpire;

可以用于规范业务属性或字段语义,避免歧义和未知语义。

定义:业务 = 有序流程 * 控制(特征X, 特征Y, 特征Z, ...), 控制 = 染色 | 填充 | 复写 | 合并 | 标记

能力组件抽取过程

针对一组业务特征,围绕这些业务特征的生产、修改操作聚合,形成能力组件。如围绕播单特征的播单组件、价格特征的计价组件等等。

Ability扩展性

支持以Addtional 的业务扩展Ability Mode,即前面提到的biz形式定制化mode,从而达到不同品类在Ability上的隔离。

Ability+品类场景配置最终思路

复用:基于品类+场景(N元组)配置化,mode selector灵活决策能力组件的执行模式 差异化:业务通过biz实现mode的定制,配置化动态加载。

其实不一定动态加载,可以实现动态感知和热更新即可。

框架目录结构


// 模块根目录
├── Dukang // 新引入的内容,区隔老代码,未来将替代hermes
│ ├── Ability // 能力目录
│ │ ├── Common // 公用能力
│ │ │ ├── DispatchOrder
│ │ │ │ └── DispatchOrderComponent.php
│ │ │ └── VirtualPhone
│ │ │ └── VirtualPhoneComponent.php
│ │ └── Express // 品类特有能力扩展
│ │ └── DispatchOrder
│ │ └── DispatchOrderComponent.php
│ ├── Config // 接口配置
│ │ └── ConfirmOrder.json
│ ├── InputSource // 接口输入
│ │ └── ConfirmOrderInputSource.php
│ ├── StepRuntime // 全局数据总线
│ │ └── ConfirmOrderStepRuntime.php
│ ├── Model // 公用model
│ │ ├── Dao
│ │ ├── Driver
│ │ │ └── DriverModel.php
│ │ └── Order
│ │ └── OrderModel.php
│ ├── Service // 公用service
│ │ └── Driver
│ │ └── DriverService.php
│ ├── TransportFactor // Transport因子
│ │ └── ConfirmOrderTransportFactor.php
│ └── Transport // 流程串接
│ ├── Base
│ │ └── ConfirmOrderBaseTransport.php
│ └── Taxi
│ └── ConfirmOrderTaxiTransport.php
└── vendor
└── dukang
└── framework
├── idl // 数据字典(Dimensions,标准dto)
└── src // 框架代码
浏览 42
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报