2

跨全端SDK技术演进

 1 year ago
source link: https://developer.51cto.com/article/714719.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

跨全端SDK技术演进-51CTO.COM

2ff7c9451b003dcc5dfd3c8a0b7565a2.jpg
跨全端SDK技术演进
作者:王东炜(鹿慕) 2022-07-25 17:57:43
本文将以消息SDK为例,详述这一技术演进历程,希望能给想做跨平台的,尤其是刚步入跨平台开发的同学和团队,一些借鉴和启发,帮助大家少走一些弯路。

细想,团队进行跨平台开发已有三年有余,也是集团里面C++方向里比较早涉及该领域的部门之一,伴随业界跨平台技术发展与演进,我们也沉淀了一整套基于C++的跨平台技术体系。

关于为什么要选择跨平台的实现方式

Write Once, Run AnyWhere.

越来越多的业务需求都有统一的业务诉求,按照传统的方式,在开发、测试、维护上的成本都是乘以N的,体验也很难做到一致性,特别是复杂的业务,实现成本高,导致功能不能很快的上线,各端侧对齐存在成本,综合来看,这样或者类似的业务基于研发效率等考虑,选择用跨平台的实现方式是非常有必要的。

这里以电商的消息为例,

图片

多角色的运营,多场景的触发,多重能力的支持,导致我们的消息系统十分的复杂,历史发展下的多通道消息系统底层由于历史发展衍生出3个子系统分别是:

  1. BC消息 - 最早的阿里旺旺就是基于此
  2. AMP消息 - 淘宝天猫的各类运营基于此,衍生出来的主要业务包括商家群、淘友、达人业务等,
  3. IMBA消息 - 主要是号方面相关的消息,包括BC通知类的消息、达人运营,品牌号运营等

分别在不同的BU维护,而这些在多平台运营下都是需要的,比如多角色的融合,多载体运行的诉求,每个载体又有多种平台。基于以上背景,研发一个高可用、高复用、可定制的跨终端消息模块是非常有必要的。

关于语言的选择

选择编译型语言还是解释型语言,我觉得是没有绝对而言的,具体选择哪个要根据面对业务形态,适配的终端类型等多方面抉择而言,这里说下我们选择C++作为跨平台开​发的首选语言一些背景。

  1. 我们团队本身是客户端的业务型团队,当前需要跨平台的业务主要是消息以及消息衍生业务的开发、维护和创新。
  2. 主要的终端包括移动IOS、移动安卓、MAC、WINDOWS。
  3. 主要载体包括淘宝app、天猫app、千牛app、淘特app、1688app、ICBU app等等。

C++作为天然的跨平台语言,可以高效无缝的调用系统能力,有丰富的技术生态,综合组内的技术栈,是比较契合我们的。

其实也跟集团里其他几个有类似需求的团队聊过,目前选择比较多的也是C++技术栈,本文也将以C++作为跨平台选型语言为主要来讲述。

即使是对于客户端而言,可选择跨平台语言也是众多的,通常跟随着跨平台技术方案一起来看会比较好一些,没有绝对的对和错,只有是否适合你。

关于基础库的选择

既然选择了C++作为我们跨平台开发的基础语言,那么面临的第一个问题是需要有一个功能较为完备,且符合当前诉求的基础库。我们调研了市面上几个主流的基础库

图片

再结合集团内当时的现状,特别考虑移动端的现状:

  1. 包大小问题
  2. 集团中多种中间件(mtop、db、accs等)要不然已然跨终端,要不然在各端上都有较为优秀的独立sdk提供,基于第一点考虑,这一部分不需要在基础库里二次建设。

综合以上因素,集团内没有合适的足够小的且满足需求的c++基础库,因此我们当时决定自研一个基于C++ STD的符合移动端现状的轻量级跨终端基础库。

图片

