自动驾驶软件架构:用于自动驾驶的SOA中间件

文章目录

  • 一、三个应用领域对SOA的推动
  • 二、自动驾驶对于中间件的要求
    • 1.SOA 架构风格与自动驾驶系统的适用性
    • 2.自动驾驶相关软件的特殊要求
  • 三、构建适用于自动驾驶SOA中间件
    • 1. 相关技术及产品介绍
    • 2.动态多通讯通道绑定
    • 3.高效任务调度与异步操作
    • 4.增强对QoS 的支持
    • 5.IDL定义的扩展能力
    • 6.服务容器增强服务管理能力
    • 7.服务发现的增强实现
    • 8.增加对 RTOS 系统的支持
    • 9.增加新的语言支持
    • 10.RESTful 接口的自动生成
    • 11.本章小结
  • 四、总结

一、三个应用领域对SOA的推动

目前而言,SOA 架构在汽车软件中的应用也是刚刚开始。对SOA 在汽车领域的应用很多企业也是在摸索着前进。在这个过程中,有三大需求在推动这SOA的发展:

  • 传统汽车电子电器架构的 SOA 化;
  • 车载娱乐系统(IVI, In-Vehicle Infotainment) 与车联 需要SOA进行更广泛的应用集成;

更完整功能的SOA中间件平台就需要PSE54或POSIX.1 兼容的OS。

  • 典型的以Linux和 QNX为主。目前大多数AP平台实现都是基于Linux 和 QNX;
  • GENIVI 技术栈只支持 Linux,移植到QNX难度不大。
  • 对应SOA 应用程序能够使用的API范围越小,移植性越好,但是对于一些跟传感器强相关的服务和算法,使用平台特定API是不可避免的。
  • 平台实现及应用程序都是运行在POSIX.1兼容OS(主要是 Linux ,其它OS需要移植,难度不大)。

  • GENIVI技术栈中各软件模块依赖

  • Franca接口规范、 AP接口定义与SOME/IP 规范的映射关系如下:
    所有的接口需求都能对应上,因此基于 SOME/IP,GENIVI技术栈可以实现与 Adaptive AutoSAR 互操作。

服务的部署情况如下:

  • 服务1 与服务2 在同一个服务容器进程A 中;
  • 服务3部署在容器进程B中,容器进程B 与 A 是同一个 OS 内的两个进程,
  • 服务4、5 在另一个 OS 中的服务容器进程内

服务1 会触发 Event α , 服务2/3/4 都订阅了该事件并使用各自的 handle_α 方法进行处理。
但是收到事件的方式各不一样:

  • 服务2 的 handle_α直接被容器进程A通API直接调用
  • 服务3 所在容器进程通过共享内存获取事件再调用其方法
  • 服务4 通过 络(SOME/IP)收到事件并处理

在这个例子中,服务1产生的事件是通过三种不同的方式到达接收者。

(2)中间件Runtime 对用户代码的调用
如上文所述,中间件Runtime 至少有三个场景需要对用户代码进行调用:

  • 服务端中间件Runtime收到RPC请求后调用用户代码进行处理
  • 服务端中间件Runtime接收到订阅的事件后调用用户代码进行处理
  • 客户端中间件Runtime收到RPC的响应后回调用户注册的callback函数

我们把上面每一次调用,当作中间件 Runtime 要执行的一个任务。

  • 中间件Runtime 对任务的执行又衍生出了两个问题:“中间件的线程模型” 和 “中间件的任务调度”。

(3)中间件的线程模型

