隨著行業的 SOA 理念大火,帶著一系列的解讀和思考觀點橫行于世,筆者大多仔細研讀過,雖然增加了很多碎片化知識和曾經的盲點,但也同樣帶來了更多的疑惑,本文撰寫初衷是基于車廠的角度思考,如何在現有整車架構和軟件資產下,進行 SOA 的設計開發,并從工具鏈和操作方法上給出案例。
1. 分布式 ECU-基于信號的架構設計
現在我們來看,在域控制器開發階段,針對傳統車廠,在分布式 ECU,或區域控制器集成,已經有了深厚的架構開發和經驗積累的前提條件下,如何轉型并進行中央域控的服務設計。
本章節描述現階段,面對分布式 ECU,如何進行基于信號的整車電子電器架構開發。如下為介紹 MBSE 理論的較為經典文章。 服務設計相對軟件架構設計影響較大,接下來著重分析 SOA 服務設計。
2. 中央域控架構-基于 SOA 服務設計
為了后續方便理解,我們大致把國內的整車電子電器架構分為三個階段:
1.0 架構: 以逆向分析為主,整合現階段市面上供應商的零部件,實現整車功能(典型代表 比亞迪 F3)
2.0 架構: 以正向開發為主,融合國內外先進經驗技術,進行整車多車型的架構開發(典型代表 吉利 CMA 架構)
3.0 架構:硬件上從分布式 ECU 變為整車域控架構,軟件上由基于 signal 變為 SOA ,能夠大幅降低車輛上 ECU 數量,軟件迭代速度也由質的飛躍(典型代表 特斯拉)
2.1. 服務設計依據
總體采用自上而下與自下而上想結合的形式進行服務定義。
針對網絡上全拓補硬件,進行自下而上設計,將其分為傳感器,執行器,與單功能 ECU 三類,分別針對硬件進行設備抽象 api 設定,與原子服務抽象。
針對整車功能定義 FR 與 FDR ,進行自上而下設計,首先使用面向對象的思維進行整車的類抽象,然后設計類的方法與屬性,其中屬性盡量與 原子服務進行映射,方法需要使用一個或多個原子服務進行實現
最終進行原子服務,與整車類的屬性與方法進行映射,找出無法實現的類,以及沒有使用到的原子服務,此部分進行服務代理設計,及使用傳統 SWC 軟件模塊實現部分功能,然后代理成組合服務形式,參與整車架構設計。
?
2.2. SOA 設計區別
3.0 架構全面采用 SOA(service-oriented Architecture)設計思想進行構建,上一代 2.0 架構采用的是 POP(procedure oriented programming)面向過程的設計思想,需要注意的是,在 SOA 設計中,自上而下的設計方法中引入了 OOP(object oriented programming)面向對象的抽象與封裝概念,這是為了在 2.0 現有架構基礎上,能夠繼承原有 FR,FDR,LC,然后進行迭代開發。
也就是說通過 Class 的抽象,在原有 LC 一層新添加了類圖的設計,通過抽象的類進行用例設計進行功能鏈路實現。后續進行服務化設計,只要滿足類中的屬性和方法能夠實現即可,而不必去關心設計的服務如何支撐整個子系統及功能鏈路的實現。
POP 面向過程設計
在 2.0 架構中,首先要進行 Composition 功能組合的劃分,然后在進行 Component 功能組件的劃分,每個組件都有相應的輸入和輸出信號,依據這些來實現高內聚,低耦合的功能點實現,設計好組件/組合之后,然后進行模塊間接口信號的設計,每個模塊平均有 20 個左后的輸入和輸出信號
SOA 面向服務設計
在 3.0 架構中,首先要進行服務的劃分和設計,每個服務是松耦合的,也就是分治的設計理念,及服務里包含的方法、event、field 具備高扇入,合理的扇出,而服務所抽象的數據要與處理的業務邏輯、流程、功能實現三方解耦,所設計的基礎服務也要與操作系統解耦。
對比 2.0 中的設計,可以類似的理解為 2.0 先設計軟件模塊,然后設計信號接口,而 3.0 soa 后先設計服務接口(此接口不僅包含類似信號的 event,還包含類似函數的 method 方法),有了服務之后,在設計哪些模塊提供這些服務,哪些模塊訂閱服務。
需要注意,SOA 后里的軟件模塊需要嚴格的區分 server 與 client,也就是一個模塊要不就是提供某個或多個服務,要不就是訂閱了一個或多個服務,不存在既訂閱了一些服務又提供了一些服務的情況,這與 2.0 架構中的 swc 軟件模塊既有輸入又有輸出完全不一樣。
OOP 面向對象設計
在 3.0 架構中,需要借助面向對象的設計方法來輔助支撐,也就是依托現有 2.0 架構,不進行大范圍重構的前提條件下,使用類抽象出所有 LC 模塊,并且通過設計不同類的用例圖來實現原 LC 處理的功能。
?
2.0 架構上 MBSE 設計圖上 LC 映射實現 ?
3.0 架構上 MBSE 設計圖上 LC 映射實現
2.3. 接口命名規范
在進行 SOA 服務設計時,需要遵循如下命名規范
2.3.1. 基礎規范
盡量采用單詞全稱,名稱過長后才使用縮寫
名稱不包含特殊字符?,./~
名稱如果過長,需要參考常用單詞縮寫表中內容進行縮寫
不同層級的各類名稱不能重復
命名中不能使用如下系統關鍵字:
skeleton
proxy
internal
resources
method
event
field
input/output
amsr
ara
com
someip
base
vac
std
serialization
2.3.2. Service Instance 服務實例
服務實例及指代定義的服務實現,后文若單獨寫服務,則意為服務實例
服務名采用首字母大寫,全英文名稱
服務名不能有下劃線
服務名后綴需要以?Srv?結尾
eg. LedControlSrv
2.3.3. Service Interface 服務接口
SOA 平臺上服務之間通信接口有 Event、Method 和 Field 三種形式, ServiceInterface 用于定義 Event/Method/Field 消息類型和具體的命名空間,與具體的通信協議無關。
服務接口名采用首字母大寫,全英文名稱
服務接口名不能有下劃線
服務接口名需要以?SrvIf?結尾
eg. LedControlSrvIf
2.3.4. Event
Event 接口表示實際傳輸的數據,以數據為操作對象,只要能夠清晰的表達數據的含義即可,命名規范遵循基礎規范,后綴要以?Evt?結尾。 eg. CurrentVleEvt : 電流值 Event 消息傳遞方式如下圖所示,為服務端主動向客戶端發送,并且會觸發客戶端的 callback 函數進行數據處理。 ?
2.3.5. Method
Mehtod 接口表示某種控制,通訊方式采用 RPC 遠程調用,通常有動詞行為,比如控制,狀態查詢,傳輸,注冊,設置等。其中 Method 又分為 F&F,與 R&R 兩類,FF 為單次調用,不需要反饋,RR 為 request resoponse,需要反饋。
請求-響應(request/response): R&R
請求-響應流(request/stream)
發后不管(fire-and-forget) : F&F
通道模式(channel)
整體設計依據遵循?CURD/REST?這類成熟的互聯網通用接口概念 CURD
REST
接口名稱需要表達清楚該方法的含義,推薦使用動名詞進行命名,采用駝峰命名規范,基于如上 CURD/REST 參考,命名要以后綴?Mtd?作為結束,設計如下基礎命名范式:
get 獲取狀態
set 設置狀態
report 傳遞信息
judge 判斷事件,返回 boolean
create 創建線程/進程/動態服務/文件/事件 等
delete 刪除線程/進程/文件 等
eg. setSoundOnMtd : 鳴響喇叭
judgeVehMovingMtd : 判斷車輛是否移動
getCarCfgMtd : 獲取 car config 值
reportComponentStsMtd : 上報 component 狀態信息
createXTaskUsrLightShowSrvMtd : 創建用戶自定義的燈光 show 服務
deleteDebugClass0MsgMtd : 刪除 debug 等級為 0 的所有 msg 調試文件 Method 消息傳遞方式如下圖所示,為客戶端主動向服務端請求,可以設定是否有服務端的返回值。
2.3.6. Field
Field 表示一種屬性,通常指狀態值或某種信息,名稱應該清楚的表達該屬性的含義。 Field 包含如下三類信息:
getter : 只讀接口,原型為 method,獲取服務端信息
notifier : 只讀接口,原型為 event,接收服務端的數據
setter : 寫入接口,原型為 method,設置/修改服務端相關信息
eg. VehMoveFld : 車輛移動控制 Field 消息傳遞方式如下圖所示
3. 服務設計方法
針對大部分 OEM,需要在現有整車架構上進行服務設計升級,也就是已有 base 的 LC 需求,和工程級的軟件 swc,需要依據這兩類已有資產,使用 OOP 面向對象的抽象與封裝手段,進行 SOA 服務化重構。 本章節以車身控制器中?危險報警?軟件模塊為例,說明如何在已有 LC 需求和軟件模塊前提下,使用 gitee,進行 SOA 設計。
需要注意的是,在設計服務接口時,要清楚的知道不同接口的實際特性和性能消耗。Event 為 服務端主動向客戶端 發送請求,而 Method 恰好相反,為 客戶端主動向服務端 進行請求調用。根據如上接口描述,整體服務設計遵循如下方案要點。
原 2.0 平臺中信號盡量保留,作為 Event 接口類型進行預留
服務設計包括 類抽象-服務接口設計-服務實例設計-設計具體的進程/線程 運行此服務實例
每個抽象好的類,對應一個服務接口 : XX_Class -> XX_SrvIf
類中的屬性對應 Event 接口類型 XX_Class::value -> XX_SrvIf-valueEvt
類中的方法對應 Method 接口類型 XX_Class::fuction -> XX_SrvIf-valueMtd
盡量不要設計 Field 接口
每個服務接口由一個具體的服務進行實例化 : XX_SrvIf -> XX_Srv
每個實例化的服務,都要設計哪個進程/線程/軟件模塊/ECU 來提供,哪些 App 會訂閱
App 使用/設定服務里的數據/功能,需要通過 CM 通訊管理進行服務的訂閱
實例化的服務之間,數據/功能 傳遞,則直接調用相互暴露的 api,可以不用 CM 參與(即組合服務和原子服務的關系)
App 之間不能直接進行數據傳輸,需要調用專有的服務進行數據傳遞(即服務代理模塊)
3.1. 需求分析
示例軟件模塊主要實現危險警報功能,在整車條件允許的情況下,如果按下手機 app 上的警報按鈕,則會觸發車輛進行聲光報警。
需要注意?針對 VFC/PNC 相關軟件邏輯,雖然在 3.0 架構上已經不復存在,但是需要保留功能分區劃域的思想,也就是針對不同場景需要觸發不同的軟件組件來執行完成,針對不同的 PNC,在 3.0 架構上可以作為 VLAN 劃分的設計參考。 使用 gitee 進行需求編寫,與原 LC 中需求進行追溯
3.2. 類的抽象和封裝
使用 OOP 手段,根據需求和已有的軟件模塊,進行類的抽象,并將有可能被多次調用的軟件邏輯進行類方法的封裝,后續多次執行的代碼邏輯,僅在實例化的類中執行一次即可。
類抽象,將整車從多個角度抽象成不同的類,每個類都可以映射成一個 service 的實體,不同的軟件模塊調用相同邏輯時,可以直接訂閱此 service,使用 service 中的 method、event、field。
類方法封裝,將接口進行泛化,封裝成通用類的方法,達到松耦合的效果
類圖:
? ?
時序圖:
?
3.3. 服務設計
上一章推導出,所設計的類就是一個需要實現服務,根據此原則,在 gitee 中進行服務設計。 服務設計包含如下步驟和要素:
服務接口設計(method/event/field)
接口變量設計(method 的入參出參及數據類型,event 變量名及數據類型)
服務實例設計(發布者,服務 ID 等信息)
3.3.1. 數據類型設計
在?Gitee-數據類型?中進行數據類型設計 ?
3.3.2. 服務接口設計
在?Gitee-Service 接口?中進行 service 接口設計 ?
3.3.3. 服務實例設計
在?Gitee-Service 實例?中進行服務實例設計 ?
3.3.4. 配置文件導出以及代碼框架生成
通過 gitee 能夠導出所有服務 list 的 csv 文件,基于此開發工具進行 arxml 文件和代碼框架的轉換生成,最終進行基于 SOA 服務化的軟件開發。 代碼框架可以參考筆者之前的回答。
4. 小結
針對已有歷史軟件資產的廠商,進行 SOA 架構升級的方法大致如上,此處借用了 gitee 企業版輔助進行架構設計,也希望大家意識到,軟件定義汽車,不僅僅是軟件產品,甚至整車研發的工具鏈和開發流程也都會慢慢靠向軟件開發的生態工具鏈,抱殘守缺,是注定要被時代淘汰的,此處諾基亞和柯達會深有感觸。?
審核編輯:劉清
評論