APPKIT打造稳定、灵活、高效的运营配置平台
一、背景
美团App、大众点评App都是重运营的应用。对于App里运营资源、基础配置,需要根据城市、版本、平台、渠道等不同的维度进行运营管理。如何在版本快速迭代过程中,保持运营资源能够被高效、稳定和灵活地配置,是我们团队面临的重大考验。在这种背景下,大众点评移动开发组必须要打造一个稳定、灵活、高效的运营配置平台。本文主要分享我们在建设高效的运营配置平台过程中,积累的一些经验,以及面临的挑战和思考。
运营资源
简单而言,运营资源可以理解为App中经常变动的一些广告、运营活动等等,譬如下图中电影首页顶部的Banner位,就是一个典型的运营资源。对于这类运营资源,它们有如下明显特征:
- 时效性,只在一定时间范围内显示在C端固定位置。
- 城市强相关,这类运营资源往往是基于LBS类服务,每个活动、广告都只会出现在固定的某些城市(或区域)。
基础配置
基础配置,常见的有入口资源的配置、网络的配置等。相对运营资源来说,其变更的频繁度相对较低,与时间、城市的关系也没那么强。譬如下面大众点评App-我的页面里的入口。这类配置有如下几个特征:
- 多维度:需要针对不同的版本、平台、渠道,做不同的配置。
- 长期有效:这种类型的配置一般长期存在,不会存在过期问题。
二、遇到的问题
在从0到1打造运营配置平台的过程,我们遇到了很多“坑”。特别是在早期"刀耕火种"的时代,对于入口的配置,往往是通过"hardcode"(硬编码)的方式写死在代码中。所以必然会遇到很大的问题,这主要体现为以下两方面:
运营效率低
对于新的运营配置需求,研发同学需要开发对应的配置页面,然后转给运营同学进行配置的管理,最后运营人员对资源进行配置上线,其流程如下:
对于每个运营配置需求都要经过需求评审、页面开发、配置管理、上线的流程。同时,对于配置页面的开发,少则需要1到2天的开发工时,研发成本高。问题总结如下:
- 研发成本高,每个需求要开发新的配置管理页面。
- 研发周期长,运营效率低,从需求的提出到运营上线周期长。
- 灵活性差,对不同的运营维度(城市、版本、时间等)都需要事先确定好,无法动态调整。
上线流程"粗糙"
在早期,运营配置上线流程需要研发同学参与。产品提出运营配置需求,研发同学通过修改代码对配置进行变更,然后通过代码上线进行发布。整体流程如下:
这种上线机制存在以下几个问题:
- 配置上线过多依赖于代码的发布。
- 整体上线过程无审核机制,无法对配置资源进行合规审核。
- 配置容易出错,上线前不能提前预览上线后的效果,只有“事后”(上线后)才能验证效果。
三、我们的思考
针对以上问题,我们希望通过设计一个通用的解决方案,去解决上文阐述的各种运营资源管理的问题。我们把这个整体的项目称之为APPKIT,寓意是App的运营配置工具(Kit)。通过不断的实践和总结,我们希望能从三个维度解决上述问题:
数据JSON化
随着业务的不断迭代,无论采用怎样的数据字段组成,都无法满足业务变化的字段(这里是指像标题、副标题、图片、跳转链接等)要求。对底层数据进行JSON化,其对应的数据字段完全可动态扩展,从而满足业务不断迭代的需求。JSON化随之也会带来运营位字段管理的问题,我们通过字段管理的工具来解决这个问题。
运营流程化
设计一套整体的流程管理机制,解决运营的投放、审核、发布和回滚的问题。通过流程化的机制,我们实现了“事前”、“事中”、“事后”的三级管理。
首先,在运营配置上线前,通过测试用户的预览功能,可以预览上线后的实时效果。同时,通过穿越功能可查看将来时段显示的效果。防止出现上线后链接出错、视觉效果达不到预期等问题。
其次,在流程阶段,引入审核机制,通过视觉和内容两方面的审核,保证投放数据的准确性。
最后,在运营配置上线后,如果发现问题,可以通过快速回滚,最大限度地实现“止损”。
接口SDK化
对于运营数据,无论是通过数据库的落地方案、还是通过分布式缓存的方案,都无法彻底解决服务中心化和服务抖动的问题。通过接入的SDK化,可以做到数据的本地缓存更新机制,解除对中心化服务的依赖,大大提升服务的稳定性和性能。同时整个APPKIT服务变成可水平扩展,在扩展过程中也不会影响中心服务的稳定性。
四、APPKIT架构
APPKIT运营配置系统整体框架如下(数据流向如箭头所示)。从功能角度,大体上分为四层:数据层、服务层、接入层和监控层。
4.1 数据层
数据层作为最底层的数据存储,其保存了最基本的运营后台数据、流程数据和线上数据。对持久化的数据,我们采用MySQL进行存储;对于缓存数据,我们采用了Redis的解决方案。这样数据层形成基本的两级存储结构:MySQL保证了数据的持久性,Redis保证了数据获取的速度。
这里我们对底层数据划分为三个不同域:后台数据,相当于草稿数据,运营人员所有的操作都记录在这里;流程数据,运营人员操作完成后,提供发布流程,预览及审核都在流程数据里进行;线上数据,审核通过后,数据同步到线上数据,最终C端用户获取到的数据都是来源于线上数据。
谈到数据层,这里我们遇到了存储上的一个小问题。按城市运营的每条数据,都需要存储具体的城市ID列表,其在数据库里的存储为 “1,2,3,4...... ”这样字符串。而这种数据存储在业务请求和条件过滤过程中,存在着如下两个问题:
a. 大数据存储对内存的消耗
美团、大众点评运营的城市成千上万,如果每条运营的投放数据都包含大量的城市列表信息,对机器内存势必产生一定消耗。
b. 过滤性能问题
城市的过滤逻辑大体是这样:用户所在城市与从数据库获取到的城市列表(“1,2,3,4...... ”)进行匹配,在每次匹配过程中都需要做字符串"split"的切割操作。这种操作的特点是流量越大,对机器CPU的消耗越大。
解决方案:基于以上两点考虑,再结合Java语言提供的BitSet机制。我们从数据库里取出城市列表数据后只做一次"split"切割操作,将数据转化为BitSet类型。这样在实际过滤过程中只需要通过BitSet的get机制就可以判断运营投放的城市是否包含了用户所在的城市。通过BitSet机制,我们既解决了大数据存储对内存的消耗问题,又解决了城市过滤的性能问题。
4.2 服务层
服务层向下对底层数据进行操作;向上为接入层获取数据提供接入能力。其提供四个服务能力:运营后台、开放平台、数据服务、APPKIT-SDK,如下表所列:
4.3 接入层
接入层主要为运营人员、业务研发提供接入能力。通过运营流程化为事前、事中、事后提供保障。一个运营资源从制作到最后在C端展示,需要经过运营人员的投放、测试预览、审核及发布的中间流程。这里对于一些敏感的运营资源,需要通过安全部门的审查。安全审查主要涉及到敏感词的处理、敏感图片的检测等。对运营配置平台来说,它完全是一个“黑盒模型”。这里主要涉及到两种情况:
- 资源上线时
- 资源上线后
4.4 监控层
APPKIT-SDK运行在业务机器上,这里就涉及到多台机器的数据一致性问题。同时,随着业务接入运营数据的增多,SDK对机器内存势必有一定消耗。基于服务的稳定性考虑,我们对SDK运行时的投放内容进行监控,其主要监控两个指标:运营位数及每个运营位的配置总数。这样做可以带来以下几个好处:
- 对接入的业务数及机器数进行统计。
- 通过SDK的配置总数监控,防止数量超过最大限制。
同时,对于非SDK的其他性能指标,我们采用统一的监控平台--CAT进行监控,其中包括:APPKIT中心服务的调用QPS,机器的性能,网络流量等通用指标。
五、底层模型--灵活性设计
5.1 从一个例子切入
数据模型往往与业务相关。业务越复杂,设计需要越简单,这样方能满足复杂业务的各种变化。因为数据模型太过于抽象,如果直接进行述说会有些乏味,我们可以先从一个具体的业务实例入手。下面是大众点评App顶部金刚位的截图,对于这部分数据,如何做到运营可配?
首先,我们对运营数据做需求拆解。对于这块数据,每个 “节点”(对应每个位置:如美食,技术上我们称之为 “节点”),其基本的运营诉求如下:
- 节点内容信息:标题、图片、跳转链接、排序。
- 节点的过滤维度信息:城市、版本、平台、渠道等。
- 节点其他信息:角标,如外卖节点,其有一个下午茶这样的角标。值得注意的是,像下午茶这样的角标,除去文案、文案颜色这些基本信息之外,我们也可以按城市、平台、进行过滤(不周的城市对应的文案可能不一样,如上海为“下午茶”,北京因为嘉年华活动可以改成“嘉年华”)。
上面这个运营场景算是非常经典、复杂的一个运营场景了,如果这个问题解决了,其他问题自然就会迎刃而解。
5.2 技术分析
我们做一下进一步的技术分析:
首先,这里有节点,每个节点(Node)有其相应的内容(Content),节点与内容是“一对多”的关系。这里的内容,我们指的是如标题、图片、跳转链接等信息,虽然是“一对多”的关系,但最后在同一个城市、同一个版本下(可选择)只显示一条内容。为什么有这样的需求?举一个简单的业务场景实例,以外卖为例,在新版本10.0的时候做一了全新的外卖频道页面,其链接信息与老版本的完全不同,这里我们就需要按版本的不同配置两条不同的内容信息。
其次,节点与节点之间有两层关系,其一为“平级关系”,如美食与外卖的关系,这种关系就是一种简单的列表关系;其二为树关系(Tree),如外卖与下午茶之间的关系。这里我们将角标(下午茶)视为一个节点,因为角标也需要按不同维度进行过滤,因此下午茶成了外卖的子节点。其实这里有一些特殊的地方,如果角标不需要按城市、版本等维度进行运营,那很简单它就是一个内容信息(类似标题)。
最后,我们谈一谈排序问题,对于这么多品类,如何排序,他们的优先级是什么?我们需要定一个基本的基调,每个节点都有一个基本的排序值(优先级)。但深入业务分析,对于不同的人(群),每个人关注的点不一样,需要一个“千人千面”的算法,来决定每个人所看到的内容是其真正关心的内容。所以,这种应用场景下的排序应该通过机器学习算法而得到。
5.3 数据建模
针对上面的技术分析,我们提出了一种节点(Node)-内容(Content)-树(Tree)模型,简称为N-C-T模型。如下图所示:左边为抽象的数据模型,右边为以上实例的实现。
N-C-T数据模型设计的非常简单,其中C和T部分都是可选择的,这样使得其灵活性比较强,可以应对业务变化的大部分需求。注意,这里我们只是对业务需求的宏观表现形式进行建模,对于具体Node和Content里的有哪些字段(标题、副标题、图片、跳转链接),这些都是JSON化的存储格式,可以满足任意字段的扩展。
5.4 模型的应用与小结
通过以上经典实例,我们可以很容易通过我们的数据模型解决这个问题。我们再回到文章最开头的背景章节的运营场景,Banner位,如下:
这种Banner位,套用我们上的数据模型,它其实是一种只有一个Node结点、多个Content结点的模型。这也是一种典型的应用场景,为此我们总结了两种应用场景。
其实,大部运营场景都可以套用以上两种经典的运营组合。
六、运营流程化
将运营资源的管理进行流程化,具有以下几个好处:
- 资源上线前可进行严格的审核。
- 出问题时可快速回滚。
- 记录用户的(上线)操作历史。
- 上线前可提前预览线上效果。
数据域
对于流程化的实现,我们是将数据域切分成三个不同的部分:后台数据、流程数据和线上数据,如下图所示:
后台数据:我们可以简单理解为草稿数据,这里的数据多用户可同时进行操作,也不会对线上数据有影响。
流程数据:当用户后台数据编辑完成后,对数据提交一个发布流程,数据进入流程数据区域;这时可对数据进行测试预览、审核等操作。
线上数据:这块数据是C端用户真正获取到的数据,当流程数据审核通过后,数据会自动同步到线上数据域,完成上线操作。
上线流程
整个上线流程如下:
- 运营同学对后台数据进行修改,提交发布流程,同时进行预览测试。
- 审核同学对提交的发布流程进行审核。
- 审核通过,自动发布到线上(对审核不通过的流程,数据回退到后台进行再次编辑)。
为了能平稳上线,我们设计了一个测试预览功能。当数据处于流程中时,用户可以通过扫描二维码加入到测试用户名单,可对处于审核流程中的数据进行预览,用美团、大众点评App查看上线后实时效果,其实现的数据流如下:
七、稳定性的演进
稳定性是一个运营配置平台最重要的能力,没有稳定性,其他任何功能都会失去实际意义。运营系统的稳定性经历了不同的迭代时期,总结起来,可概括为以下三个阶段:
7.1 经典方案
这是APPKIT最早期的经典方案,它的实现也非常简单,如下图所示:
C端用户通过业务接入层获取数据,业务接入层通过服务调用获取配置后台数据(APPKIT服务),配置后台数据服务读取缓存数据。如果缓存数据不存在,则从数据库中读取数据,同时将数据库数据同步到Redis缓存中。这是经典的数据获取模型,但它有以下几个缺点:
- 数据调用有网络时延。
- Redis缓存抖动(网络抖动)会对服务的稳定性产生影响。
- 缓存的单Key存储的容量限制。
7.2 缓存方案
针对以上经典方案的缺点,我们做了进一步的改进,对配置后台数据服务做了一层本地内存缓存,如下图所示:
样做可以解决数据调用的部分网络时延问题,同时Redis缓存的抖动也不会影响整体服务的性能。不过,这个方案也有其自身的缺陷。
- APPKIT服务成了中心节点,业务方对中心节点强依赖,随着业务接入越来越多,中心服务的压力会等比例增加。
- 业务接入层与配置后台数据服务间调用的网络时延问题仍然存在。
- 单机的Web缓存容量有限,随着业务接入越多,APPKIT服务器本地缓存的数据量越大。
7.3 SDK方案
为彻底解决缓存方案的问题,尤其是服务中心化带来的流量、容量等问题,我们将运营数据的获取、Web缓存的管理集成进SDK。如下图所示:
这样的话,无论接入再多的业务,也不会对中心服务产生过大的流量压力和容量压力。SDK同时也解决了服务间调用的网络时延问题。所有同步数据的网络调用都是通过后台线程异步完成,不会影响业务线程的正常处理逻辑。
不过,SDK方案也引进了如下的新问题:
- 数据时效性和一致性如何保证?
- SDK本地缓存如何监控?过期数据如何删除?
- SDK版本如何升级?
为了解决数据的时效性和一致性问题,我们引入了监听更新机制,如下图所示:
运营人员在运营后台操作完成后,提交上线流程,流程发布后通过ZooKeeper的变化监控发送一个变化事件;SDK通过监听变化事件,拉取变化后的运营数据更新到本地。这里,为了防止这种监听机制失效,我们也做了一个兜底策略:每分钟定期进行一次数据同步。这样保证数据最迟一分钟内就能实现同步。对于SDK本地缓存,我们设计了监控上报机制,如下图所示:
这里有两条线路,其一为SDK在请求数据时,带上数据的accessTime时间戳,APPKIT服务会根据accessTime时间戳判断SDK本地数据是否过期。当accessTime时间超过24小时,说明这个运营位在一天内都没有使用,可以从本地内存中进行删除。其二为SDK定期进行监控上报,上报SDK本地缓存的数目,这样可以对SDK本地缓存进行监控和告警。对SDK版本升级问题,现有的解决方案,是通过CI构建时对SDK版本升级进行提示(必要时进行强制),不过大部分运营位使用的都是基础功能,在很大程度上不需要进行频繁地升级。
效果对比
缓存方案与SDK方案的效果对比如下:
注: SDK方案的平均线为0.0是因为统计时舍入引起的,真实值其实非常小。
八、总结与展望
本文通过美团点评移动运营平台的实践,详细介绍了我们在打造稳定、灵活、高效的运营配置平台过程中遇到的问题和挑战,同时本文也提供我们的解决思路:通过数据JSON化,运营流程化,接口SDK化分别解决了运营平台的灵活性、高效性和稳定性。APPKIT帮助产品、运营和研发提升C端的开发和运营效率,加速产品的迭代进程。
目前基于APPKIT的平台化特性,对App的模块化配置、Picasso的JS的管理、ABTest、个人中心入口管理、鲁班(面向C端的Key/Value配置系统)等业务提供了底层的数据存储和数据获取的支持,为移动端业务提供了运营配置的基础保障。
同时,为了进一步提升运营效率,我们基于Picasso的多端(Android、iOS、H5、微信小程序)能力,正在构建移动化的运营能力。这样保障用户无论在什么办公环境都能进行运营配置的管理。
作者简介
国宝,美团点评移动运营平台负责人,Java后端架构师,APPKIT项目发起人,负责APPKIT项目的架构设计。专注于高性能、高稳定、大并发系统的设计与应用。
小龙,目前为APPKIT项目负责人,主要负责APPKIT项目开发、技术对接和实施、开放平台等。专注于前后端全栈技术开发,喜欢挑战新的技术和业务问题。
发现文章有错误、对内容有疑问,都可以关注美团技术团队微信公众号(meituantech),在后台给我们留言。我们每周会挑选出一位热心小伙伴,送上一份精美的小礼品。快来扫码关注我们吧!
APPKIT打造稳定、灵活、高效的运营配置平台的更多相关文章
- GitHub + jsDelivr + PicGo + Imagine 打造稳定快速、高效免费图床
GitHub + jsDelivr + PicGo + Imagine 打造稳定快速.高效免费图床 前言 为什么要使用图床呢? 因为在不同平台发布同一篇文章的时候,最一个痛苦的点就是,图片存储问题,各 ...
- GitHub+jsDelivr+PicGo 打造稳定快速、高效免费图床
标题: GitHub+jsDelivr+PicGo 打造稳定快速.高效免费图床 作者: 梦幻之心星 347369787@QQ.com 标签: [GitHub, 图床] 目录: 图床 日期: 2019- ...
- 用友NC V6.3打造集团企业高效信息平台
近年来,随着互联网快速发展,信息化管理的应用也越来越普及,信息化建设已经深入到很多企业的核心业务,而且为了确保业务稳定.可靠并快速.有效地 开展,企业经常会运用多个信息系统进行辅助支撑,但是,许多企业 ...
- QQ会员活动运营平台架构设计实践——高效自动化运营
QQ会员活动运营平台(AMS),是QQ会员增值运营业务的重要载体之一,承担海量活动运营的Web系统.在过去四年的时间里,AMS日请求量从200-500万的阶段,一直增长到日请求3-5亿,最高CGI日请 ...
- VSCode + PicGo + Github + jsDelivr 搭建稳定快速高效图床
VSCode + PicGo + Github + jsDelivr 搭建稳定快速高效图床 目录 前言 准备 配置 验证 前言 所谓图床,就是将图片储存到第三方静态资源库中,其返回给你一个 URL 进 ...
- “如何实现集中管理、灵活高效的CI/CD”在线研讨会精彩内容分享
"如何实现集中管理.灵活高效的CI/CD"在线研讨会精彩片段分享 片段主讲人:李培(西瓜刀) 大家好,我是李培.前面听文老师讲DevOps,包括CI/CD 的一些理论,也是挺有 ...
- 如何突破Jenkins瓶颈,实现集中管理、灵活高效的CI/CD
在过去的几年间,随着DevOps的兴起,持续集成(Continuous Integration)与持续交付(Continuous Delivery)的热度也水涨船高.在本文中,我们将首先带您了解热门的 ...
- “如何实现集中管理、灵活高效的CI/CD”研讨会报名即将截止
如何实现集中管理.灵活高效的CI/CD ZOOM中文在线研讨会将于 2022年3月29日,星期二,下午3:00-5:00, 也就是 明天 举行, 如果您还未注册,点击按钮,立即注册此次研讨会(注册即可 ...
- 端云协同,打造更易用的AI计算平台
内容来源:华为开发者大会2021 HMS Core 6 AI技术论坛,主题演讲<端云协同,HUAWEI HiAI Foundation打造更易用的AI计算平台>. 演讲嘉宾:华为海思AI技 ...
随机推荐
- spring框架学习(七)spring管理事务方式之xml配置
1.DAO AccountDao.java package cn.mf.dao; public interface AccountDao { //加钱 void increaseMoney(Integ ...
- 发现IE 9的一个独有的小bug,并附解决方案
在最近的项目中,解决了一些浏览器兼容方面的bug,这篇主要描述在IE 9在渲染值为auto的overflow-x属性时,所产生的专属bug及解决办法. 1.问题描述 在做一个收货地址管理静态页面的时候 ...
- HDU 1069 Monkey and Banana(最长递减子序列)
题目链接 题意:摞长方体,给定长方体的长宽高,个数无限制,可随意翻转,要求下面的长方体的长和宽都大于上面的,都不能相等,问最多能摞多高. 题解:个数无限,其实每种形态最多就用一次,把每种形态都单独算一 ...
- C++中全排列函数next_permutation用法
最近做了TjuOj上关于全排列的几个题,室友告诉了一个非常好用的函数,谷歌之,整理如下: next_permutation函数 组合数学中经常用到排列,这里介绍一个计算序列全排列的函数:next_pe ...
- 61.volatile关键字
volatile作用 volatile的作用是可以保持共享变量的可见性,即一个线程修改一个共享变量后,另一个线程能够读取到这个修改后的值. 先来看一个问题: 定义一个Task类 package com ...
- 42、Java装饰者设计模式
设计模式简介 什么是设计模式?设计模式是可以重复利用的解决方案.软件开发的先驱或者前辈们将之前在开发中遇到的问题进行总结并给出了解决方案,后辈在遇到这些问题之后直接使用这些方案即可解决问题.比如盖高楼 ...
- c# 超长字符串截取固定长度后显示...(超长后面显示点点点) 通用方法
通用方法: 此方法是采用unicode编码方式,一个汉字为2个字节,一个数字or字母是1个字节,此方法传入的第二个长度参数是unicode长度. 所以不用考虑截取的字符串是汉字还是英文字母的问题,参数 ...
- 双击CAD对象,显示自定义对话框实现方法
class TlsApplication : IExtensionApplication { void IExtensionApplication.Initialize() { TTest.Start ...
- 新电脑重新安装win10+python3.6+anaconda+tensorflow1.12(gpu版)
安装了一天的软件,遇到了很多坑,在快泪崩的时候,始终以磨刀不误砍柴工鼓励自己,坚持安好了,话不多说,上干货: 前言: TensorFlow 有两个版本:CPU 版本和 GPU 版本.GP ...
- Java并发编程(2) AbstractQueuedSynchronizer的设计与实现
一 前言 上一篇分析AQS的内部结构,其中有介绍AQS是什么,以及它的内部结构的组成,那么今天就来分析下前面说的内部结构在AQS中的具体作用(主要在具体实现中体现). 二 AQS的接口和简单示例 上篇 ...