写点什么

【上汽零束 SOA】云管端一体化 SOA 软件平台系列介绍之五:服务实现篇

发布于: 9 小时前


近来 SOA 技术在汽车圈可谓是风生水起, 各路大咖关于 SOA 的文章也层出不穷,有写电子电气架构的,有写服务设计的,有写具体实现协议的,而我接下来从 SOA 软件实现的角度,结合一个具体的软件开发实例,让更多的朋友们理解什么是 SOA,SOA 背后的实质是什么,SOA 框架承担哪些职责,SOA 服务开发者要做哪些事情,SOA 开发过程中可能潜在哪些问题等等。


SOA 是一种方法论, 除了公认的一些特点外(譬如接口契约, 松耦合等),业界尚未有统一的定义。既然没有统一的定义,也就没有统一的实现方式。不过得益于一些标准化协会、开源组织及商业公司的共同努力,业界一时间出现了很多 SOA 框架,譬如 W3C 组织定义的 Web Service,OMG 组织定义的 Corba,微软的 WCF,阿里的 duboo 等,在很多领域(尤其是互联网领域),SOA 架构成为大量应用场景首选的解决方案。


而在汽车领域,目前非常热门的框架要数 Genivi 组织定义的 CommonAPI 和 AUTOSAR 组织定义的 Adaptive AUTOSAR(简称 AP)(AP 平台内容较多, SOA 框架核心部分是 ara::com)。AP 的 ara::com 和 CommonAPI 有很多的相似性,对于开发者而言,CommonAPI 实现起来会容易许多,而且 CommonAPI 是开源的,而 AP 则多是由商业公司(譬如 Vector, Electrobit 等公司)闭源提供。本文将基于开源的 CommonAPI 介绍,同时对比 AP 实现,让大家看到更多实现细节的同时,也可以看到 CommonAPI 和 AP 的差异。


当然,上汽零束的云管端一体化 SOA 软件平台也提供基于 SOA 的服务开发工具链和方法论,相关信息零小束也会在日后逐步公开,敬请期待。


一、设定应用场景

首先我们还是基于一个应用场景来定义服务。譬如以导航为例, 可以把计算一条路径的模块定义成一个服务。原因很简单,算路过程里面的实现还是蛮复杂的,里面会用到若干算法,通过把算路定义成服务,可以很好的把算路过程分离出来,很多基于算路的应用,譬如 HMI 等可以独立于算路模块,单独进行设计,这样可以达到模块解耦的目的。如下图所示:


二、服务接口定义

首先我们得认识一下什么是服务接口, 服务接口不同于传统应用的函数接口。因为 SOA 有一个基本特点,就是“接口契约”。“接口契约”简单点说就是一种接口描述语言 IDL,不同的 SOA 框架接口描述语言不尽相同,譬如 SOAP 框架基于 xml 语言,定义若干标签,通过标签描述交互数据及交互指令。而 CommonAPI 则是采用一种 Franca 设计的语言。


定义接口描述语言最大的好处就是,软件开发过程得到解耦。服务端开发团队和客户端开发团队在开发过程中不再依赖对方的交付,而仅依赖于该描述文件。一旦服务接口定义完毕, 双方可以独立开发,独立测试,可以有效地提高开发效率。


对于上述场景中的算路服务,我们假设该服务中提供一个算路接口,譬如叫 CalcRoute,该接口由 2 个输入参数(一个是起点道路 ID,一个是终点道路 ID),1 个输出参数(算路结果,由多条道路组成的一个 list)。这里仅仅是一个示例,实际场景会复杂许多。那么基于 CommonAPI 框架定义的接口文件为如下形式:


服务接口定义看起来非常容易,基本上有一些编程经验的朋友,上手应该会比较快的,因为定义服务接口只需额外记住一些规则即可。譬如输入参数用 in 标识,输出参数用 out 标识, 定义数组要使用 array,定义一个服务要用 interface 等等。如果我们要把接口设计得强大,要用到的特性就会更多一些,无论怎样,想做服务开发,服务接口提供哪些特性,开发者都是需要进一步深入了解一下的。


