找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

1472

积分

0

好友

191

主题
发表于 前天 16:14 | 查看: 6| 回复: 0

一、背景

现状与痛点

在互联网飞速发展的今天,企业对后端开发的要求愈发严苛。开发同学的大部分精力都投入在处理复杂需求、保障代码架构与系统稳定性上。相比之下,简单重复的 CRUD 工作就显得尤为浪费开发资源。以供应链管理为例,其页面中约 77% 为标准页面,其中充斥着大量相似的参数配置页,即对某个模型进行增、删、改、查、导入、导出等重复操作。这类开发工作技术含量低,却耗费了大量人力。

什么是业务参数配置中心

业务参数配置中心是一个能够通过配置方式,快速生成前端页面及配套增、删、改、查、导入、导出服务的配置平台。它与得物内部的低代码前端页面平台(wizard)深度集成:参数配置中心提供后台数据操作服务,wizard 则输出对应的前端页面代码,并支持用户进行二次自定义修改。

使用场景

  • 针对读多写少的简单单表增删改查场景。
  • 业务中需要交给运营修改的复杂 ark 配置(简单配置除外),可尝试接入,以减少人为修改 JSON 可能导致的编译错误和系统故障。

例如,类似下面这样结构复杂的 JSON 配置,交由运营手动维护极易出错:

[{"position":"1","red":2.49,"blue":2.4,"green":1},
{"position":"2","red":2.49,"blue":2.4,"green":1},
{"position":"3","red":2.49,"blue":2.4,"green":1},
{"position":"4","red":2.49,"blue":2.4,"green":1},
{"position":"5","red":2.49,"blue":2.4,"green":1},
{"position":"6","red":2.49,"blue":2.4,"green":1},
{"position":"7","red":2.49,"blue":2.4,"green":1},
{"position":"8","red":2.49,"blue":2.4,"green":1}]

业务参数配置中心极速体验

  1. 后台服务搭建与数据录入:(原视频部分已移除,不影响技术理解)
  2. 数据读取:业务方可通过参数配置中心的 SDK,输入自定义的业务入参和出参对象。SDK 会自动根据方案定义及用户输入条件,查询并返回对应的参数信息。

SDK调用代码示例:创建请求对象并调用SDK获取参数

从上面的快速体验中,你可能会产生许多疑问:

一个卡通人物周围有很多对话框,里面写着:什么是元素?什么是方案?数据怎么存的?什么是维度?什么是参数?

二、整体架构与原理

实现思路

首先,我们对常见的配置页面进行剖析:这类页面通常包含搜索条件、静态展示字段以及操作栏。搜索条件往往是静态字段的子集,操作栏的功能也大同小异。为了结构化地构造这类页面,我们将静态展示字段进一步抽象为几个核心概念:元素、维度、参数、方案、参数实例

一个参数配置后台页面截图,包含搜索框和表格,展示了字段如‘仓库’、‘一级类目’等

元素
构成页面的每一个业务字段,统称为元素。部分字段(如仓库、品牌、一级类目等)是通用字段,拥有自己的字段名称和取值范围。

维度
一条记录中能够标识其唯一性的信息,可能是一个或多个字段。在参数中心里,所有能确定记录唯一性的字段集合被称为维度。这个概念至关重要,且一旦确定便不可变更。

参数
在业务发展过程中,其值可以发生改变的字段,就称为参数。简单来说,一条记录中,除了维度字段,其余都可以归为参数。

综合维度和参数来理解:例如在商品信息中,商品ID是维度,商品售价、折扣率是参数;在医院挂号系统中,科室ID是维度,挂号费、出诊时间则是参数。

方案
一个参数方案管理着一个特定场景下的业务配置。可以简单理解为一个方案就代表一个页面,它定义了该页面包含哪些维度、哪些参数,并可以指定哪些字段作为搜索条件、哪些是必填项、哪些支持多选等。

参数实例
在方案定义好并生成页面后,实际录入产生的业务配置数据,我们称之为参数实例。

经过上述解剖,搭建这样一个页面就像建房子:维度和参数是基础木料,创建方案是设计蓝图,参数实例则是建成的真实房间。因此,业务参数配置中心的产品思路如下:

从构建元素到发布页面的流程图:构建元素 → 构建方案 → 生成/调整页面 → 发布页面 → 后台维护数据 → SDK获取数据

整体架构

上文介绍了业务参数配置中心的核心概念,接下来看看整体的架构设计。我们需要围绕这些概念,设计实现业务功能的架构,核心包括领域模型、领域服务、应用服务以及基础设施层的存储组件。同时,需要整合外部的导入导出框架、日志框架(也可自行实现)。在完成核心的元素维护、方案维护和存储设计后,还需要提供一个 SDK,供业务方便捷地访问数据。

参数配置中心整体架构图,展示了应用层、核心服务层、SDK层和存储层的关系

系统的实体关系图如下:

实体关系图,展示了业务元素、方案、方案明细、参数实例、操作日志等实体及其关联关系

通过上文的介绍,我们初步了解了整体架构。那么,每个子模块具体如何实现呢?接下来我们深入分析更细节的原理。

