初次接触氛围系统架构,聊聊我这三个月的理解
ccwgpt 2024-10-13 01:36 27 浏览 0 评论
褚浩(对易) 大淘宝技术 2022-11-25 16:20 发表于浙江
本文主要介绍了作者对于氛围中心的业务理解。从氛围的概念出发,阐述了氛围系统的必要性,然后展示了配置端的数据写入、调用端的配置读取等氛围系统的架构细节,最后作者提出了一些对于氛围中心未来的想法和思考。
概述
?氛围的概念
氛围是能够刺激消费者购买欲望的一类视觉表达。氛围一般与优惠、价格相关,其目的在于烘托当前商品所处的营销氛围,促进消费者的购买欲望。
?氛围的概念
- 从产品的角度,氛围中心提供了一个操作台,在配置规则之后,就可以在不同位置设定不同的氛围文案
- 从开发者的角度,调用氛围中心的接口,将商品的信息和要展示的位置等参数输入进去,就会输出需要展示的氛围结果
- 从用户的角度,氛围中心使得商品在页面上的不同位置展示了一些不同的营销氛围。
氛围中心的主要工作就是决定在什么位置经过某些规则后展示什么内容。
举个例子,在淘宝App的购物车页面,如果满足访问用户是88VIP用户的规则,就展示与88VIP相关的文案,同时屏蔽掉其他氛围。
?为什么需要氛围中心?
- 从用户体验上:导购、交易等全链路需要进行统一的氛围表达和规则管控,以保证营销活动整体氛围的完整性,促进成交转化
- 从开发成本上:由氛围中心统一收口,能够减少团队之间的沟通成本,屏蔽各方差异性,提高开发效率。如果没有氛围中心,单个团队推动耗费精力较大:每新增一类营销优惠工具(例如卡券)需要对接搜索、详情、下单等多条链路;每开辟一条新的渠道链路(例如新的搜索页)需要确认是否涵盖原有工具、协调新渠道的透出优先级等等。
氛围中心的整体架构
与一般业务系统不同,氛围系统涉及淘宝和其他App的各种位置,QPS非常高。任何的外调、DB/Tair查询都会导致RT急剧上升,所以采取本地调用的方式进行接入。在业务方的应用中,氛围二方包通过中间件Diamond读取并同步配置信息,并为业务方提供本地接口。
Diamond 是在阿里巴巴集团中广泛使用的配置中心,提供持久化管理和动态配置推送服务。
氛围中心的整体架构如下图所示,以氛围二方包为中心,红线左侧为前端界面,红线右侧为后端逻辑;以蓝线为划分,上方为配置端逻辑,下方为实际业务方调用链路。
从图中可以看出,配置端的操作会经由“前端—应用M—应用B”的链路最终影响到Diamond配置,业务方应用通过二方包进行配置同步并更新配置。
此外,氛围中心还通过应用S提供了HSF接口。除了用以集成测试和用例回归外,对于一些QPS不是很高的业务方,HSF调用也是一种远程接入的方式。
HSF(高速服务框架,High-speed Service Framework)是在阿里巴巴集团中广泛使用的分布式RPC服务框架。
?为什么有两套配置端?
如果观察氛围中心的架构图,你会发现其实氛围中心有两套配置端,这其中有一部分是历史的原因,但很大程度上也是必然的结果。
我们回顾一下氛围中心的核心任务:决定在什么位置经过某些规则后展示什么内容
似乎看起来责任很清晰,只需要将位置、规则和内容抽象出来,就生成了一套对应的氛围逻辑。配置端A正是如此:在配置端A里,我们将规则抽象为利益点,位置抽象为渠道,每一个利益点在一个渠道配置有相应的氛围内容,由此实现了规则到位置的 NxN 映射关系。但是在实际中,因为大促活动的存在,我们还有能够随着活动时间快速配置、但透出位置和规则(活动标)却相对固定的需求,即为一种 MxNxN 的一种映射关系,这里的M特指活动时间,由此形成了配置端B。
我们可以看到两套配置端其实侧重点不一样,配置端A主要关注的是规则到位置之间业务映射,而配置端B更关注于如何在大促活动中进行统筹管控。
那么,真的需要同时存在两套配置端吗?
需要,但也不需要。
从现状来看,两套配置端各自有自己特殊的表达,无法单独支撑全部氛围管控任务,需要同时存在:配置端A无法支持大促信息;配置端B的日常氛围管理(即除大促活动外的普通日常氛围)虽然能在一定程度上的等价替代,但是对于位置而言,页面逻辑还是不足以完全表达。
从未来看,两套配置端合并只是时间和成本的问题:第一,两套配置端非常容易引起误解,很多初次接入的应用方会配错位置;第二,两套配置端底层有着相同的输出(二方包、Diamond),改动点只在于前端界面如何从产品角度完整展示位置、规则和内容这三部分的逻辑。
?配置端链路
下面通过简述配置链路来说明氛围配置是如何生产并同步的。
在配置链路中,应用M仅起到了认证和权限控制的作用,不作过多阐述。
在应用B中,氛围中心维护了一个针对TDDL数据库的增删改查模块,而且由于配置端使用人数很少,只有有限个产品和开发使用,不需要考虑高并发场景。氛围中心与一般的后端系统相比特殊之处在于:保存数据库时,会同时保存两份数据。一份是一般的数据表单对象,包含了修改人、更新时间等较为详细的信息,用以向前端输出展示,另一份数据是需要同步到Diamond的配置信息,它以字符串的形式,按照分类保存在数据库中,并通过中间件ScheduleX的定时推送任务周期性同步至Diamond。
TDDL(Taobao Distributed Data Layer):是在阿里巴巴集团中广泛使用的一套分布式数据访问引擎,这里作为数据库使用
ScheduleX:是在阿里巴巴集团中广泛使用的分布式任务调度工具,这里作为定时任务中间件使用
氛围中心选择ScheduleX的推送模式为单机模式,即在应用B的集群中随机选择一台机器执行该任务。同时为了保障手动推送时的数据一致性,氛围中心还使用Redis维护了全局锁,保证了每次操作有且仅有一个线程在运行。
在数据库中,每条Diamond配置是分类型存放的,比如时间、图标、文案等都分别保存在不同的Diamond中,这种保存方式有利于配置读取操作的实现,但是却给保存操作带来了困难。对于普通表单的增删改查,只需要操作DAO层即可,但是如果要同时修改对应的Diamond信息,因为不同场景保存的Diamond各有不同,则需要针对不同业务做定制。氛围中心使用抽象类来实现对基本表单对象的修改;而在不同的继承子类中实现对不同业务的Diamond配置的更新。例如在业务处理器A中,通过定制方法只更新了图标、规则等A业务所需要的配置信息。
public abstract class BaseHandler{
/**
* 抽象类中add方法示例
*/
public Result<T> add(Request request, boolean effect) {
// 使用Maybatis对应的DAO修改普通表单数据
// ……
// 走定制逻辑修改Diamond配置
if (effect) {
effect(request);
}
// ……
}
/**
* 实际继承类单独定制方法
*/
protected abstract void effect(T t);
}
public class AHandler extends BaseHandler{
/**
* 针对业务A的定制
*/
@Override
protected void effect(ADTO dto) {
// 保存与A相关的配置
// 输入参数已序列化为待保存的对象
Result<ADTO> result = AManager.saveA2Diamond(dto);
// ……
}
}
由上述逻辑可以推测出,在Controller层至少要存在有两个字段才能区分出前端的请求:一个字段指定要操作的处理器,另一个字段要指定进行操作的具体方法(包括增加、删除、修改、生效、推送上线等等)
// 从请求参数中取出识别码获取对应的处理器
Handler handler = HandlerFactory.getHandler(request.getBusinessCode());
handler.check(request);
// 针对不同的操作,调用对应处理器的处理方法
switch (request.getHandleType()) {
case add:
return handler.add(request, true);
case detail:
return handler.detail(request);
case list:
return handler.list(request);
case copyOnline:
return handler.copyOnline(request);
// ...
default:
return Result.buildErrorResult("handle not support");
}
实际上前端的请求也确实包含了这两个字段,一个典型的POST前端请求参数如下
{
"environment": "pre", // 用以区分线上还是预发
"businessCode": "业务code", // 指定要使用的Handler
"handleType": "modefy", // 具体操作方法
"id": 0, // 主键id
"content": {
//JSON对象
}
}
至此,我们沿着数据库/Diamond—Manager/Handler—Controller—前端的链路了解了氛围中心配置端的整体调用链路。
总结一下配置端的几个特点:
- 数据库同时保存两份数据,一份普通表单对象,另一份整理为Diamond配置
- 配置通过ScheduleX进行周期性同步,并使用Tair的全局锁保证数据一致性
- Handler层使用抽象类封装对普通表单数据的操作,继承子类实现对不同Diamond配置的保存
- 前端请求参数中有处理器、处理方法的标识字段
?二方包逻辑
我们再来看一下氛围二方包是如何调用的。
氛围二方包除同步配置之外不进行任何远程调用,应用方如果查询氛围,请求参数除了必备的位置信息(应用名+位置)外,还需要提供商品、优惠等信息。
不同链路依赖的数据源不同,为屏蔽链路之间的差异性,首先需要将输入标准化,构建出统一输入对象。
统一输入对象构建完成后,就是计算有效氛围列表的环节了,首先氛围二方包会从Diamond中获取对应渠道和当前时间的利益点列表,利益点经过一些特制的预处理操作之后,就会循环计算单个氛围是否满足规则条件,最后,通过规则过滤的氛围还会进行互斥等后置处理。
验证氛围首先是根据配置中的全局规则、时间等规则进行过滤,再执行用户自定义规则的过滤。
用户自定义规则按照树型结构进行整合,主规则节点定义了条件执行的策略,包含与(And)、或(Or)的关系;叶子节点定义了实际规则,例如{商品标:1234,优惠:abc,取反:true}
符合条件的氛围会进行素材写入。在素材写入中,除了读取Diamond中配置好的固定内容之外,氛围中心还支持动态文案拼接。动态文案是指在配置端配置诸如满${a}件打${d}折的文案,只需要在请求参数的扩展字段Map中填入相应的内容,例如{a:2,d:75}即可为满足透出逻辑的氛围动态生成,这个功能是通过org.apache.commons.lang3.text.StrSubstitutor#replace(java.lang.Object, java.util.Map<java.lang.String,V>)实现的。
总结与展望
初次接触氛围中心,谈一谈我这三个月来的所见所想。
氛围中心是一个有其自身特性的系统,它经过了不断的迭代和优化,形成了现在的体系。它很好,但是仍有不足:
- 整合配置端:同时存在两个配置端确实带来了一些困扰,我们需要通过合理的产品抽象,将位置、规则、时间、活动等信息统一表达,将配置端整合为一个。
- Diamond优化:目前氛围中心有四十多条配置,约6MB。一方面超出了Diamond推荐的大小了;另一方面,手工很难去维护和管理如此数量的配置信息。近期的计划是增加过期删除逻辑,先将一部分过期的配置从Diamond中剔除掉,只保留在基本表单中。在开发过程中也在思考是否需要重新组织Diamond的结构,减少Diamond的条数,同时使用分区分片的方式,使得单个应用只读取与自己有关的配置,增强配置的可读性。
- 特殊逻辑的代码越来越多:随着开发的不断迭代、修改,层出不穷的预处理器和后置逻辑,还是被不可避免的引入到了代码中。每当个性积累到一定程度,我们就需要对代码进行重构和整理,提取其中的共性加以抽象。这是一个周期性的任务,一个应用只有不断的重构和优化,才能走得更远。
团队介绍
我们是大淘宝技术平台营销工具团队,是营销业务核心支撑团队,承担成交杠杆的职责,通过创新不断帮助业务挖掘新场景新用户、结合商业化能力打造技术引擎。平台营销工具不断沉淀商业能力、运营支撑能力,例如品类券、购物津贴、会员卡等实现动态加码、混合出资,极大提升了面向竞争的灵活性;前N、买就返等形成大促标配组合拳,稳定支撑全年50+大促活动。
相关推荐
- RACI矩阵:项目管理中的角色与责任分配利器
-
作者:赵小燕RACI矩阵RACI矩阵是项目管理中的一种重要工具,旨在明确团队在各个任务中的角色和职责。通过将每个角色划分为负责人、最终责任人、咨询人和知情人四种类型,RACI矩阵确保每个人都清楚自己...
- 在弱矩阵组织中,如何做好项目管理工作?「慕哲制图」
-
慕哲出品必属精品系列在弱矩阵组织中,如何做好项目管理工作?【慕哲制图】-------------------------------慕哲制图系列0:一图掌握项目、项目集、项目组合、P2、商业分析和NP...
- Scrum模式:每日站会(Daily Scrum)
-
定义每日站会(DailyScrum)是一个Scrum团队在进行Sprint期间的日常会议。这个会议的主要目的是为了应对Sprint计划中的不断变化,确保团队能够有效应对挑战并达成Sprint目标。为...
- 大家都在谈论的敏捷开发&Scrum,到底是什么?
-
敏捷开发作为一种开发模式,近年来深受研发团队欢迎,与瀑布式开发相比,敏捷开发更轻量,灵活性更高,在当下多变环境下,越来越多团队选择敏捷开发。什么是敏捷?敏捷是一种在不确定和变化的环境中,通过创造和响应...
- 敏捷与Scrum是什么?(scrum敏捷开发是什么)
-
敏捷是一种思维模式和哲学,它描述了敏捷宣言中的一系列原则。另一方面,Scrum是一个框架,规定了实现这种思维方式的角色,事件,工件和规则/指南。换句话说,敏捷是思维方式,Scrum是规定实施敏捷哲学的...
- 敏捷项目管理与敏捷:Scrum流程图一览
-
敏捷开发中的Scrum流程通常可以用一个简单的流程图来表示,以便更清晰地展示Scrum框架的各个阶段和活动。以下是一个常见的Scrum流程图示例:这个流程图涵盖了Scrum框架的主要阶段和活动,其中包...
- Mockito 的最佳实践(mock方法)
-
记得以前面试的时候,面试官问我,平常开发过程中自己会不会测试?我回答当然会呀,自己写的代码怎么不测呢。现在想想我好像误会他的意思了,他应该是想问我关于单元测试,集成测试以及背后相关的知识,然而当时说到...
- EffectiveJava-5-枚举和注解(java枚举的作用与好处)
-
用enum代替int常量1.int枚举:引入枚举前,一般是声明一组具名的int常量,每个常量代表一个类型成员,这种方法叫做int枚举模式。int枚举模式是类型不安全的,例如下面两组常量:性别和动物种...
- Maven 干货 全篇共:28232 字。预计阅读时间:110 分钟。建议收藏!
-
Maven简介Maven这个词可以翻译为“知识的积累”,也可以翻译为“专家”或“内行”。Maven是一个跨平台的项目管理工具。主要服务于基于Java平台的项目构建、依赖管理和项目信息管理。仔...
- Java单元测试框架PowerMock学习(java单元测试是什么意思)
-
前言高德的技术大佬在谈论方法论时说到:“复杂的问题要简单化,简单的问题要深入化。”这句话让我感触颇深,这何尝不是一套编写代码的方法——把一个复杂逻辑拆分为许多简单逻辑,然后把每一个简单逻辑进行深入实现...
- Spring框架基础知识-第六节内容(Spring高级话题)
-
Spring高级话题SpringAware基本概念Spring的依赖注入的最大亮点是你所有的Bean对Spring容器的存在是没有意识的。但是在实际的项目中,你的Bean必须要意识到Spring容器...
- Java单元测试浅析(JUnit+Mockito)
-
作者:京东物流秦彪1.什么是单元测试(1)单元测试环节:测试过程按照阶段划分分为:单元测试、集成测试、系统测试、验收测试等。相关含义如下:1)单元测试:针对计算机程序模块进行输出正确性检验工作...
- 揭秘Java代码背后的质检双侠:JUnit与Mockito!
-
你有没有发现,现在我们用的手机App、逛的网站,甚至各种智能设备,功能越来越复杂,但用起来却越来越顺畅,很少遇到那种崩溃、卡顿的闹心事儿?这背后可不是程序员一拍脑袋写完代码就完事儿了!他们需要一套严谨...
- 单元测试框架哪家强?Junit来帮忙!
-
大家好,在前面的文章中,给大家介绍了以注解和XML的方式分别实现IOC和依赖注入。并且我们定义了一个测试类,通过测试类来获取到了容器中的Bean,具体的测试类定义如下:@Testpublicvoid...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- 框架图 (58)
- flask框架 (53)
- quartz框架 (51)
- abp框架 (47)
- jpa框架 (47)
- springmvc框架 (49)
- 分布式事务框架 (65)
- scrapy框架 (56)
- shiro框架 (61)
- 定时任务框架 (56)
- java日志框架 (61)
- JAVA集合框架 (47)
- mfc框架 (52)
- abb框架断路器 (48)
- ui自动化框架 (47)
- beego框架 (52)
- java框架spring (58)
- grpc框架 (65)
- ppt框架 (48)
- 内联框架 (52)
- cad怎么画框架 (58)
- ps怎么画框架 (47)
- ssm框架实现登录注册 (49)
- oracle字符串长度 (48)
- oracle提交事务 (47)