一个对用户(中间件的使用者)友好的中间件系统应该对用户屏蔽复杂的线程管理,用户只需要提供方法函数供中间件Runtime 调用。

  • 中间件Runtime 执行线程有很多设计决策需要考虑。

  • 线程与任务的映射关系。
    a) 如果一个任务到来,就分配一个线程去执行,新建线程或从线程池中取一个空闲线程,没有空闲线程就等待。这样任务的调度就等价与线程的调度。
    b) 维持较少的线程数量(一般是CPU核心数的两倍),每个线程有个待执行的任务队列,新任务到达就放到线程的任务队列的合适位置。

  • 对同一个客户端的RPC请求是否要按照顺序执行。如何保证顺序p>

  • 对同一个客户端的多个RPC请求是否允许在不同的线程执行r> 如果允许,则用户要在自己的代码中对共享资源做加锁处理;
    如果不允许,用户代码就不用考虑共享资源的加锁,编程简单。

  • 在为任务分配执行线程的时候,是否考虑请求来自哪个客户端,比如把来自同一个客户端的执行任务分配到同一个线程。

  • 中间件线程模型的设计对用户编写的难易程度有很大影响。
    (1)中间件自身典型的做法是底层通讯( 络/共享内存)使用异步I/O (典型的反应器模式),同时开启一个线程池,新任务到达就从线程池中获取空闲线程执行。
    (2)这样所有竞争资源互斥的问题都由用户代码解决,任务调度就依赖操作系统的线程调度。
    (3)而优秀的中间件Runtime实现应该给用户提供灵活的线程执行机制,以简化用户代码的实现。

(4)中间件的任务调度

前文说过,对用于自动驾驶中间件来说,应该有更精细的任务调度机制,而不是依赖于操作系统本身的线程调度。

  • 一方面线程数量过多会占用较多内存(每个线程都有自己独立的栈空间,Linux上一般默认设置8MB以上),一方面线程切换的系统开销大,线程调度用户不可控。

  • 解决的办法就是维护独立的多个任务队列,少量线程逐个获取执行任务并执行。将CPU内核态的线程切换转变成了用户态的任务切换。

  • 在自动驾驶软件系统中,前者典型的是发起异步IO操作,后者是中间件Runtime的典型行为。
    这种用户态的任务并发设计根据具体的实现机制有不同的称呼,比如“协程”和 “Actor 模式”都是其体现形式。

  • 这种设计对处理计算任务和I/O任务的并发尤为有用,在自动驾驶软件中,还有一个额外的好处,为在CPU的用户态实现精细的任务调度提供了可能。

  • 自动驾驶系统中的计算任务有几个特点:
    (1)对完成任务的时间有要求
    (2)同一个类型的任务会被反复执行
    (3)排除I/O的影响后,同一个类型的任务的执行时间相对稳定
    比如一个视觉目标检测的算法要求1秒钟能处理 50 帧。
    这个算法的执行是有时间约束的,算法启用后反复执行,没有特别的意外(主要是I/O上),执行实际基本在一个小范围内波动(执行时间的统计方差小)。
    当有很多这样的任务需要被调度时,调度算法可以动态的安排任务执行的顺序,保证最大限度的满足任务的时间要求。

  • 为了得到这样的调度协助,中间件的使用者也需要告诉中间件Runtime他所需要的调度要求,这一点在下一节“IDL的定义扩展”中我们继续阐述。

  • 中间件的API设计上甚至程序语言的特性上也最好能够对这种调度机制提供支持,我们在下文的“程序语言支持”一节中说明。

4.增强对QoS 的支持

QoS 的重要性第二章已经说过,这里不再赘述。

  • SOME/IP协议本身并没有定义QoS相关的支持。
  • 目前对QoS实现最完善的是DDS相关产品。
    作为DDS互操作标准的RTPS(Real-Time Publish-Subscribe)协议也定义了对QoS的支持。

所以目前大多数中间件产品为了实现对QoS的支持,往往采用直接绑定 DDS 作为底层的通讯方式来实现。

  • Adaptive AutoSAR 的“通讯管理”就是采用绑定DDS来提供QoS能力。并在描述服务配置的 ARXML 中指定 QoS需求
  • SOME/IP-SD 协议中包含对QoS能力的描述,也是用于以DDS为通讯通道时,交换服务的QoS能力。

对于GENIVI,也可以通过提供对DDS的绑定来增加对QoS的支持。

  • 但是这种方法是无法对使用SOME/IP的通讯来提供 QoS能力的。
  • 为 SOME/IP通讯提供 QoS的方式也有浅度和深度两种。
    (1)浅度支持指的是:中间件 Runtime 在不对 SOME/IP 协议做扩充的前提下,增加QoS 单方面的有限支持。
    比如在 RPC 请求中增加重试次数的设置,但这只适合“幂等”的请求。
    也可以在RPC请求中增加Deadline时间,但是不能期望对端的服务能够支持,只能在本地Deadline时间超过后给出错误提示。
    也可以在订阅事件时增加FPS要求,同样不能指望事件产生方对这个要求有对应的处理。
    (2)深度的支持要求SOA服务的双方(RPC的请求者和响应者,事件的生产者和消费者)都能够对QoS信息进行处理。
    但是对这些行为的约定并不是SOME/IP协议本身的一部分,如果SOA系统中客户端和服务端采用中间件都是同一个厂商开发的产品,那么是可以做到类似DDS的QoS能力的。