这里是跨终端轻量级基础库(LITE)的一个功能集合图,在对这部分进行设计的时候,主要考虑的几个设计原则:

  1. 基础能力要圈覆盖,
  2. 综合考虑包大小,性能 以及耗电量等
  3. 除了提供默认实现外,当系统层面有比较好的能力、或更优解时时,复用端上的能力,通过统一的方式嫁接。举个例子,集团中间件mtop,accs等,亦或者诸如Crypt模块,我们期望用比较简单的方式去实现,调用了Openssl的加解密接口,熟悉Openssl的同学都知道他的库大小在1M左右,同时IOS系统直接就提供Openssl能力,所以在做这一部分的时候我们提供了默认实现,同时开放统一接口接入系统能力,从而实现包大小最优。

总结一下设计原则9个字:最小够用可扩展原则。

包大小(kb, 基础功能)

ANDROID

动态库,v8a

静态库,实际占app大小

Windows

包大小情况如图(未包含淘宝天猫基础客户端能力,包含后略增加60k左右)。

目前Lite库已经作为淘系C++基础库集成在集团的近100个App里,除了包大小优势外,稳定性也极佳,百万分之1左右的崩溃率(淘宝双端统计),同时与淘宝天猫架构组合作,无缝提供淘宝天猫客户端基础能力(log、埋点、键值存储等)。

关于跨平台的架构选择

通常技术还是为业务服务,还是贴近业务来讲述,能更有体感一些,这样也更直观的把我们遇到的问题和背后思考透漏给大家,作为参考,还是以消息为例:

我们面临的问题和诉求:

  1. 屏蔽通道,以统一的数据模型方式对外提供:底层需要对接3个服务端(多通道),同时每个server端提供的能力、功能又高度相似,需要抽象后统一屏蔽提供给上层,此外相关数据需要跨通道或者屏蔽通道存储。
  2. 调用方线程不统一:业务部分需要处理来自不同线程的高并发(于客户端而言)请求。
  3. 多语言:接入层需要适配不同平台,ANDROID-JAVA,IOS、MACOS-Object C,WIN-C++。
  4. 多维度支持定制:
  1. 业务定制:业务上需要面对不同的APP可以有不同的功能定制,这里还包括支持通道的可配置,业务能力的可定制等,举个例子:在淘特里无群聊服务,但是在淘宝里这一部分又是需要的,在千牛里需要有商家群,但不需要有淘友关系群,等等基于业务、以及包大小考虑的定制。
  2. 线程调度定制:基于耗电量、系统资源、平台特性等考虑,需要线程调度方案的可定制。在移动端对耗电量比较敏感且系统资源有限,但是PC端上对性能要求会更高一些,如何在统一的方案里支持线程调度的平台级、甚至是业务级别定制。
  3. 网络流量管理定制:对网络能力一方面要有统一的监控,方便判断MTOP的各种API调用情况分析,另一方面需要有统一的切面能力,在MTOP的调用上做二次业务级别的网络流量接口优化定制。
  4. DB管理定制:基于FD、平台特定等考虑,需要DB管理可以根据不同的平台有不同的定制策略,在移动端采用单用户一库多表的形式,在pc端性能最大化采用多库多表甚至需要支持不同app的不同db管理方案可定制。
  1. 基础能力复用:对于集团通用的基础组件,需要有统一的能力从外部获取从而方便c++层使用。
  2. 稳定性保障:是否方便做单元测试,设计上如何避免单元测试对内部代码的入侵。

基于以上,我们设计了MessageSDK的架构大致如下:

图片

来整体看下上面的设计是如何解决这些问题的。

