“好奇號”火星車和它搭載的軟體(來自Erlang程式設計師的觀點)

類別: IT

我十分好奇,忍不住想推測一下“好奇號”火星車上的軟體究竟是個什麼樣的構造。我們已經知道,好奇號上的軟體大部分都是用C語言寫成的,這些程式碼加起來大概有250萬行。有人可能會感到詫異,這樣複雜的系統怎麼能寫出來而且能讓它好用?下面是來自Erlang程式員的觀點。

首先來些基礎的。“好奇號”火星車使用的是核動力,它能持續的受控的方式提供給火星車能量。這個能量源同時還要負責平時對火星車進行加熱——這是在火星表面極端天氣環境下對火星車的必要保障。

“好奇號”基本上是自主控制的。它傳送一條資訊可能要用幾分鐘到幾小時的時間,你只能在火星上一天裡的有限時間段內給它傳送資訊。“好奇號”自己可以和地球通話,但這條線路速度很慢。它也可以通過圍繞火星飛行的人造衛星進行通訊,把衛星作為上行線路中繼,這樣更快。這種情況表明:火星車必須要能自主行動。我們不能讓一個人坐在地球上的某個椅子裡拿著操縱桿來指導它。

“好奇號”火星車上安裝有兩個完全一樣的計算機。我們注意到美國宇航局正是按照Joe Armstrong(Erlang程式語言的創造人)的話做的:“要想獲得一個可信賴的系統,你需要兩臺計算機”。一個一直處於休眠狀態,一旦另一個由於異常情況當機,它可以隨時受命接管系統。這樣的做法在Erlang語言系統裡、在OpenBSD PF防火牆等其它軟體裡都是很典型的接管方案。“好奇號”上使用的計算機是BAE systems RAD750。處理器是PowerPC ISA,速度非常的快。200百萬赫茲, 150或250奈米 的製造工藝,它工作時對能允許的溫度範圍的表現非常優秀。它是經過抗輻射加固的,能經受相當強的輻射侵襲。記憶體也是抗輻射的。“好奇號”上的計算機裡的每個硬體都不是隨隨便便一個東西能勝任的。

“好奇號”的作業系統使用的是VxWorks。它屬於標準的的微核心系統。保守的估計,它的核心程式碼應該少於1萬行,而且經過了嚴格的測試。也就是說,這個核心接近零bug。它的一個主要特徵就是隔離。火星車上的各個模組都是相互隔離的。有些子系統對火星車的生命起著至關重要的作用,而另外一些只是用於科學觀察的裝置。所以,我們可以肯定這樣一個事實,“好奇號”上的250萬行程式碼中,只有一部分程式碼是深度測試杜絕了bug的。車上的有些程式並不是生命必須的。

美國宇航局使用了各種辦法來確保程式碼質量。例如,遞迴呼叫是要求避免的,這是這因為C語言編譯器不能保證遞迴堆疊不被撐破。迴圈要確保有終止點,這通過一個靜態分析器來發現這些問題。所有的記憶體使用都幾乎是靜態分配的,這樣避免了突然的記憶體收集產生的混亂和不可預知的效能問題。我們還可以發現訊息傳遞(Message Passing)作為子系統間的訊息傳遞方式在火星車是被當作了首選。不存在互斥,不存在軟體事務性記憶體。同樣,隔離概念也是編碼指導原則上的一部分。通過對記憶體進行保護和資料的單一歸屬關係,子系統之間就很難影響對方。Erlang程式員都很習慣這樣的做法。

“探路者”號火星車

當年的“探路者”號火星車的架構設計事實上也跟Erlang語言系統的理念相似。它有用於傳遞訊息的“元件”。元件只在接收訊息時才等待,傳送訊息的都是無返回值的函式。它們接受訊息採用的是單事件迴圈,這跟Erlang語言中的 gen_server 工作方式很相似。不同的模組間通過某種協議傳遞訊息進行通訊,你可以訪問其它模組使用的記憶體,但按照JPL編碼指導原則,這種做法是要避免的。這跟Erlang語言有所不同,Erlang語言完全禁止這樣操作。火星探測漫遊者(勇氣號和機遇號)擁有更多的元件,但軟體基礎上相同的。“好奇號”也不例外。它本質上是在老的軟體上改造出來的。系統中的執行緒數有大幾百個,這完美的和一個類似的如此規模的Erlang語言系統中的執行緒數相匹配。