核心原理

如何设计存储细节是本系统的一大挑战,既要兼顾页面灵活变动,又要保证数据一致性,同时还需确保查询性能。下文将逐一剖析这些核心挑战点。

存储流程

每一个页面的字段都可能不同,数据是如何存储的呢?

商品库存管理配置页面截图

瑕疵原因配置页面截图

从以上两个页面可以看出,由于页面字段千变万化,我们的设计思路是采用抽象存储来应对。核心是使用一张大宽表进行存储,表中包含多个抽象列。同一抽象列在不同的方案下,其业务含义不同。

同时,将方案的元数据——维度、参数以及功能性设置(如字段是否可删除、是否支持多选)单独存储。每个方案下大宽表中抽象列对应的业务含义,就记录在这些元数据表中。

此外,为应对大批量查询,我们引入了 OLAP 数据库。应用内部的单点查询走 MySQL,运营后台针对特定字段的大批量查询则使用 OLAP 数据库来缓解压力。

下图展示了存储的整个过程及示例:
(注:原流程图“从用户登录到数据存储”图因过于通用且与核心流程关联性不强,为优化阅读体验已移除。下文以文字描述核心存储逻辑。)

SDK查询流程

由于各业务方在使用参数时拥有自己的业务对象,我们在 SDK 中集成了反射能力,使用户无需感知底层抽象存储。查询流程非常简洁,主要分为三步:自定义请求对象、自定义响应对象、调用 SDK 方法获取参数实例。

1. 定义请求对象(Request):

@Data
public class PinkDeviceCameraConfigRequest implements Serializable {

    /**
     * 配置类型
     */
    private String configType;
    /**
     * 设备编号
     */
    private String deviceNo;

}

2. 定义响应对象(Response):

@Data
public class PinkDeviceCameraConfigResponse implements Serializable {

    /**
     * 配置类型
     */
    private String configType;
    /**
     * 设备编号
     */
    private String deviceNo;

    /**
     * 配置明细
     */
    private List<CameraConfigDto> configValueList;

    @Data
    public static class CameraConfigDto implements Serializable {
        private String position;
        /**
         * 白平衡(Red)
         */
        private BigDecimal red;
        /**
         * 白平衡(Blue)
         */
        private BigDecimal blue;
        /**
         * 白平衡(Green)
         */
        private BigDecimal green;
        /**
         * 亮度(Brightness)
         */
        private BigDecimal brightness;
        /**
         * 自动曝光时间上限(us)
         */
        private BigDecimal autoExposureTimeUpperLimit;
        /**
         * 采集帧率
         */
        private BigDecimal acquisitionFrameRate;
        /**
         * 增益自动开关(us)
         */
        private String gainAuto;
        /**
         * 增益自动上限
         */
        private BigDecimal gainAutoUpperLimit;
        /**
         * 增益自动上限
         */
        private BigDecimal gainAutoLowerLimit;
    }
}

3. 调用SDK服务方法查询:

PinkDeviceCameraConfigRequest pinkDeviceCameraConfigRequest = new PinkDeviceCameraConfigRequest();
pinkDeviceCameraConfigRequest.setConfigType("DEVICE_NO");
pinkDeviceCameraConfigRequest.setDeviceNo("123@LuSun");

// 单个查询场景
PinkDeviceCameraConfigResponse response = paramInstQueryService.getParams("P80-DEVICE-CAMERA-PARAM-MANAGER", pinkDeviceCameraConfigRequest, PinkDeviceCameraConfigResponse.class);

// 批量查询场景
PageQueryOption pageQueryOption = new PageQueryOption();
pageQueryOption.setPageIndex(1);
pageQueryOption.setPageSize(200);
PageInfo<PinkDeviceCameraConfigResponse> paramsPage = paramInstQueryService.getParamsPage("P80-DEVICE-CAMERA-PARAM-MANAGER", pinkDeviceCameraConfigRequest, PinkDeviceCameraConfigResponse.class, pageQueryOption);

4. 获得结果:
API响应结果JSON示例

整体查询实现原理如下:

SDK查询时序图,展示了用户服务、SDK、核心服务、Redis、MySQL之间的调用关系

目前,整个服务的平均查询性能控制在 10+ms 左右:

应用监控截图,显示接口平均耗时约为14.8ms

参数优先级实现

为什么需要参数优先级功能?

考虑一个供应链补货参数(安全库存)的场景:系统中有100个仓库、20个一级类目、200个二级类目、2000个三级类目以及500个品牌。需要为每个商品维护安全库存,你会怎么做?

显然,你不会为 100仓库 2000类目 500品牌 = 10亿种可能性都设置一遍参数。通常,重点类目需要详细配置,非重点类目可能只需管控到一级或二级类目。这样,配置量将大大减少。此时,参数的决策就需要遵循一定规则,例如:

  • 若存在“仓库+一级类目+二级类目+三级类目”的安全库存,则优先取用;
  • 若未找到,则取“仓库+一级类目+二级类目”的安全库存;
  • 若仍未找到,则取“仓库+一级类目”的安全库存。