总体分5部分,Service层,业务层,数据层,数据通道层以及基础服务层。从上到下看整个架构设计

  1. Service层:也就是我们通常说的Wrapper层,其目的是为了翻译业务层C++的接口,提供三种方式的直接接入,Java,Oc,C++,需要说明的是这一层不要做除语言转换外的任何代码,一来方便问题排查,wrapper不做额外的处理和问题排查,二来业界也有不少自动化实现语言翻译的工具,有关这部分我们后面部分详细聊。
  2. 业务层:业务逻辑的一个组合,以消息为例,按模块分为三个子模块第一个消息模块,第二个profile模块,第三个群模块,模块与模块之间相对独立,做强制隔离,代码无耦合,功能可定制化
  3. 数据层:分为两部分本地存储以及网络存储,其目的是屏蔽数据来源以统一的方式提供给业务层,让业务不感知通道来源,同时在这一层还吃掉所有的耗时操作,IO以及网络请求,其中Adpter主要是屏蔽通道之间的差异,这一部分支持整体可替换,目的提高扩展性,可定制接入三方通道
  4. 数据通道层:这一部分就是数据来源的通道,主要有SYNC,WXNet,DB等
  5. 基础服务层:是一个跨平台的c++基础库。

其实客户端按层分割的设计理念,无论是在PC时代还是现在的移动互联,都不是什么显而易见的事儿,主要关注下这里面的差异点也可以说是这种框架设计的优点。

  1. 便捷:service我们只做语言层面的胶水,缩短后期排查问题的整个链路,方便后期排查和定位问题。同时自动化的实现也再次降低了维护成本。
  2. 开放:上图右侧是Openpoint能力,主要是通过一些标准化的开放点去开放一些能力,让接入方做更多的业务属性,简单来说【每个业务有特定的开放点,用统一的形式开放出去】
  1. 业务定制:模块与模块之间相互完全独立,代码无耦合,强制隔离,实现功能的可定制化,让业务方可以自由的进行业务形态组合的同时做到包大小最优,
  2. 线程调度定制:统一线程调度处理方案,抽象线程配置策略,多app可自由配置,上层可选择平台级线程调度最优方案。
  3. 网络流量管理定制:网络调用处统一切面处理,一方面对瞬时相同请求做拦截合并,大幅度降低服务端压力,另一方面针对业务级别做原子调用的合并定制,减少服务端查询量,此外切面处进行统一打点处理,方便客户端做调用流量监控。
  4. DB管理定制:同线程调度定制,统一DB管理分配方案,抽象库分配策略,多app可自由配置,上层可选择平台级线程调度的最优方案。
  1. 扩展:对外提供整体能力,又可以动态替换,目的是提供一种能力让接入方可以放入自己的数据通道,从而实现一个业务的扩展,此方法也极大的方便了后期做统一的单元测试。

于CPP程序员而言,线程模型是非常重要的,好的设计可以从架构上就避免掉后期一系列隐秘的bug,这里包括一系列问题,比如:

  1. 在移动端上,通常调用者不关心调用线程,但是在数据层又需要做统一的数据修改和聚合能力
  2. 业务层频繁调用,过多的锁除了可能会出现死锁外,也不利于性能最大化。
  3. 部分接口如果IO、NET时间过长可能导致整个流程中断,或异常。

来看下跨终端SDK架构设计的线程模型:

图片
  1. 接入层:不限制调用线程,降低接入成本
  2. 业务层 : 按模块做隔离,单独运行在自己的业务线程里,在biz层做业务无锁话的同时,做到单业务无锁化,多业务并行化
  3. Model层 : 主要是做IO、网络操作,目的是为了业务线程IO、网络无阻塞

整个线程模型的特点:纯异步,可定制,单业务无锁化,多业务并行化,IO网络无阻塞。

C++工程脚手架及C++工程标准化

C++作为天然的跨平台语言,可以高效无缝的调用系统能力,有丰富的技术生态。但是实际面向Android、iOS、Windows、Mac等多平台的开发过程并不顺滑,主要存在以下问题:

  1. 平台特性差异、开发语言、开发工具链、编译打包等
  2. 多平台下项目配置维护成本高
  3. 胶水(语言转换层)代码人工接入成本高、重复性工作大、门槛高(主要是对于C++开发者)
  4. 业务及技术框架选型困难
  5. 构建发布方案规范化较差、集团研发平台对跨平台构建发布的设计不足
