一切数据皆可配置:爱奇艺海外站的运营后台设计实践

{"type":"doc","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"爱奇艺海外App是一个"},{"type":"text","marks":[{"type":"strong"}],"text":"重运营"},{"type":"text","text":"的应用。对于App里的顶导航、我的页面、弹窗等,需要根据模式、版本、平台、语言、渠道等不同的维度进行运营管理。随着业务快速发展,版本快速迭代,如何保持运营资源能够被高效、稳定和灵活地配置,如何高效稳定的为新的运营需求提供支持,是我们需要解决的问题。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在这种背景下,爱奇艺海外Phone后端研发组通过打造一个"},{"type":"text","marks":[{"type":"strong"}],"text":"稳定、灵活、高效"},{"type":"text","text":"的运营配置平台来解决前面遇到的问题。本文主要分享我们在建设高效的运营配置平台过程中积累的一些经验以及面临的"},{"type":"text","marks":[{"type":"strong"}],"text":"挑战和思考"},{"type":"text","text":"。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"1.配置资源拆解"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"运营类配置可以分为两块,运营资源和基础数据的配置。"}]},{"type":"image","attrs":{"src":"https:\/\/static001.infoq.cn\/resource\/image\/f9\/a2\/f9dd01e9e6526e9a5563df73f100c4a2.png","alt":null,"title":"","style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"1.1 运营资源"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"简单而言,运营资源可以理解为App中经常变动的一些广告、运营活动等。比如上图中弹窗广告,就是一个典型的运营资源。对于这类运营资源,它们一般有如下特征:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"时效性强:"},{"type":"text","text":"只在一定时间范围内显示在C端固定位置。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"模式强相关:"},{"type":"text","text":"每个活动、广告都只会出现在固定的某些模式。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"数据变动频繁:"},{"type":"text","text":"特别是活动类数据,展示的图片文案等变动较为频繁。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"支持多语言展示:"},{"type":"text","text":"基于爱奇艺海外站面向全球用户的情况,不同模式下需要展示不同的语言文案。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"1.2 基础数据配置"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"基础数据配置相对于运营资源来说其变更的频率相对较低,与时间、版本的关系也没那么强。譬如下面爱奇艺海外App-底部导航栏(样式如上图所示)。这类配置有如下几个特征:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"多维度:"},{"type":"text","text":"需要针对不同的模式、语言做不同的配置。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"长期有效:"},{"type":"text","text":"这种类型的配置一般长期存在,过期场景较少。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"2.实践中的痛点:运营效率低、重复工作多"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"面对接二连三的运营配置需求,我们最初通过实现不同的配置界面来对接各类运营产品需求。但这必然会遇到很大的问题,这主要体现为以下方面:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"运营效率低"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"对于新的运营配置需求,研发同学需要开发对应的配置页面,然后转给运营同学进行配置的管理,最后运营人员对资源进行配置上线,其流程图如下:"}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/47\/476d047cca2cfa55fea0f5a89aa62faf.png","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"对于每个运营配置需求都要经过需求评审、页面开发、配置管理、上线的流程。同时,对于配置页面的开发,少则需要1到2天的开发工时,研发成本高。问题总结如下:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"1. 研发成本高,每个需求要开发新的配置管理页面。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"2. 研发周期长,运营效率低,从需求的提出到运营上线周期长。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"3. 灵活性差,对不同的运营维度(模式、版本、时间等)都需要事先确定好,无法动态调整。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"重复开发工作多"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"对于通用型的运营配置后台,某些特有的功能特别对于前后端来说重复开发工作明显。如操作记录,审核机制,根据不同的模式版本语言过滤数据等功能,在每次出现的配置需求中都需要重复的开发。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"3.实践中的思考:明确三个原则"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"针对以上问题,我们希望通过设计一个通用的解决方案,去解决上文阐述的各种运营资源管理的问题。我们把这个项目称为IQ运营位。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"通过调研我们确认项目设计的原则主要有以下三个:"}]},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"一切数据皆可配置"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"运营数据高可用"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"接口性能高效"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"通过不断的实践和总结,我们希望能从以下三个方面实现上述原则:"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"3.1 数据JSON化"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"随着业务的不断迭代,无论采用怎样的数据字段组成,都很难满足业务变化的字段(这里是指像标题、副标题、图片、跳转链接等)要求。对底层数据进行JSON化,其对应的数据字段即可实现"},{"type":"text","marks":[{"type":"strong"}],"text":"可动态扩展"},{"type":"text","text":",从而满足业务不断迭代的需求。JSON化随之也会带来运营位字段管理的问题,我们通过在运营后台提供了相应的字段管理功能来解决这个问题。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"3.2 运营数据多点存储"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"通过持久化存储,分布式缓存,以及接入业务方的本地缓存,运营数据的多方存储,保证极端情况下都有降级数据获取,降低系统异常的损失。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"3.3 接口SDK化"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"对于运营数据,无论是通过数据库的落地方案、还是通过分布式缓存的方案,都无法彻底解决服务中心化和服务抖动的问题。通过接入的SDK化,可以做到数据的本地缓存更新机制,解除对中心化服务的依赖,大大"},{"type":"text","marks":[{"type":"strong"}],"text":"提升服务的稳定性和性能"},{"type":"text","text":"。同时整个IQ运营位服务变成可水平扩展,在扩展过程中也不会影响中心服务的稳定性。调用方请求流程图如下:"}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/8c\/8cabb2e5760b06a552243ab6d57eff0f.png","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"4.IQ运营位架构"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"IQ运营位配置系统整体框架图。从功能角度,大体上分为四层:数据层、服务层、接入层和监控层。IQ运营位架构图如下:"}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/d8\/d8ac651dddc7e50ed37e454a90068ff6.png","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"4.1 数据层"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"数据层主要是存储接入IQ运营位的各类运营数据。数据层主要面临以下难点。"},{"type":"text","marks":[{"type":"strong"}],"text":"难点1,数据量大;难点2,QPS高。"},{"type":"text","text":"基于以上两大难点,我们通过redis集群做中间缓存,通过SDK使各业务方接入本地缓存、通过消息监听异步更新的方式来解决中心服务的流量压力。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"4.2 服务层"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"服务层向下对底层数据进行操作;向上为接入层获取数据提供接入能力。其提供四个服务能力:"},{"type":"text","marks":[{"type":"strong"}],"text":"运营后台、开放平台、数据服务、IQKIT-SDK"},{"type":"text","text":"。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"其中运营后台主要面向运营人员和产品,提供数据的配置后台。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"开放平台收归于开发技术人员,提供一个增加运营位配置的后台。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"数据服务主要是为调用数据的开发提供一个"},{"type":"text","marks":[{"type":"strong"}],"text":"统一的、高可用的、高性能的api接口"},{"type":"text","text":"。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"SDK为数据服务服务。主要目前是简化开发人员的接入成本,提供数据服务性能和可用性。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"4.3 接入层"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"C端接入如何更方便?"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"为了简化开发人员的接入成本,调用逻辑在SDK内实现,用户只需要引入maven包,注入OppkitClient,封装OppkitRequest,通过OppkitClient直接调用即可返回过滤并且翻译后的数据。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"B端配置如何更便捷?"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在设计项目的时候后台配置秉持的原则有且只有一个:"},{"type":"text","marks":[{"type":"strong"}],"text":"一切皆可配置"},{"type":"text","text":"。通过开放后台来配置IQ运营位,每个IQ运营位相当于一个业务形态,比如导航栏,而运营位内包含多个数据,比如title,link等,而title包含多种语言,需要配置多语言key。开放平台的作用就是创建IQ运营位,为IQ运营位配置字段。运营后台则用于配置开放平台创建的IQ运营位数据。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"4.4 监控层"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"除了数据存储层的监控以及烽火台对数据层与服务层的监控外,我们还对SDK内实现的本地缓存进行了监控。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"C端的接入即数据的获取在SDK内部实现,SDK内部我们做了以下功能:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"1. 如果请求包含某些特定离散字段如设备id,因为包含的数据量极大,存入本地缓存会给业务方的机器内存带来很大压力,则避开缓存直接请求服务。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"2. 为了满足数据实时性要求较高的业务方,新增不接入本地缓存的逻辑。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"3. 如果只包含某些聚合度高的字段如平台字段,版本,模式,语言等,则把请求的数据存入本地缓存。本地缓存通过监听运营平台的方式进行异步更新,当异步更新获取数据失败,则保持之前的数据返回,避免极端情况运营数据全部为空,将"},{"type":"text","marks":[{"type":"strong"}],"text":"业务损失降至最低"},{"type":"text","text":"。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"4. SDK内部通过异步线程,将本地缓存的使用情况通过定时线程存入,通过后台界面展示各缓存使用情况,对各类缓存的使用情况实时监控。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"5.稳定性与性能保障"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如上文所说在运营后台的设计考虑中,我们秉持了以下几个原则:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"一切数据皆可配置"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"运营数据高可用"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"接口性能高效"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"下面我们介绍下运营后台稳定性与性能保障所作出的解决方案。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"整体请求流程图如下:"}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/28\/2857b53f155400f4860ed5f9eb88d2d4.png","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"5.1 稳定性保障"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"作为各类运营数据配置的运营后台,"},{"type":"text","marks":[{"type":"strong"}],"text":"稳定性"},{"type":"text","text":"尤为重要。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"除了在操作机制上即运营流程化数据配置机制、多级数据存储使用分布式缓存以及分布式数据库以外,我们还提供了一个SDK方案来对服务的故障进行降级。下面我们将详细介绍该方案的落地过程。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"SDK本地缓存方案"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我们考虑到在实现本地缓存,有这样几个好处:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"1. 缓解中心服务的流量压力,更多的流量将会请求到本地服务的内存中。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"2. 基于爱奇艺海外站业务的特点,国外网络环境不可预测,环境差等情况,尽可能的减少网络请求链路。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"3. 一旦中心服务故障,周知各业务方不要重新部署,以本地缓存实现数据降级。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"但是本地缓存的方案缺点也非常明显,即一旦有运营后台数据更新,各业务方无法实时获取到最新的数据。基于此,我们对SDK进行了以下几个版本迭代工作。具体见下图:"}]},{"type":"image","attrs":{"src":"https:\/\/static001.infoq.cn\/resource\/image\/d8\/c5\/d8fd9c08dee428f6b164f641cbe44dc5.png","alt":null,"title":"","style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"技术架构演进到第三版,可以较好的解决中心服务流量问题,使得运营后台的流量由用户请求量决定改为"},{"type":"text","marks":[{"type":"strong"}],"text":"后台的数据更新频率"},{"type":"text","text":"决定,从而解决流量过载问题。但是该版实现也需要解决以下几个难点:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"1. 各业务方本地缓存的使用情况种类繁多,如何进行提供系统监控?"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":"br"}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"2. MQ的方案该如何设计?"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"针对问题1,我们在SDK内部实现一套这样的机制,通过"},{"type":"text","marks":[{"type":"strong"}],"text":"scheduledexecutorservice"},{"type":"text","text":"定时任务,周期性的将缓存使用情况拉取到库内,这样在通过后台界面就可以根据时间展示本地缓存的使用情况。这样,可以系统的掌握各个不同的业务方缓存的使用情况,供业务方的内存申请和分配提供数据支撑。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/e8\/e8fe5a584186b1d38dca3d792edd2028.png","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"针对问题2,涉及到的难点主要有两个:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"(1)业务服务机器一般都是一个服务有多台机器,所以一个消息的更新需要被多台部署相同代码的服务器同时消费,这样"},{"type":"text","marks":[{"type":"strong"}],"text":"确保每台机器都获取到最新的数据"},{"type":"text","text":"。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"(2)运营位有多个,但对于业务方来说没有必要在没有接入的运营位更新数据时去异步地请求运营后台中心服务更新数据(因为这些数据这个业务方压根没接入)。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"针对(1),明确的是消息的生产者是运营后台服务,而一个消息需要被所有业务方监听,具体的说是所有业务方的每台机器。所以,每台机器应该属于不同的消费组。所以我们需要找到一个每台机器都不一样的"},{"type":"text","marks":[{"type":"strong"}],"text":"标识节点"},{"type":"text","text":",以这个节点做为消费组。显然,这个节点最好的就是机器地址,可以保证每台机器所在分组都不一样。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"针对(2),我们提供一个配置文件,各业务方需要在配置文件内写入各自业务方使用的IQ运营位名称,当一个消息来临时,首先需要判断这个消息中的运营位名称是否包含在配置文件内,如果不在,则这条消息被忽略(空消费),如果在,则请求响应的运营位更新本地数据。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"5.2 性能保障"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"以上的SDK提供的本地缓存可以提高后端服务的性能,除此以外,我们还做了其他一些工作。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在运营位的实践配置中我们发现,运营数据的变化或者说运营人员更改运营数据的情形相比网络请求来说是非常低频的,比如之前分析的基础运营数据。因此,数据缓存在客户端可以避免客户端与后端服务的网络消耗,极大的提高性能。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我们的方案是为每个运营位数据提供一个版本的概念。通过保存各运营位的操作最新时间,在客户端开屏时发起一次请求,将所有的运营位最近的数据更新时间返回给客户端,客户端将该时间戳缓存在本地,当下次开屏请求时,同样会获取到服务端返回的运营位最近更新时间戳,将本地的与服务的进行匹配,来确认是否去更新各个运营位的数据,如果客户端缓存的运营数据时间与运营后台返回一致,则直接展示缓存在客户端的数据。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"这种方案的另一个好处是可以在极端的情况下,如对外暴露的api出现故障,通过"},{"type":"text","marks":[{"type":"strong"}],"text":"禁止运营后台的数据更新,可以使业务数据正常展示,避免出现运营数据消失的严重故障"},{"type":"text","text":"。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"具体的请求流程图如下:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/2f\/2fc1cf7c87b4f7afc0a23ac63913a826.png","alt":"图片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"6.总结与展望"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"本文主要介绍了IQ运营位的设计与开发的相关内容,首先根据遇到的痛点提出了运营后台的设计原则:一切数据皆可配置,运营数据高可用,接口性能高效。针对提出的原则去思考与实现具体的技术方案。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"通过配置数据的Json化实现业务字段的"},{"type":"text","marks":[{"type":"strong"}],"text":"可扩展性"},{"type":"text","text":"。通过设计的数据模型来介绍满足多语言情况下的各类运营配置数据方法。通过提供SDK内部实现本地缓存,MQ监听,异步更新的机制解决了服务中心化的大流量问题和缓存导致的数据不一致问题。针对海外的具体情况,提出了客户端缓存的相关方案。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"IQ运营位从今年5月开始规划,历时近半年时间,由于中途穿插了很多的产品需求,所以在自身使用与用户反馈两个渠道进行问题收集,前后共经过了两个版本的迭代。目前在运营后台的界面与使用便利度上在持续优化。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"IQ运营位上线2个多月以来在爱奇艺海外站得到广泛使用,在工程效率上更是有质的提高,拿最近的错误码配置来举例,错误码需要给客户端返回各类错误码以及对应的相关文案,文案是多语言场景的,通过IQ运营位配置化实现,只需要在分析需求,拆分业务字段和数据露出的条件后,"},{"type":"text","marks":[{"type":"strong"}],"text":"5min以内"},{"type":"text","text":"就可以给出相应的运营后台。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"当然,随着业务的迭代与场景更新,IQ运营位仍存在一些不完善的地方,在未来我们将会在工程实践中的持续迭代过程中做更进一步的工作,解决各类问题,更好的服务好IQ运营位的客户与广大爱奇艺海外用户。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"团队介绍:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"爱奇艺海外phone后端团队:爱奇艺海外事业部下,负责爱奇艺海外phone后端服务的开发和维护,为广大用户提供稳定、高效、流畅的视频内容服务。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"正飞:IQ运营位项目负责人,IQ运营位的设计与开发者。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"本文转载自:爱奇艺技术产品团队(ID:iQIYI-TP)"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"原文链接:"},{"type":"link","attrs":{"href":"https:\/\/mp.weixin.qq.com\/s\/ZBk4C4FpHoce6ngA340FfQ","title":"xxx","type":null},"content":[{"type":"text","text":"一切数据皆可配置:爱奇艺海外站的运营后台设计实践"}]}]}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章