What have you found for these years?

2012-01-01

理想的 server concurrency 架構

這幾天一直在想這些事,快速筆記一下...

最外面一層肯定是一個 reactor, 畢竟 server 最前端是完全 I/O bound 的東西。
接下來 application 層如果碰到 I/O bound 的東西,大概就是用 server 所選擇的
reactor 來處理這些 I/O, 並用 fiber (coroutine) yield 一下。等到資料都 buffer
好之後,再 resume 跳回來。

假設在一個 request 中,我們有 A, B, C 三個 network dependency, 就是三樣
I/O bound 的操作。其中 C depends on A and B, 則我們可以叫 reactor 幫忙處理
A 與 B, 處理完之後透過 fiber (coroutine) resume 回來,由 application 處理,
處理完之後再叫 reactor 處理 C. 其中 A, B 可以同時處理,但是 C 不行,因為這裡
C depends on A, B, 而 A B 本身互相沒有關係。

最後要回傳回去的又 depends on C 的結果,所以這個 request 中的 fiber 將會
被 resume 兩次,一次是 A+B 的結果,另一次是 C 的結果。

假設之後其實又還有個 CPU bound 的 D 操作,而 D depends on C, 則在 C
處理完 resume 回來後,接著是 spawn 一個 thread 或 process 來處理 D!
可以由 reactor 維護一個 thread pool, 要 spawn thread 時,由 reactor 來
選擇使用哪個 thread. 接著同樣,application 層的 fiber 要 yield 出去。等到
D 完全處理完後,再 resume 回去。

以上完全沒提到 ruby, 不過我是在為 ruby 思索的。這可以透過 eventmachine
來處理。eventmachine 本身就有一個 thread pool, 可以讓玩家 programmer
defer 出去。也就是說,以上全部都可以透過 eventmachine + fiber 來完成。

不過事實上,我比較想透過 cool.io 來完成。原因很簡單,我覺得 eventmachine
已經太疊床架屋,東西變得太複雜難搞了。看看我前幾天的測試:

config.ru

cool.io 可以用最直觀的作法,但是 eventmachine 卻需要 async-rack + rack-fiber_pool.
當然啦,這裡會變成這樣,最主要的原因是 rainbows 中有 CoolioFiberSpawn,
但是卻沒有 EventMachineFiberSpawn. 我不知道這有什麼特別的原因,但我覺得
這肯定是有其原因的,可日後再思考,或是直接請教 Eric.

總而言之,用 cool.io 的話,東西都可以寫得很簡單。

eventmachine 會搞成這樣,我推測有一個很大原因是,有些 async framework,
例如 async_sinatra, 是用 throw :async 的方式來達到某種 Fiber.yield...
怎麼說,如果沒有 fiber (coroutine) 的話,這可能確實是比較簡單的作法。
但這樣做的話,其實把問題變得複雜很多 :(

cool.io 是沒有 thread pool, 沒有 eventmachine 的 defer 機制,不過我覺得
這應該還好,要做的話不是那麼困難。重點是這可以是獨立的東西,我甚至做在
application 層而非 reactor 層應該都沒問題。

總而言之,目前看起來就 ruby 而言,要完成這個方式最好的方式可能是用
rainbows + CoolioFiberSpawn, 雖然在 cool.io 上,感覺還欠不少東西,
可能要慢慢補上去.... 我不確定 Tony 是否有打算繼續做下去,這點讓我有點傷腦筋。
eventmachine 的替代品並不是很多啊 :(

0 retries:

Post a Comment

All texts are licensed under CC Attribution 3.0