2014/1/20

Why erlang? What can erlang do for us?

Erlang 是一種通用的平行導向程式語言,老爸是Joe Armstrong,想開發出一個共時、分散式、多核心、容錯的系統,Erlang 是個絕佳的選擇。

C10K Problem

著名的 The C10K problem 告訴我們,在高速網路與便宜的硬體的帶動下,如果一台機器能服務更多使用者,就代表著每一個客戶端消耗掉的運算資源更少,成本更低。

要解決這個問題,最重要的是要處理網路IO與硬碟IO,這些方法的區隔與不同之處如下:

  • 決定要不要在 single thread 中處理多個 I/O calls,要怎麼做?

    1. 不使用single thread處理多個 I/O 的方法,還是沿用 blocking/synchronous calls 並持續以 multiple threads or processes 來處理 concurrency 的問題

    2. 使用 nonblocking calls 啟動 I/O (e.g. write() on a socket set to O_NONBLOCK),並以有資料需要讀取的通知 readiness notification 來告訴該 channel 要啟動一輪新的 I/O (e.g. poll() or /dev/poll) 這種方法只適合 network I/O 不適合 disk I/O

    3. 使用 asynchronous calls 啟動 I/O (e.g. aio_write()),處理完成後發出通知(例如 signals or completion ports),這種方法同時適合 network 與 disk I/O。

  • 如何撰寫處理每個客戶端的程式碼?

    1. 每一個 client 使用一個 process (這是Unix 自 1980年開始,就一直採用的方法)

    2. 一個 OS-level thread 服務多個 clients,每一個 client 透過以下某個方式控制

      2.1 一個 user-level thread (例如 GNU state threads, classic Java with green threads)

      2.2 a state machine (a bit esoteric, but popular in some circles; my favorite)

      2.3 a continuation (a bit esoteric, but popular in some circles)

    3. 一個客戶端使用一個 OS-level thread (e.g. classic Java with native threads)

    4. 一個 active client 使用一個 OS-level thread (e.g. Tomcat with apache front end; NT completion ports; thread pools)

  • 不使用標準 OS services,直接將程式碼放進 kernel (e.g. in a custom driver, kernel module, or VxD)

下面的五種是最常見的組合方式

  1. 一個 thread 服務多個客戶端,使用 nonblocking I/O 和 level-triggered readiness notification
  2. 一個 thread 服務多個客戶端,使用 nonblocking I/O 和 readiness change notification
  3. 一個 thread 服務多個客戶端,使用 asynchronous I/O
  4. 一個 thread 服務一個客戶端,使用 blocking I/O
  5. 把程式碼編譯進 kernel

Currency in Erlang

共時導向編程 提到「共時」有兩種不同的作法,分別是「共享狀態共時」,與「訊息傳遞共時」。大多數的主流語言(Java、C#、C++)採用「共享狀態共時」的設計,但 Erlang 採用「訊息傳遞共時」。

在Erlang中沒有共享狀態,唯一一種交換資料的方式,是透過「非同步」訊息傳遞。Erlang的共時單位稱為行程(process),但其實是類似執行緒的地位,而不是真正的OS process。Erlang的行程之間彼此透過訊息傳遞方式來進行溝通,每個行程都可以在不同的核心,不同的CPU,甚至不同的電腦上執行。

對照到上面的 C10K 的解決方案,Erlang 的方法是一個 thread 服務一個客戶端,使用 asynchronous calls 啟動 I/O,處理完成後發出通知,從上面的分析,我們也知道這種方式,同時可以處理 網路 與 Disk I/O。

Java設計分佈式網絡架構的不足及與Erlang的比較 中提到,傳統的 RPC (Java RMI) 都是錯誤的,我們不應該想辦法把遠端呼叫包裝成跟 local call 一樣。Erlang 沒有 RPC,只有 message send/receive,receiver也能設定 timeout。

Dig into Erlang

雖然 Erlang 天生的分散式及語言本身的特性,讓他非常適合實作一個多工、容錯、分散式的系統,但並不是學會了 Erlang 的語法,了解了 OTP,就代表我們可以完美地解決 C10K Problem,甚至能處理到 C500K Problem,這牽涉到語言熟悉度,以及一些性能調整的技巧,換句話說,我們需要花時間深入 dig into the world of Erlang。

從 C10K 到 C500K 這篇文章說,現在大家開始在談 C500K,而不是 C10K 了,也提供了資訊(Linux Kernel Tuning for C500k),使用 Java+NIO 的方式,達成 C500K 的指標。

其實要達成 C500K,也不一定要用 Erlang,用 Java+NIO 也可以。那麼是不是就不要用 Erlang 呢?Erlang 還有其他優勢是 Java 欠缺的,那就是容錯與分散式。

當我們以 Erlang OTP 撰寫服務時,可以很快速,在不需要修改太多程式碼的狀況下,將程式放在多個 Erlang VM 中運作,而且這幾個 Erlang VM 可以在單一或多個實體機器上執行,Erlang OTP 也內建了monitor機制,可以設定 process 存在的條件,在發生錯誤時,自動重新啟動,或做對應的處理。這樣的優勢在 Java 開發上完全是看不見的。

世界是平行的

當我們搜尋 Erlang 時,在繁體中文的網頁中,一定會搜尋到蔡學鏞先生寫的 Erlang:世界是平行的!,還有他翻譯而且已經絕版的 Erlang程式設計 這本書。Erlang的相關資料除了英文,還有對岸 Erlang資源列表 產出了很多翻譯的資料,背後的原因,當然是經濟規模。

在台灣的軟體開發,要求要能處理 C1K 已經算是個大型的系統了,一般中小企業的系統,同時大概都是幾十到幾百個使用者使用而已,在大陸,一個城市的經濟規模的最大值就可能遠遠超過台灣的狀況。

但我們也不需要妄自菲薄,大陸的軟體公司,也不是每一個都有需要作到 C10K,也有很多中小企業需要的軟體,並不是每一個系統,都要杞人憂天,幻想會有超多的使用者同時連線進來使用。畢竟系統都是在一個進化的過程中,慢慢地因應需求,逐漸調整到最佳狀態。

erlang 的語言特色

  1. 平行導向程式設計: 以 spawn/* 函式,將函式設定為獨立的 process,後續使用訊息互相傳遞,進行跨行程通訊
  2. functional programming
  3. single assignment: 變數只能被設定一次,不能異動
  4. dynamic data type: 動態資料型別
  5. exception catching: 以 try catch 進行異常處理
  6. code hot deployment: 在不中斷系統的情況下,進行程式替換

LYME/LYCE

在 open source 軟體堆疊中,如果要建構一個支援動態網頁內容的網站,相對於常見的 LAMP:Linux, Apache HTTP Server, MySQL, PHP,在 Erlang 環境有著 LYME/LYCE:Linux, Yaws, Mnesia/CouchDB, Erlang 的軟體bundle。

要開發網頁程式,LYME 也能提供完整的開發環境,而且除了 Linux 沒什麼好挑的之外(其實可以選擇自己慣用的 distribution,我們是用 CentOS),網頁 Server Yaws也有替代選擇:Mochiweb、Misultin、Cowboy,資料庫 Mnesia 的替代選擇為:CouchDB、Riak、SimpleDB、Cloudant、Couchbase Server。

Prepare to Jump Higher

C1K 已經很夠用了,那我們選擇學習 Erlang 的用意在哪?就是為了要「準備」,公司目前雖然還是在小企業的規模中掙扎,一開始也不自我膨脹,引入外部資金來支撐一些線上服務的夢想。

我們是雙面人,一方面要激進地嘗試不同的領域與技術,另一方面又是保守的,就算是要燒錢,也要在更有把握的條件下孤注一擲。

接下來我們會嘗試從基本語法開始,認識 Erlang 的語言特性,然後是 OTP,最終目的是產出一個 open source 專案。

Erlang 的爸爸:Joe Armstrong

最後要認識一下 Erlang 的爸爸 Joe ArmstrongSICS首頁 有他的照片。1986年釋出了第一版的 Erlang,到今天已經過了28年。

Github:http://joearms.github.io/
SICS:http://www.sics.se/~joe/
Blog:http://armstrongonsoftware.blogspot.tw/ 已經很久沒有更新了)