關於同步/異步、阻塞/非阻塞IO的摘要

四種IO模型

Boost application performance using asynchronous I/O把同步阻塞、同步非阻塞、異步阻塞、異步非阻塞的模型講得很清楚。

處理大量連接的問題

event-driven模型派(異步模型):

有人對於event-driven模型有一些批判,認爲多線程模型(同步阻塞模型)不比事件模型差:

  • Thousands of Threads and Blocking I/O,講了C10K提到的多線程模型的性能瓶頸在如今的內核裏已經不存在了,而多線程模型開發起來更簡單。
  • Why Events are a Bad Idea(for high concurrency servers) Rob von Behren,講了多線程模型的性能瓶頸基本上是因爲內核支持的不好、多線程類庫有缺陷造成的。認爲可以通過編譯器的優化、修復內核、修復多線程類庫來達到和事件驅動模型相當的結果。且認爲事件驅動模型的開發比較複雜。

兩種模型也不是說水火不容,SEDA提出了可以將兩種模型結合起來,構建更具彈性的系統。10年之後該作者寫了篇回顧文章A Retrospective on SEDA

SEDA提出了幾個很具有見地的意見:

  1. 應用程序的各個stage的壓力應該是可觀測和可調節的。
  2. 應用程序應該是well-conditioned。

什麼是Well-conditioned service?

Intuitively, a service is well-conditioned if it behaves like a simple pipeline, where the depth of the pipeline is determined by the path through the network and the processing stages within the service itself. As the offered load increases, the delivered throughput increases proportionally until the pipeline is full and the throughput saturates; additional load should not degrade throughput. Similarly, the response time exhibited by the service is roughly constant at light load, because it is dominated by the depth of the pipeline. As load approaches saturation, the queueing delay dominates. In the closed-loop scenario typical of many services, where each client waits for a response before delivering the next request, response time should increase linearly with the number of clients.

The key property of a well-conditioned service is graceful degradation: as offered load exceeds capacity, the service maintains high throughput with a linear response-time penalty that impacts all clients equally, or at least predictably according to some service-specific policy. Note that this is not the typical Web experience; rather, as load increases, throughput decreases and response time increases dramatically, creating the impression that the service has crashed.

簡單來說當負載超過一個應用的容量時,其性能表現要滿足以下兩點:

  • 吞吐量依然保持穩定,可以稍有下跌但絕不會斷崖式下跌
  • 隨着負載的增加其延遲線性增長,絕不會出現尖刺

Reactor pattern

事件驅動模型到最後就變成了Reactor Pattern,下面是幾篇文章:

Scalable IO in Java介紹瞭如何使用NIO,其中很重要的一點是handler用來處理non-blocking的task,如果task是blocking的,那麼要交給其他線程處理。這不就是簡化版的SEDA嗎?

Reactor Pattern的老祖宗論文:Reactor Pattern,TL;DR。Understanding Reactor Pattern: Thread-Based and Event-Driven幫助你快速理解什麼是Reactor Pattern,文中提到如果要處理10K個長連接,Tomcat是開不了那麼多線程的。對此有一個疑問,Tomcat可以採用NIO/NIO2的Connector,爲啥不能算作是Reactor呢?這是因爲Tomcat不是事件驅動的,所以算不上。

The reactor pattern and non-blocking IO對比了Tomcat和vert.x的性能差別,不過看下來發現文章的壓測方式存在偏心:

  1. 文中給Tomcat的線程少了(只給了500),只利用了40%左右的CPU,而vert.x的測試的CPU利用率爲100%。我把的Tomcat的線程設到2000,測試結果就和vert.x差不多了(驗證了多線程模型派的觀點)。
  2. vert.x的測試代碼和Tomcat的測試代碼不等價,沒有使用Thread.sleep()。不過當我嘗試在vert.x中使用sleep則發生了大量報錯,應該是我的使用問題,後面就沒有深究了。

總結

看了前面這麼多文章其實總結下來就這麼幾點:

  1. 選擇事件驅動模型還是多線程模型要根據具體情況來(不過這是一句廢話,; )
  2. 推崇、反對某個模型的文章/論文都是在當時的歷史情況下寫出來的,說白了就是存在歷史侷限性,因此一定要自己驗證,當時正確的論斷對現在來講未必正確,事情是會發生變化的。
  3. 看測試報告的時候一定要自己試驗,有些測試可能本身設計的就有問題,導致結果存在偏見。對於大多數性能測試來說,我覺得只要抓住一點就行了,就是CPU一定要用足。
  4. 我們真正應該關注的是不變的東西。

Jeff Darcy's notes on high-performance server design提到了高性能服務器的幾個性能因素:

  • data copy,問題依然存在,需要程序員去優化。
  • context switch,這個問題已經沒有了(見多線程派的幾篇文章),現代操作系統不論有多少thread,開銷不會有顯著增加。
  • memory allocation,這個要看看,不過在Java裏似乎和JVM GC有關。
  • lock contention,這個問題依然存在,應該儘量使用lock-free/non-blocking的數據結構。
  • 另外補充:在C10M裏提到kernel和內核的network stack也是瓶頸。

仔細看看有些因素不就是事件驅動模型和多線程模型都面臨的問題嗎?而又有一些因素則是兩種模型提出的當時所各自存在的短板嗎?而某些短板現在不是就已經解決了嗎?

上面說的有點虛,下面講點實在的。

如果你有10K個長連接,每個連接大部分時間不使用CPU(處於Idle狀態或者blocking狀態),那麼爲每個連接創建一個單獨的線程就顯得不划算。因爲這樣做會佔用大量內存,而CPU的利用率卻很低,因爲大多數時間線程都閒着。

事件驅動模型解決的是C10K問題,注意C是Connection,解決的是用更少的硬件資源處理更多的連接的問題,它不解決讓請求更快速的問題(這是程序員/算法的問題)。

要不要採用事件驅動模型取決於Task的CPU運算時間與Blocking時間的比例,如果比例很低,那麼用事件驅動模型。對於長連接來說,比如websocket,這個比例就很小,甚至可近似認爲是0,這個時候用事件驅動模型比較好。如果比例比較高,用多線程模型也可以,它的編程複雜度很低。

不論是採用哪種模型,都要用足硬件資源,這個資源可以是CPU也可以是網絡帶寬,如果發生資源閒置那你的吞吐量就上不去。

對於多線程模型來說開多少線程合適呢?Thousands of Threads and Blocking I/O裏講得很對,當能夠使系統飽和的時候就夠了。比如CPU到100%了、網絡帶寬滿了。如果內存用滿了但是這兩個都沒用滿,那麼一般來說是出現BUG了。

對於事件驅動模型來說也有CPU用滿的問題,現實中總會存在一些阻塞操作會造成CPU閒置,這也就是爲什麼SEDAScalable IO in Java都提到了要額外開線程來處理這些阻塞操作。關於如何用滿CPU我之前寫了一篇文章如何估算吞吐量以及線程池大小可以看看。

如何用滿網絡帶寬沒有什麼經驗,這裏就不說了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章