顺便说一下 AP,AP 在配置上就会稍微复杂一些,虽然仍然绕不开一些常见的概念:接口、方法、事件等,但是两者的形式还是有许多不同。CommonAPI 的接口是基于纯文本的,所见即所得,一看接口就能看出个所以然来。而 AP 则是基于 ARXML 的,ARXML 也是一种 XML,不过直接写 XML 还有点困难,因此 AUTOSAR 组织定义了一整套的 XML Schema,有很多的标签,定义了很多的特性,因此基本上只能通过图形化工具配置,而各家供应商定义的工具使用方法各异,各家供应商对 ARXML 的理解或者实现存在一些偏差,不兼容的现象也时有发生,甚至同一家供应商定义的不同上下游产品,也存在兼容性问题。这些对于开发者而言,确实是一件很让人头疼的事情。


三、服务接口代码生成

接口定义完毕,接下来就要进行代码生成了。通常至少会生成两个类,一个提供给服务端开发使用, 另外一个则提供给客户端使用。提供给服务端的通常叫 Skeleton, 提供给客户端的通常叫 Proxy。如下图所示:


该图除了描述代码生成过程之外,也基本描述了程序(服务端和应用端)的依赖组成以及函数接口调用流程。为帮助大家的理解,这里简单描述如下:


无论是服务端或者应用端,其核心组成主要是三部分:

1) 业务功能代码,譬如算路算法的实现等;

2) 服务接口生成代码 ;

3) 框架库,所谓的框架库是指一些常用的功能,不依赖于用户定义的功能,SOA 框架设计者通常把这些功能单独定义成 lib 库。

其由此不难发现, 应用程序和服务程序的本质基本是相同的,只是对于服务而言,提供服务实现,对于应用而言,调用服务接口,角色不同而已。


该图中描述了一个接口的调用过程, 应用端发起调用, Proxy 将函数调用 encoding 成数据流, 发送到服务端,服务端接收后,decoding 成函数调用,服务端触发其执行代码,这样就完成一次函数的调用。我们可以先简单讨论到这里,下文我们可以再详细讨论一下该过程。


生成代码以及类图如下图所示:



其中绿色代表代码自动生成的, 而白色则代表开发者需要完成的, 不难发现,客户端只需调用 RouteCalcProxy 即可, 该类提供两个方法,一个是同步调用方法,一个是异步调用。所谓同步调用就是指当客户端调用该方法时,会阻塞在调用处,直到服务端响应完该调用。这种方式对客户端而言,调用简单,但存在被服务端阻塞住的风险。因此,还定义一种异步调用方法,客户端调用时,需要设置一个 callback 函数,会通过该回调函数响应来自服务端的结果。这样,当某一个服务需要很长时间的时候, 客户端就有机会避免被卡死。


AP 生成的方法和这个类似,重点提两个小差别:

1) 服务端称之为 Skeleton。无论是 Skeleton,还是 Stub,这两种称谓在业界主流框架中都有被采用的,所以我们知道服务继承于该类即可。

2) Proxy 里只有一个基于 future 的方法,估计 AUTOSAR 认为无论是同步调用还是异步调用都可以通过 future 方式完成吧。同步调用,无非是调用结束后,多执行下 future 的 wait 函数而已,有利有弊吧。AUTOSAR 估计也是做出大量讨论之后做出的结论,零小束在这里就不多加评论了。


四、服务端代码开发


如下图所示,我们做了一个最精简的实现。当用户请求算法接口时,我们仅仅是打印一句话,返回一个简单的结果:


单纯构建一个服务类还不够,还需要有地方创建该对象。


我们在主函数中创建一个 RouteCalc 的对象, 然后将该对象注册到 runtime 中,这样服务端的代码就基本完成了。


五、客户端代码开发