例如,有以下规则:

  • DN仓 鞋 安全库存 100
  • DN仓 鞋-运动鞋 安全库存 500
  • DN仓 鞋-运动鞋-篮球鞋 安全库存 1000

那么,一个篮球鞋商品将命中第三条规则(安全库存1000);登山鞋只能命中第二条规则(安全库存500);高跟鞋则只能命中第一条规则(安全库存100)。

这意味着,当用户入参可能同时命中多条参数时,系统需要通过预设的优先级来判断应返回哪条参数。

优先级设置界面截图

参数优先级匹配流程图:输入原始数据 → 获取维度优先级 → 按优先级从高到低匹配维度 → 返回参数

为加速查询,系统设计了两层缓存机制:

两层缓存结构示意图:第一层缓存维度优先级,第二层缓存维度对应的具体参数值

当后台数据发生变化时,系统会及时使对应的缓存失效,确保数据一致性。

缓存失效流程图:运营修改数据 → 发送领域事件 → 各业务方SDK监听事件 → 失效本地缓存

元素多选处理

维度多选场景:
维度多选配置页面截图

参数多选场景:
参数多选配置页面截图

既要保证维度组合的唯一性,又要支持灵活的搜索与展示,如何实现?业务参数配置中心引入了“组(Group)”的概念。将同属于一行的参数实例归为一个组,这个组是数据新建、编辑的最小单位。

新增流程如下图所示,系统会对多选值进行分组(聚类),生成多条唯一的参数实例记录:
数据分组(聚类)处理流程图,将多选的维度值展开为多条唯一记录

修改流程如下图所示,系统会智能对比新旧数据,进行更新、删除和新增操作,并保持组的聚合ID不变:
数据修改前后对比图,展示如何更新、删除和新增记录

元素范围查询

页面中的字段(元素)都有其取值范围。为平衡易用性与系统性能,我们将元素取值类型划分为四种:

  1. 枚举类元素:由用户在页面手动创建,数量通常在几十个以内,如“是/否”、单据类型等。
  2. Dubbo全量接口元素:取值范围体量在几十到上百个,可通过一个 Dubbo 接口获取全部枚举值,如一级类目、仓库等。
  3. Dubbo单点查询接口元素:取值范围体量在几千到几万,无法一次性加载所有枚举,如品牌。需要通过“值->文案”和“文案->值”两个接口来完成搜索与展示。
  4. 自定义文本元素:非枚举类字段,直接由用户输入文本。

以下是 Dubbo 全量接口元素的配置示例:
Dubbo全量接口元素配置界面

Dubbo 单点查询接口的配置与全量接口类似,不同之处在于需要为系统调用预留变量占位符 #{var}
Dubbo单点查询接口元素配置界面

有时,元素的范围还取决于同页面中其他元素的取值。例如,“质量原因”字段,当一级类目为“鞋”时取值为A、B、C,为“服装”时取值为D、E、F。在设置此类元素范围时,需要将其依赖的其他元素入参也维护在接口配置中。

导入导出

以下是核心的导入处理流程
数据导入流程图:预处理 -&gt; 校验 -&gt; 存储 -&gt; 返回结果

为了提升运营人员的使用体验,在多数导入场景中,导入文件使用的是业务文案(如“鞋”、“服装”),而非后台存储的数值(如2、3)。这就需要在导入过程中进行文案到数值的转换,其依赖的正是上文“元素范围查询”中定义的接口。对于需要其他元素作为入参的元素,系统默认允许使用当前元素左侧的所有元素值作为其查询入参。

业务参数配置中心不适合做什么?

  1. 有极为复杂的UI交互的场景。
  2. 需要极为复杂业务校验逻辑的场景(长期规划中可能支持)。
  3. 高频写入的场景。
  4. 应用查询参数时,匹配条件不是简单的“等于”(=) 的场景。

三、总结与展望

本文详细阐述了得物业务参数配置中心的设计思路与核心架构。该中心通过配置化方式,配套生成增、删、改、查、导入、导出等后端服务,并与前端低代码平台结合自动生成页面代码。目前,平台已接入40多个业务场景,节省了大量研发人日,使开发人员能够从低效的 CRUD 中解放出来,更专注于核心业务逻辑的开发。

未来规划主要包括:

  1. 增强SDK查询灵活性:支持批量带优先级查询、通过SDK分页查询全量参数、暴露更多系统字段以方便业务方使用。
  2. 提升方案定义灵活性:支持更多元素范围的定义方式,如 HTTP 接口调用等。
  3. 增加元数据定义的动态性:使部分元数据的取值能够根据页面中其他元素的取值动态决定,实现更智能的联动配置。

通过持续的迭代与优化,参数配置中心旨在为 云栈社区 的开发者及广大技术同仁,提供一套更高效、更灵活的配置管理解决方案,以应对日益复杂的业务配置需求。




上一篇:MySQL全文索引FULLTEXT详解:告别低效LIKE模糊查询
下一篇:算法项目管理实战:电商团队如何应用混合式敏捷方法提升效能
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-1-18 21:32 , Processed in 0.225806 second(s), 40 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表