一、前言
笔者曾负责 vivo 利用商店服务器开发,有幸见证利用商店从百万日活到几千万日活的倒退历程。利用商店客户端经验了大大小小上百个版本迭代后,服务端也在架构上实现了单体到服务集群、微服务降级。
上面次要聊一聊在业务疾速倒退过程中,产品一直迭代,服务端在兼容不同版本客户端的 API 遇到的问题的一些教训和心得。一方面让团队内童鞋对已有的一些设计思维有一个更彻底的了解,另一方面也是心愿能引起一些遇到相似场景同行的共鸣,提供解决思路。
二、通用解决方案
利用商店客户端迭代十分频繁,公布新的 APP 版本的时候,势必导致呈现多版本,这样服务端就会导致多个不同的客户端申请。强制用户降级 APP,可能会导致用户散失,因而采纳多版本共存就是必须的。以下是业界探讨过的的一些 SOA 服务 API 版本控制办法参考[1]。在理论开发中原则上离不开以下三个计划。
计划一:The Knot 无版本——即平台的 API 永远只有一个版本,所有的用户都必须应用最新的 API,任何 API 的批改都会影响到平台所有的用户。(如下图 1)
计划二:Point-to-Point——点对点,即平台的 API 版本自带版本号,用户依据本人的需要抉择应用对应的 API,须要应用新的 API 个性,用户必须本人降级。(如下图 2)
计划三:Compatible Versioning——兼容性版本控制,和 The Knot 一样,平台只有一个版本,然而最新版本须要兼容以前版本的 API 行为。(如下图 3)
(援用自:The Costs of Versioning an API)
简略剖析,The Knot 只保护最新版本,对服务端而言保护有肯定简化了,然而要求服务使用者及时适配最新的版本,这种做法不太实用用户产品,目前外部服务比拟实用。Point-Point 针对不同客户的版本提供独立的服务,当随着版本的减少开发和运维的保护老本会减少,这种在前面咱们面对“协定降级”的时候有应用。
计划三应该是最罕用的状况,服务端向后兼容。前面案例也次要采纳这种思维,具体的做法也是有很多种,会联合具体的业务场景应用不同策略,这个会是接下来探讨的重点。
三、具体业务场景面临的挑战和摸索
3.1 The Knot 无版本和 Point-to-Point 模式的利用场景
上图是咱们利用商店迭代变动的一个缩影,业务倒退到肯定阶段面临以下挑战:
1)业务倒退后期,作为服务提供方,服务端不仅要撑持多个版本利用商店客户端,同时服务于软件侧的 PC 助手;
2)产品状态变动多样,服务端接口变更和保护面临多版本客户端兼容的挑战;
3)架构逻辑上,服务端采纳晚期传统架构,开发和保护老本比拟高;服务端与客户端进行交互的协定优化降级;以及服务拆分势在必行。
所以服务端协定、框架降级以及公共服务拆分是首要解决的方向。革新经验了两个过程:
- 阶段一 新版本新的接口一律采纳新的 JSON 协定;已有性能接口进行兼容解决,依据客户端版本进行辨别,返回不同协定的格局内容。
- 阶段二 随着业务迭代,新的版本商店依赖的所有接口都实现了协定降级后,为了晋升服务的稳定性,旧的协定性能无奈显著晋升,一方面降级后端架构和框架,晋升开发效率和可维护性。同时拆分和独立新的工程,实现历史工程只提供给历史版本应用。咱们针对大流量高并发、以及根底服务场景比方首页、详情、下载进行独立服务独立拆分。同时也提取一些公共的外部 RPC 服务,比方获取利用详情、过滤服务等。
通过革新,服务端架构如上图所示。
1)至此 Old-Service 后续只用进行相应的保护工作即可,对应 Point-to-Point 版本。
2)外部的 RPC 服务因为只提供外部服务,服务端和客户端能够随时同步降级,只有保护最新的版本就能够,采纳 The Knot 模式。这里须要留神的是服务的降级须要留神放弃向下兼容,在扩大字段或者批改字段的时候须要特地小心,不然可能在服务降级的时候会引起客户端调用的异样。
3.2 Compatible Versioning:兼容性版本控制
兼容性版本控制应该是最常见的版本控制形式,特地是在 C / S 架构当中,具体的兼容性版本不同的策略总结有 API 版本、客户端版本号、性能参数标记等。
场景一:API 版本号管制
随着互联网倒退的,用户体验要求也是越来越高,产品模式也会随之每年有不一样的变动。除了防止审美疲劳外,也是在一直摸索如何晋升屏效、点击率和转化。就拿利用商店首页列表举例。
利用列表在状态上经验过繁多的 利用双排 -> 单排 -\> 单排 + 交叉 的布局。内容上也经验了不同商业化模式、人工排期到算法等演进。
每个版本接口外部逻辑变动是非常大的,有显著差别。如果只是简略在 service 层依据版本进行判断解决,会导致解决逻辑会变得异样简单,并且还可能导致对低版本产生影响。同时商店首页是非常重要的业务场景,联合危险思考,相似这样对场景,在接口 URL 上新增版本字段,不同对版本应用不同的值,在管制层依据不同的版本进行不同的解决逻辑会更加正当,简略无效。具体策略也有比方在 URL 上新增接口版本字段 /{version}/index、申请头携带版本参数等。
场景二:客户端版本号管制
相似首页列表,商店的交叉 Banner 也经验了多个版本的迭代。如下图所示。这些交叉款式都是在不同版本下呈现的,在款式布局,反对跳转能力等方面各个版本的反对水平不一样,接口返回时须要进行相应的解决适配、过滤等解决。
这类场景如果采纳场景一的计划降级新的接口也可能解决,然而会存在大量反复代码,而且新增接口对于客户端接口革新、特地是一些接口门路会影响到大数据埋点统计,也是有比拟高的沟通和保护老本在外面。
为了晋升代码复用性。应用客户端版本号管制是首选思考策略。然而须要留神,如果只是简略的在代码层面依据客户端版本号进行判断,会存在以下问题须要思考:
1)代码层面会存在各种判断,造成的代码可读性差,有没有更加优雅的办法;
2)存在一个客观情况。那就是客户端的版本号是存在不确定性的。因为客户端采纳火车公布模式 参考[2],多版本并行开发,导致版本号存在变动、版本跳跃不间断的状况时有发生,也给服务端开发带来了不少困扰。
如何思考解决这些问题呢?其实对于不同的产品状态波及的一些资源或者产品模块自身呈现在不同的迭代周期,能够认为他们具备了版本或者工夫的属性。站在程序员视角,把某个资源反对对应的客户端版本作为这个资源对象的一个成员属性。每种资源具备这种属性后,也有相应的逻辑行为来对应成员办法 — 依据属性进行过滤。这样的设计赋予资源了属性和行为后,资源具备了对立的、灵便的过滤能力,而不再是简略的硬编码依据版本进行 if-else 判断。
有了计划后,施行起来就比拟容易了。开发分配资源 ID,并且设置对应反对客户端版本范畴。过滤逻辑对立到资源对象。
代码层面能够将过滤逻辑对立封装到一个工具类(示例代码),在各个业务接口返回进行过滤。更加优雅的计划是建设对立的资源下层类,封装资源过滤办法,所有资源位的资源对象实现该下层类,对立在获取资源逻辑实现过滤能力。
场景三:新增性能标识参数
利用商店业务次要提供用户发现和下载新利用、更新手机已装置的利用。商店有增量更新能够减小更新包体积,因而也叫省流量更新,无效晋升用户体验。后期咱们应用开源的增量算法,然而发现该算法在局部机器合成拆分包会耗时很长,甚至引起 crash。
于是项目组寻求更加高效拆分算法。相似在这些已有接口的进行性能加强的场景,除了提供新的 API 或者外部简略通过客户端版本判断进行扩大外,有没有更好的计划呢?因为除了这些计划已知的弊病外,须要从久远思考,比方后面提到的算法,后续还会不会存在降级的可能,下载接口会不会有更多能力的加强。
联合下面思考,在原来接口根底上新增 标记参数 字段,示意该申请收回的客户端反对的能力。为了后续扩大,字段类型为整数值,不只是简略的 boolean,服务端通过 位运算实现判断逻辑。客户端也解脱某个性能与版本的强一致性,不必去记录某个版本具备某种能力。
四、对于接口设计的更多思考
最初补充一些踩过的坑和反思。服务端在提供接口时,不能仅仅关注接口的实现,更多的时候须要关注接口的应用方,他们应用的场景、调用机会等等。否则开发在对接口问题排查、保护破费的工夫会比理论开发的耗时要多上好几倍。
1)场景化:具体到什么是场景化呢,拿商店客户端的帮忙用户检测手机装置的利用版本是否最新的服务举例,检测机会是存在不同的场景的,比方用户启动、用户切换 wlan 环境、定时检测等。当须要进行精细化剖析,哪些申请是无效的,哪些会引起集中申请时,这个时候如果申请上没有场景辨别,那么剖析将无从下手。所以在与客户端沟通接口设计时,请带上场景这个因素。接口设计上可参考如 /app/{scene}/upgrade,定义好各个场景名称,在门路上带上具体的场景,这样对线上不同起源申请量级、问题剖析都会有很大益处。
2)鉴权和服务隔离:除了场景须要思考外,接口调用在调配时做好记录和鉴权以及服务隔离。比方商店的局部接口服务不仅提供给客户端,同时也会提供给手机零碎利用调用。目前 vivo 上亿的存量用户体量,这里要非常小心,零碎利用的调用量管制不当,并发可比商店自身要大的多。首先后期与服务调用方评估沟通、做好设计,防止出问题。即便在出问题时,也要有机制可能疾速发现问题、可能剖析出问题的起源,升高问题带来的损失。
至此下面解决问题的思路,都与具体业务以及背景有肯定关系。随着技术一直迭代和倒退,在挪动端 APP 页面动态性,目前业界也有了更多高效的技术计划,比方谷歌的 Flutter、Weex 等。这些技术可能实现灵便扩大,多端对立,性能也可能靠近 native。不仅缩小了客户端发版频次,也缩小了服务端兼容性解决老本。目前咱们 vivo 也有团队在应用和实际。
技术一直更迭,没有最好的计划,只有最适宜的计划。开发过程中不仅满足以后实现,更多的是思考到后续扩展性和可维护性。开发不能一味谋求高端技术,技术最终服务于业务,保持长期主义,效率至上。
五、参考资料
1、The Costs of Versioning an API
2、麻利开发,火车公布模式
作者:vivo 互联网服务器团队 -Song jie