图片

我们在想,SDK开发流程是否可以是一个可被SOP的过程?如果有统一的跨平台SDK开发SOP流程,特别是对于新入此行的同学,当然是非常友好的。想想coder如果可以上来就可以写业务代码,不用关心框架,工程模型,打包方案等等,是不是美滋滋。

为了解决上述共性问题,结合之前我们在消息SDK上的相关经验,我们启动了Eyas(雏鹰)项目。

Eyas旨在进一步结合集团技术能力,降低跨终端开发成本,为其提供标准化的作业流程,包括跨平台基础库组件化、业务框架通用化、配置一体化、语言转换层代码工具化,以及发布能力统一化等一整套解决方案,让开发者们可以在轻量级认识跨终端的同时,更专注于业务本身。

Eyas的中文是雏鹰,我们希望通过Eyas,可以一起在跨终端的蓝海中探索无限可能,同时可以孵化出更多跨平台的模块,让开发者低成本开发跨平台SDK,保证多平台业务一致性,提升业务开发效率的同时降低测试成本。

为了让开发者可以更快的上手跨平台的开发,我们拟定了一套跨平台SDK开发的作业流程,同时在每一步都提供了对应的解决方案,所有的解决方案均提供工具化的方式来高效、低成本的辅助开发者们进行跨平台SDK的开发。下图是MTL4上C++跨平台研发工作流:

图片

其中 IDL(接口描述)的编写 以及 功能代码编写,需要开发者根据实际业务进行开发。我们从项目创建、代码生成、编译选项和构建四个维度分析。

▐  创建项目

跨终端团队在以往的桌面端开发中积累了很多SDK开发经验,也有一套成熟的SDK框架代码,但是我们在孵化新SDK时候,还是要花一定时间在SDK的通用代码的拷贝上,无法快速的复制出一个新的SDK项目。

开发者都是懒惰的,为了尽可能的复用代码,提升开发效率,开发者发明了宏,也发明了模板编程。为了支持复用SDK框架通用代码和项目配置,我们提供了基于项目模板创建项目的工具,快速实现项目工程从0到1的过程。

其实对于刚涉足到跨终端开发的开发者,创建了可以编译不同平台产物的项目就已经开启了跨平台的大门。

图片

▐  代码生成

代码生成即语言胶水层代码工具化,由于平台开发的语言差异,需要有一层胶水代码来进行语言的翻译,胶水代码本身是没有业务逻辑的,并且耗费开发成本,人工编写代码也会带来出错的风险。我们使用胶水代码自动化来解决该问题。

胶水代码自动化的原理:

根据接口的idl描述生成接口文件和胶水代码

JNI: C++ <-> Java交互的胶水代码ObjCPP: C++ <-> ObjC交互的胶水代码

图片

我们基于djinni(地址:https://github.com/dropbox/djinni)进行了二次开发,提升安全性的同时增加了多项feature,更容易对复杂项目做模块定制化能力。

图片

▐  编译配置+依赖管理

项目结构:

图片

支持以下能力:

  1. 使用GN管理工程和源码文件,确保多端的C++项目配置一致。
  2. 统一多平台业务模块定制化能力。
  3. 支持多平台下不同IDE编码和调试。
  4. 结合集团技术能力,统一依赖管理解决方案,支持通过一份配置文件管理多平台下的依赖。

我们是大淘宝技术部行业与商家技术跨终端技术团队,业务上负责为千万级商家打造最高效的一站式工作台千牛,为淘宝上亿商家和消费者提供稳定高效的端到端消息IM服务;技术上深耕C++跨终端及PC桌面端技术(Window​s&Mac),为商家,消费者提供稳定,可靠,高效的客户端产品。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK