天天看點

[Erlang 0060] Joe Armstrong 論文《面向軟體錯誤建構可靠的分布式系統》筆記架構的定義Erlang 故障隔離面向并發程式設計語言COPLErlang世界觀概覽

周末讀了兩篇論文"On Designing and Deploying Internet-Scale Services"和Joe Armstrong的論文"面對軟體錯誤建構可靠的分布式系統",這兩篇論文實戰内容相當多,整理筆記于此,備忘.

  An architecture is the set of significant decisions about the organization of a sodware system, the selection of the structural elements and their interfaces by which the system is composed, together with their behaviour as specified in the collaborations among those elements, the composition of these structural and behavioural elements into progressively larger subsystems, and the architectural style that guides this organization—these elements and their interfaces, their collaborations, and their composition.                                                                                                         Booch, Rumbaugh, and Jacobson [19]

  在我接觸到的架構定義中,Joe Armstrong論文中提到的定義相當務實,相當具有實踐指導價值;首先和Martin Fowler等人對架構的共識是架構是一組系統組織方式的重要決策;決策包含系統有哪些構成元素,元素之間的接口,元素之間的協作方式;是一種把這些結構和行為元素建構為更大子系統的的合成方式;也是一種建構風格,在其指導下把元素,元素接口,元素協作和合成方式組織起來.

  把架構的抽象概念映射到具體實踐過程,可以從六個具體方面去考量,這時候我們已經從萬裡高空下降到陸地上了.

1.問題領域——我們的架構是為解決什麼類型的問題而設計的?軟體架構一定不是通用的,而是為解決某一類特定問題而設計的.缺少了關于用來解決哪類問題的描述的架構是不完整的.

  筆記:同樣的,缺少上下文描述的程式設計語言比較也隻是一場關公戰秦瓊的亂鬥而已;遇到過一些"技術牛人"身居要位,硬是把之前項目的設計方案強制應用在目前的項目上,這都不是偷懶那樣簡單,而是缺少對項目負責的專業态度.而更為糟糕的是一旦項目做失敗了,就甩手走人,留下一個爛尾的工程留給團隊;對團隊的傷害,需要更長時間進行修複.

2.哲學——  軟體構造方法背後的原理是什麼?架構的核心思想是什麼?

  筆記:在解決了問題或者完成了一個設計之後,我們一定要回顧一下解決問題的思路和設計的原理;具體的技術細節可能無法服用,但是思維方式和設計方法都是可以複用的.在閱讀開源項目時,學習語言技巧是一方面,更為重要的是看這個項目是解決了什麼問題,如何解決的,整體思路是怎樣的.

3.軟體構造指南——我們如何來規劃一個系統?我們需要一個明确的軟體構造指南集.我們的系統将由一個程式員團隊來編寫和維護——是以對所有的程式員和系統設計者來說,了解系統的架構和它的潛在哲學是很重要的.從實用性的角度來講,這些知識以軟體構造指南的方式表現出來更便于維持.一個完整的軟體構造指南集包括程式設計規則集,例子程式和教育訓練資料等等.

 筆記:這個還是深有感觸的,現在有一些項目比如PlayStation®Suite SDK把C#當作腳本使用,但是你會發現在這些項目裡面雖然同是C#語言但無論是類庫組織還是命名規範都是有自己的規則和風格的.

4.預先定義好的部件——以“從一組預先定義好的部件中選擇”的方式進行設計遠比“從頭設計”的方式要來得容易.Erlang 的OTP庫包含了一個完整的現成部件集(稱之 behaviour 庫),一些常用的系統都可以使用這些部件建構起來.例如 gen_server 這種 behaviour 就可以用來建構client-server 系統,gen_event 這種 behaviour 可以用來建構基于事件(event-based)的程式. 

  筆記:學習語言,其中一個重要的部分就是掌握這個語言所提供的類庫;一方面是不重複造輪子,能夠直接使用高品質類庫;另一方面從類庫中可以學習這種語言的程式設計風格.

5.描述方式——我們如何描述某一部件的接口?我們如何描述系統中兩個部件之間的通信協定?我們如何來描述系統中的靜态和動态結構?為了回答這些問題,我們将介紹一些專門的符号.其中一些用來描述程式的API,而其他的則用來描述協定和系統結構。 

  筆記:學習一種新知識,其中的門檻一方面是來自于概念,另一方面就是來自于符号系統;這兩種都是對資訊進行了簡化,背後包含了較大的資訊量,沒有額外的資訊支援難以了解.在最初接觸一種新知識的時候,由于不了解這個領域的術語和概念,我們甚至都不能正确的描述遇到的問題.