5.IDL定义的扩展能力

IDL 必须具备的基本能力就是定义服务接口API,包括数据类型、RPC方法、发布订阅的事件等。

同样,前面几节也提出了几个可以在 IDL 中进行扩展定义的特性。

  • 接口实现的线程模型需求
  • 接口实现对任务调度的需求
  • 对 QoS 的需求

以图同步/异步调用代码示例中的例子来说,我们可以给 IDL 中定义的plus 方法,指定来自同一个客户的方法在同一个线程中执行,要求完成时间不超过20 毫秒,如果因为通讯通道的原因执行失败,自动重试5次,仍然不能成功执行才 告错误。

  • 代码生成工具可以根据这些信息生成对应的代码,中间件Runtime也能根据这些信息做好任务的线程安排和调度执行。

  • Adaptive AutoSAR的接口定义是以ARXML格式的文件表述的。
    其IDL规范等价于一个定制的XML 规范,定义了可以使用的XML标记集合及语意。
    作为XML的一个方言, ARXML文档主要是供程序读写,使用者直接阅读是比较困难的。所以Adaptive AutoSAR 厂商需要提供可视化工具来给用户使用。
    如要对ARXML进行扩充,可以增加自定义的标记,对应的可视化工具要能够识别和处理。

  • GENIVL的Franca 类似普通的程序语言,可读性很好,可以供用户直接编写,对应的编译器进行解析。
    Franca规范及编译器也提供了好几种方式供用户对规范进行扩充。

6.服务容器增强服务管理能力

服务容器的基本意图是为了实现服务装配机制,让SOA服务获得服务部署与服务管理的灵活性 (这里的容器与Docker 容器没有关系)

  • 同时,如果想实现节描述的SOA服务之间的通讯直接通过“进程内API”调用,也必须通过服务容器的支持。
  • 典型的实现方式图下图的服务容器所示,两个服务共享同一个中间件Runtime,中间件Runtime负责在内部做API的对接以及异步化处理。
  • 一个服务容器进程中也可以有多个中间件Runtime供不同的SOA服务使用,不过这样实现服务之间“进程内API”通讯就难一些。

我们知道GoogleC++编码规范定义了约100页编码规则,AutoSAR CPP14 编码指南更是达到了500页的篇幅。

  • 这些规则中很大一部分都是为了防止内存错误。
  • 程序语言历史上为了解决内存安全问题的典型方法就是使用自动垃圾收集(Java,.Net 等)。垃圾收集瞬间,程序执行被冻结,这在车载软件中是不可接受的。
  • Rust 通过严格的所有权与生命周期管理成功的解决了这个问题。详情请参考拙作《图解Rust 所有权与生命周期》。

除了内存安全,Rust在异步编程方面设计完备的语言级支持,async/await 关键字让发起异步任务极为简便,同时支持完全自定义的任务调度算法。

当然Rust要成为成熟的汽车软件语言,还需要逐步具备符合功能安全要求的工具链体系,需要一定的发展时间,但前景可期。

10.RESTful 接口的自动生成

SOA 服务在IDL定义中已经给出了详细的数据类型定义,方法名称和参数定义,所以直接根据IDL定义生成基于HTTP的RESTful接口是完全可行的。

  • 中间件实现应该允许我们扩展 IDL定义,支持在IDL描述中直接指定为某个接口的某个方法生成 RESTful API。
  • 比如下面的例子中,指定Math接口支持 RESTful 访问:
  • 那么代码生成工具应该能生成代码,让plus 方法能够通过以POST动作访问URL “http://xxx:xx/math/plus”来被调用。
  • Web Server可以直接集成进中间件Runtime或者由服务容器内置Web Server,收到HTTP请求后代为对受管 SOA服务发出请求。具体的实现方式很多,但是自动生成RESTful API可以节省很多开发时间,让应用集成更为便利。

11.本章小结