機遇號火星車

在“好奇號”上,他們增加了“元件”的概念,元件由一組組的模組構成,以此用來控制複雜度。因為有兩臺計算機做冗餘,很多子系統為了系統的穩固也是冗餘的,元件的概念也是處理這些情況需要的。有趣的是,Erlang語言的設計者也看到了這一點,只是在Erlang裡被叫做Applictions。

對函式恆量的校驗。輸入引數必須要滿足前置條件。後置條件約束返回值。各種恆量必須滿足這些條件。Erlang程式員熟悉這種做法。有趣的是,“好奇號”上的每個函式的長度限制在60行以內,這樣它們可以被列印到單張紙上。Erlang程式員也喜歡簡短的函式體,但沒有這種限制。但都是為了讓程式碼簡單。讓程式碼易於理解。

勇氣號火星車

還有另外一個有趣的事情,在過去,有個火星車發生過優先順序顛倒的問題。他們在除錯控制檯裡向火星車注入了一段糾正資訊挽救了火星車。這也跟Erlang語言系統裡經常使用的方法相似。我們可以對執行中的系統進行修改,隨時對系統進行升級和改造。我們對執行中的系統進行監控,確保它的執行狀態跟我們期望的一樣。這種對系統進行熱修復的能力非常的有用。當然,這種開發是配合了大量的跟蹤和分析——例如使用Erlang QuickCheck/PropEr,錯誤記錄以及跟蹤工具。

很明顯,Erlang語言系統的很多特徵都跟火星車上的系統吻合。但我並不認為這是巧合。各種軟體有自己不同的屬性特徵——火星車屬於硬實時(hard realtime)環境,Erlang語言系統是軟實時環境。但大體上,寫出健壯系統的條件是你需要隔離系統中的各個部分。這值得思考,看起來這種方式好用。這些對於高可靠性系統來說都是的重要的特徵。也許比靜態型別校驗還要重要。

總結來看,對於火星車上的所有程式碼,我們也許並不必保障所有程式碼都達到最高階別的安全。我們可以把不同的模組進行隔離測試,對它們實施不同等級的正確性檢查。換句話說,我可以通過精心的設計來控制錯誤和管理風險。因此,對於某些模組,我們可以承認它們可能存在某些錯誤。如果上行通訊中繼壞了,我們可以重啟機器,這樣來恢復它。如果這樣不行,我們還有一個冗餘的上行通訊通道直接和地球通訊,只是速度慢些——但可以替代另外一個通道。這種架構意味著只有多個元件同時失敗時才能導致任務無法完成。模組出錯,重啟,恢復,然後就可繼續拍攝圖片。這種設計的基本原理是非常可靠的,也許需要根據情況做一些小的調整。畢竟它是經過了另外3個火星車的嚴格考驗上發展出來的。

跟Erlang語言理念不相同的部分跟所對應的硬實時和軟實時環境有關。在Erlang語言系統中我們可以暫緩服務。雖然不好,但可以這麼幹。在火星車上,這會成為災難。在飛行控制系統中尤其是這樣。如果火箭啟動晚了,你的麻煩就大了。這就是為什麼“好奇號”上要使用靜態分配記憶體和固定堆疊大小,而不是使用動態分配的原因。這同樣也是他們不喜歡遞迴的原因。而在Erlang語言系統裡,我們不鼓勵通過手動管理記憶體。我們對tail呼叫做了革命性的優化,所以我們可以放心的使用它。

長話短說——“好奇號”火星車的軟體在某些特徵上跟Erlang語言系統在架構上非常是相似。這些特徵是一個健壯的軟體系統的基本特徵嗎?

“好奇號”火星車和它搭載的軟體(來自Erlang程式設計師的觀點)原文請看這裡