周末讀了兩篇論文"On Designing and Deploying Internet-Scale Services"和Joe Armstrong的論文"面對軟體錯誤構建可靠的分布式系統",這兩篇論文實戰內容相當多,整理筆記於此,備忘. On Designing and Deploying Internet-Scale Services [HTML]英文版"Making reliable distributed systems in the presence of sodware errors" [PDF] 中文版 《面向軟體錯誤構建可靠的分布式系統》 [PDF] 架構的定義
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.軟體構造指南——我們如何來規劃一個系統?我們需要一個明確的軟體構造指南集.我們的系統將由一個程式員團隊來編寫和維護——所以對所有的程式員和系統設計者來說,理解系統的架構和它的潛在哲學是很重要的.從實用性的角度來講,這些知識以軟體構造指南的方式表現出來更便於維持.一個完整的軟體構造指南集包括編程規則集,例子程式和培訓資料等等. 筆記:這個還是深有感觸的,現在有一些項目比如PlayStationSuite SDK把C#當作指令碼使用,但是你會發現在這些項目裡面雖然同是C#語言但無論是類庫組織還是命名規範都是有自己的規則和風格的. 4.預先定義好的組件——以“從一組預先定義好的組件中選擇”的方式進行設計遠比“從頭設計”的方式要來得容易.Erlang 的OTP庫包含了一個完整的現成組件集(稱之 behaviour 庫),一些常用的系統都可以使用這些組件構建起來.例如 gen_server 這種 behaviour 就可以用來構建client-server 系統,gen_event 這種 behaviour 可以用來構建基於事件(event-based)的程式. 筆記:學習語言,其中一個重要的部分就是掌握這個語言所提供的類庫;一方面是不重複造輪子,能夠直接使用高品質類庫;另一方面從類庫中可以學習這種語言的編程風格.
5.描述方式——我們如何描述某一組件的介面?我們如何描述系統中兩個組件之間的通訊協定?我們如何來描述系統中的靜態和動態結構?為了回答這些問題,我們將介紹一些專門的符號.其中一些用來描述程式的API,而其他的則用來描述協議和系統結構。
筆記:學習一種新知識,其中的門檻一方面是來自於概念,另一方面就是來自於符號系統;這兩種都是對資訊進行了簡化,背後包含了較大的資訊量,沒有額外的資訊支援難以理解.在最初接觸一種新知識的時候,由於不瞭解這個領域的術語和概念,我們甚至都不能正確的描述遇到的問題.
6.配置方式——我們如何來啟動,停止和配置我們的系統?我們可以在系統工作過程中進行重配置嗎?
筆記:編程完成業務功能並沒有萬事大吉,還要考慮到配置,部署,這些問題的考慮時機甚至在設計之初就要考慮;針對不同的硬體裝置,配置也有所不同;考慮到日常維護,還要準備一些給營運使用的指令碼. Erlang 故障隔離 為了構建出在軟體存在錯誤的時候仍具有合理行為的可容錯軟體系統,Erlang的解決問題的思路是:1.任務層次化,儘力完成頂層任務2.如果完成任務過程中出現錯誤,如果無法糾正錯誤,就立即取消重新啟動新的任務 這其中最本質的問題就是故障隔離,作業系統通過進程的概念實現了故障隔離,進程提供了保護地區,一個進程出錯,不會影響到其他進程的運行.不同程式員編寫的不同應用程式分別跑在不同的進程中; 一個應用程式的錯誤不會對系統中啟動並執行其他應用程式產生副作用.這種選擇當然滿足了初步的要求.然而因為所有進程使用同一片 CPU,同一塊實體記憶體,所以當不同進程爭搶 CPU 資源或者使用大量記憶體的時候,還是可能對系統中的其他進程產生負面影響. 進程間的相互衝突程度取決於作業系統的設計特性. Erlang進程和並發編程是語言的一部分,而不是由宿主作業系統提供的,Erlang應用程式是通過大量互相通訊的並行進程構建起來的,這樣做的原因是:
架構基礎設施——我們可以用一組相互連信的進程組織起我們的系統,並定義出進程間訊息傳遞的通道,我們就可以很方便地把系統劃分成定義良好的子組件,並可以對這些子組件進行單獨實現和測試.
巨大的潛在效率——設計成以許多獨立的並行進程來實現的系統,可以很方便地實現在多處理器上,或者運行在分布式的處理器網路上. 注意這種效率的提升只是潛在的,只有當應用程式可以被分解成許多真正獨立的任務時,才能產生實效.如果任務之間有很強的資料依賴,這種提升往往是不可能的. 故障隔離——沒有共用資料的並發進程提供了一種強大的故障隔離方法.一個並發進程的軟體錯誤不會影響到系統中其他進程的運行. 在並發的這三種用法中,前兩條並不是其本質特性,可以由某種內建的發送器通過在進程間提供不同的偽並行(pseudo-parallel)時分方式來獲得.第三個特性對於編寫可容錯系統的軟體來說,則是本質性的.每一項獨立的活動都在一個完全獨立的進程中來執行.這些進程沒有共用資料,進程之間只通過訊息傳遞的方式進行通訊,這就限制了軟體錯誤造成的影響.
一旦進程之間共用有任何公用資源,譬如記憶體,或指向記憶體的指標,或互斥體等等,一個進程中的一個軟體錯誤破壞共用資源的可能性就存在.因為消除大型軟體系統中的這類軟體錯誤仍然是一個未解的難題,所以我認為構建大型的可靠系統的唯一現實的方法就是把系統分解成許多獨立的並行進程, 並為監控和重啟這些進程提供一些機制, 從某種意義上講,作業系統提供了“被程式設計語言設計者遺忘了的東西”.但是在 Erlang 這樣的程式設計語言中, 作業系統是幾乎不需要的.OS真正提供給 Erlang的只是一些裝置驅動程式,而 OS提供的諸如進程,訊息傳遞,調度,記憶體管理等等機制都不需要. 面向並發程式設計語言COPL COPL編寫這樣的並發程式相當容易,它有三個步驟:
1.從真實世界中的活動中識別出真正的並發活動
2.識別出並發活動之間的所有訊息通道
3.寫下能夠在不同的訊息通道中流通的所有訊息 值得注意的是,COPL 提供的並發性一定是真正的並發性,因此以進程的形式存在的對象都是真正並發的,進程間的訊息傳遞也是真正的非同步訊息,而不像許多物件導向語言中一樣是通過遠端程序呼叫(remote procedure call)來冒充.
Erlang世界觀概覽
• 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.
思維導圖
Erlang
View more documents from ligaoren