我们再来看下客户端的代码实现,客户端代码实现起来也比较简单,先构建一个 Proxy 实例,然后不断查询该 Proxy 是否存在(Proxy Available 的前提是服务已经 ready)。当与服务连接成功后,就可以使用该 Proxy 调用服务的相关接口了。


六、服务部署配置


到目前为止,我还没有提及任何关于 SOME/IP 事情,那是因为服务定义和 SOME/IP 定义是两个完全独立的过程。对于客户端用户而言,他们关心 Stub 类即可,对于服务端用户而言,他们只关心 Proxy 类即可。这其实就是常说的 Language Binding,而至于最终底层是通过 IPC 通信或者是网络通信,而网络通信又分为若干协议,是 SOME/IP 通信,亦或者是 DDS 通信,上层开发者是无需太多关心的。而用户数据向 SOME/IP 数据流或者 DDS 数据流 Encoding 的过程又被称为 Network Binding, 也就是说一条算路的 method 请求,最终会被序列化成一条 SOME/IP 报文。


那么该 method 会对应 SOME/IP 消息格式里的 method 么?如果是的,那么 method 的 id 是多少呢?这里我们就得引入一个新的文件,fdepl 文件, Franca 创建专门的语言用于描述该文件,该文件定义服务接口与 SOME/IP 的对应关系,如下图所示:


通过该文件我们可以定义 calcRoute 方法所对应的 Method ID, Service ID 以及 Instance ID。该文件也对应一个代码生成器,代码生成之后会产生很多 SOME/IP 相关的实现文件。


从上图中不难发现,又生成了新的基于 SOME/IP 的 proxy 和 stub,它们基于服务接口描述,实现了序列化与反序列化到 SOME/IP 协议的过程, 是对 FIDL 生成代码的扩充,这样就彻底实现了从一个接口调用转化成一条 SOME/IP 消息的过程。


AP 和 CommonAPI 在这个环节基本也是类似的,但不同于 CommonAPI, AP 的服务定义与部署仅仅是 Arxml 中的两种不同标签而已,不像 CommonAPI,是通过两种不同的文件类型和代码生成器来进行区分。


七、结语

基于 CommonAPI + SOME/IP 框架的的服务端和客户端程序到这里基本就完成了。我们可以看到客户端程序可以像调用普通函数一样调用一个服务接口,而诸如序列化过程,通信细节,我们基本完全不需要考虑。这就是 SOA 框架的最大特点,开发人员将主要精力用于业务场景的服务设计上,框架提供序列化、反序列化,通信等基础能力,极大的地简化程序的设计过程。也因为如此, SOA 框架适用于大型的,复杂的业务场景,可以通过构建服务的方式,解耦相关功能,降低项目失败的风险。


SOA 架构只是一种设计方法,项目落地还需基于一个具体的 SOA 框架, SOA 框架质量的好坏从某种层面上决定了项目能否成功。然而仅有好的框架还不够,还要看服务架构的质量,而这又会涉及很多内容,譬如服务接口是否合理,服务对异常处理的能力如何,服务的依赖关系等等。


零束云管端一体化 SOA 软件平台旨在提供一个优秀的 SOA 框架,简化软件开发的难度,让服务开发和应用开发成为一件轻松的事情。相关信息后续也将逐步公开。


基于统一的平台的服务和应用,为应用生态提供了基础。后续系列文章将就云管端一体化 SOA 软件平台与应用生态的关系为大家带来更多分享,敬请期待!


作者:零小束

文章来源:上汽零束 SOA 开发者论坛

原文链接:https://bbs.z-onesoft.com/omp/community/front/api/page/mainTz?articleId=7488

版权声明:本文为博主原创文章,转载请附上博文链接!

用户头像

还未添加个人签名 2021.09.06 加入

还未添加个人简介

评论

发布
暂无评论
【上汽零束SOA】云管端一体化SOA软件平台系列介绍之五:服务实现篇