6.配置方式——我們如何來啟動,停止和配置我們的系統?我們可以在系統工作過程中進行重配置嗎?

  筆記:程式設計完成業務功能并沒有萬事大吉,還要考慮到配置,部署,這些問題的考慮時機甚至在設計之初就要考慮;針對不同的硬體裝置,配置也有所不同;考慮到日常維護,還要準備一些給運維使用的腳本.

   為了建構出在軟體存在錯誤的時候仍具有合理行為的可容錯軟體系統,Erlang的解決問題的思路是:

1.任務階層化,盡力完成頂層任務

2.如果完成任務過程中出現錯誤,如果無法糾正錯誤,就立即取消重新啟動新的任務

   這其中最本質的問題就是故障隔離,作業系統通過程序的概念實作了故障隔離,程序提供了保護區域,一個程序出錯,不會影響到其他程序的運作.不同程式員編寫的不同應用程式分别跑在不同的程序中; 一個應用程式的錯誤不會對系統中運作的其他應用程式産生副作用.這種選擇當然滿足了初步的要求.然而因為所有程序使用同一片 CPU,同一塊實體記憶體,是以當不同程序争搶 CPU 資源或者使用大量記憶體的時候,還是可能對系統中的其他程序産生負面影響. 程序間的互相沖突程度取決于作業系統的設計特性.

  Erlang程序和并發程式設計是語言的一部分,而不是由宿主作業系統提供的,Erlang應用程式是通過大量互相通信的并行程序建構起來的,這樣做的原因是:

  架構基礎設施——我們可以用一組互相通信的程序組織起我們的系統,并定義出程序間消息傳遞的通道,我們就可以很友善地把系統劃分成定義良好的子部件,并可以對這些子部件進行單獨實作和測試.

  巨大的潛在效率——設計成以許多獨立的并行程序來實作的系統,可以很友善地實作在多處理器上,或者運作在分布式的處理器網絡上. 注意這種效率的提升隻是潛在的,隻有當應用程式可以被分解成許多真正獨立的任務時,才能産生實效.如果任務之間有很強的資料依賴,這種提升往往是不可能的.

  故障隔離——沒有共享資料的并發程序提供了一種強大的故障隔離方法.一個并發程序的軟體錯誤不會影響到系統中其他程序的運作.

     在并發的這三種用法中,前兩條并不是其本質特性,可以由某種内置的排程程式通過在程序間提供不同的僞并行(pseudo-parallel)時分方式來獲得.第三個特性對于編寫可容錯系統的軟體來說,則是本質性的.每一項獨立的活動都在一個完全獨立的程序中來執行.這些程序沒有共享資料,程序之間隻通過消息傳遞的方式進行通信,這就限制了軟體錯誤造成的影響. 

    一旦程序之間共享有任何公共資源,譬如記憶體,或指向記憶體的指針,或互斥體等等,一個程序中的一個軟體錯誤破壞共享資源的可能性就存在.因為消除大型軟體系統中的這類軟體錯誤仍然是一個未解的難題,是以我認為建構大型的可靠系統的唯一現實的方法就是把系統分解成許多獨立的并行程序, 并為監控和重新開機這些程序提供一些機制, 

  從某種意義上講,作業系統提供了“被程式設計語言設計者遺忘了的東西”.但是在 Erlang 這樣的程式設計語言中, 作業系統是幾乎不需要的.OS真正提供給 Erlang的隻是一些裝置驅動程式,而 OS提供的諸如程序,消息傳遞,排程,記憶體管理等等機制都不需要. 

  COPL編寫這樣的并發程式相當容易,它有三個步驟:

1.從真實世界中的活動中識别出真正的并發活動 

2.識别出并發活動之間的所有消息通道

3.寫下能夠在不同的消息通道中流通的所有消息

   值得注意的是,COPL 提供的并發性一定是真正的并發性,是以以程序的形式存在的對象都是真正并發的,程序間的消息傳遞也是真正的異步消息,而不像許多面向對象語言中一樣是通過遠端過程調用(remote procedure call)來冒充.

• Everything is a process.

• Processes are strongly isolated.

• Process creation and destruction is a lightweight operation.

• Message passing is the only way for processes to interact.

• Processes have unique names.

• If you know the name of a process you can send it a message.

• Processes share no resources.

• Error handling is non-local.

• Processes do what they are supposed to do or fail. 

思維導圖

<a href="http://www.slideshare.net/ligaoren/erlang-12993720" target="_blank">Erlang</a>

繼續閱讀