这一章我们结合SOA架构风格和自动驾驶系统的特殊性,提出了对支持自动驾驶的SOA中间件的一些设想。并讨论了对Adaptive AutoSAR 和 GENIVI 两个技术体系分别分析了进行扩充的方向。其中有一些已经在某些中间件产品中得到实施,更多的还没有得到实践的检验,这也说明适用于自动驾驶的SOA中间件还有很大的发展空间。

四、总结

首先,Adaptive AutoSAR 让我看到浓浓的 CORBA 和 J2EE 的味道:

  • 完善但又复杂的标准体系,但学习曲线陡峭,上手困难;

  • 标准组织定义规范,提供参考实现,各厂商在标准上合作,在产品上竞争,但是产品的价格昂贵。

  • 下图是某 AutoSAR 厂商不同授权方式的阶梯价格示意。最便宜的授权只能用在指定一级供应商开发的单个ECU产品,指定芯片,只能卖给一个OEM。
    其在量产项目中使用的价格(图中的单个阶梯块)要超过500万RMB,如果需要功能安全,再乘以1.5倍。

    自动驾驶软件架构:用于自动驾驶的SOA中间件
  • 在这种价格体系下,如果广大开发商普遍采用AutoSAR,恐怕大家辛苦一场,结果却成了给中间件厂商打工了。

  • AutoSAR 的商业模式对人才的培养也造成了非常大的阻碍。虽然AutoSAR 的标准可以在 上自由下载,但是作为广大程序员,如果想基于AutoSAR开发,你要先加入一家汽车软件公司,寄希望这家公司至少能先花几百万买一个预研版。
    因为AutoSAR的配置非常依赖专用IDE工具,而工具一般要卖10万元一个License。所以一般企业也不会买太多。这也造成了人才市场上AutoSAR技术人才奇缺。

  • 互联 领域有很多开源的技术体系,大浪淘沙之下,能够流行的技术一定是在某些方面有特点,比较方便解决了特定的问题。
    一般来说要么专注于某一个具体的技术点,方便被集成进其它系统架构中;
    要么是一个整体性架构,但是在使用时可以有较大的灵活性,可以整体采用,也可以部分采用,如Spring Framework。Spring Framework也使用了大量J2EE规范里的技术,但是合适的就用,不合适的就另起炉灶。
    所谓合适还是不合适,要看能否更好的解决实际问题。而且这些开源技术可以很容易的获取,人才的培养极为便利,有人用,才能发展的更好。

  • 汽车软件领域对开源软件的采用也越来越多,Linux用于车载操作系统,ROS用于自动驾驶原型开发,各种单一功能的开源软件库更是数不胜数。
    但是比较成熟的开源SOA中间件,尤其是为自动驾驶优化的SOA中间件并不多,做得比较完整的且可用的目前看也就Cyber RT。但是不应该只有一个。
    我对GENIVI感兴趣的主要原因在于它只实现了一个SOA中间件的最小核心:IDL规范,多通讯绑定能力,SOME/IP支持。
    而且架构上每一具体技术点都有办法进行扩充与改进,可以扩展IDL规范,增加通讯绑定,增加新语言支持,改进调度机制等等。可以作为一个产品化的SOA中间件的起点。也可以选择性的对AutoSAR 规范中某些部分进行支持。毕竟SOME/IP也是 AutoSAR规范的一部分。

  • 当我们将互联 领域的常用软件架构、开源技术应用到汽车软件时,也要保持对传统汽车软件严格的开发过程管理,高标准的测试要求保持足够的尊重与敬畏。毕竟,驾驶安全无小事。要在软件敏捷开发、快速迭代与软件安全之间找到合适的平衡点。

总而言之,汽车软件的技术架构、开发方法以及人才结构都在一个快速的变化中,以适应智能 联汽车带来的新的时代。国产的SOA中间件作为重要的汽车基础软件之一,一方面吸取AutoSAR中成熟的标准和技术,保持与AutoSAR的互操作性,同时要在架构的灵活性、成本最优、人才培养上走出自己的路。

  • 参考:自动驾驶软件架构之:中间件与SOA(三)

文章知识点与官方知识档案匹配,可进一步学习相关知识云原生入门技能树基础架构自动编排(Terraform)介绍Terraform8861 人正在系统学习中

声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!

上一篇 2022年3月14日
下一篇 2022年3月14日

相关推荐