ruby服務器并發模型(譯)

并發

通常情況下會有很多用戶同時使用你的應用,并且你也希望應用能夠及時響應用戶的請求。那么你就需要使用某種方法去處理并發問題,大部分的 web服務器已經默認實現了。但是當你要擴大規模的時候,你就要盡可能的使用高效的并發模型。

不同的并發類型

處理并發問題,有多種途徑:多線程,多線程和事件循環,其中每一種都有自己的使用場景,優點及缺點。通過本文你會了解到它們的不同點和使用場景。

多進程(Unicorn)

是用多進程模型是比較容易實現并發的,主進程自身forks出多個工作進程,工作進程是用于實際處理請求的,而主進程用于管理工作進程。


每個工作進程在內存中有完整的代碼基。這導致多進程模型很容易內存吃緊并且很難擴充到大規模架構上。

多進程小結

場景
一個非 ruby 的例子就是眾所周知的Chrome 瀏覽器.
它使用多進程并發給每個標簽頁分配一個進程,這樣就不會因為一個標簽頁掛掉的導致整個瀏覽器停止工作。并且可以隔離開發單個標簽頁。

優點
非常容易實現,避免了多線程的安全問題,每個工作進程掛掉并不影響整個系統的其他部分。

缺點
每個進程會加載整個代碼庫到內存當中去。這會使得內存變得吃緊,因此不適合大規模并發請求。

多線程(Puma)

多線程模型,是通過在一個進程中運行多個線程來讓一個進程可以同時去處理多個請求。
與多進程不同, 所有的線程運行在一個進程中,這代表著它們中間是可以共享例如全局變量這樣的數據的。因此每個線程只會額外使用少量的內存。


全局解釋鎖(Global Interpreter Lock)
在 MRI中使用線程會遇到全局解釋鎖(GIL)。GIL被是用于鎖定所有 ruby 代碼的執行的,盡管我們的線程看上去是并行執行的,但實際上一個時間內只有一個線程是激活的。
IO 操作不受 GIL的限制,當你等待執行數據庫的返回結果時,是不會被鎖定的,其他的線程也是可以同時執行同樣的 IO操作的,如果你在線程中使用哈希或者數組去處理大量的數學計算的話,那么你只能利用一個核心。如果你使用 MRI 在大部分場景下還行需要使用多進程模型,去充分利用機器資源,或者你也可以使用 Rubinius或 jRuby,
這種沒有 GIL 的 ruby 實現。
線程安全
如果你使用多線程模型,那么就必須十分小心的操作線程中的共享數據。你可以通過使用 互斥鎖 在操作共享數據前鎖定它,這樣就可以確保其他線程不會在你已經修改了數據的情況下,還使用過期的數據。

多線程小總結

場景
這是一種折衷方案,被用于很多請求量少的普通 web 應用中

優點
相比于多進程模型,可以使用較少的內存。

缺點
你要確保你的代碼是線程安全的,如果線程出現了崩潰,那么它很有可能讓你的整個進程一起崩潰掉。GIL會鎖定除 IO之外的所有操作

事件循環(Thin)

事件循環是用于,當你需要執行很多并發 IO操作的場景。這個模型本身不會強制的讓多個請求在同時執行,而是通過高效的方式處理并發。
下面 你會看到非常簡單的使用 Ruby寫成的事件循環示例,循環從事件隊列中取出事件處理,如果隊列為空,他會休眠然后繼續查看隊列中是否有新的事件

loop do 
  if event_queue.any? 
    handle_event(event_queue.pop) 
  else
    sleep 0.1
  end
end

在圖中,我們能夠清晰的了解到事件循環是如何與操作系統隊列和內存交互的


步驟

  1. 操作系統一直監聽網絡和磁盤何時可用。
  2. 當操作系統看到 I/O 可用后, 它就會將事件添加到隊列中去。
  3. 隊列中存儲這若干,待事件循環處理的事件。
  4. 事件循環用于處理事件,并使用在內存中存儲與連接相關的元數據,也可以再次直接發送新的事件到事件隊列中去。
  5. 如果想要進行 I/O 操作,事件循環會告訴操作系統,它想繼續那個特定的 I/O操作。操作系統繼續監聽網絡和磁盤,并且當I/O可用后再次添加事件

事件循環小結

用例
有很多并發連接的場景,例如 Slack, Chrome notifications

優點
每個連接幾乎沒有多少內存開銷,可處理大量的并行連接

缺點
事件循環不是一個容易理解的模型。為防止隊列爆增,處理批次的大小必須小并且可預測。

究竟該使用哪一種模型?

希望這篇文章能夠更好的讓你理解不同的并發模型,雖然其中有些主題難以理解,但是掌握這些會讓你有工具去實驗并且能用正確的組織構建你的應用。

總結

大部分應用適合使用多線程模型,Ruby/Rails 生態圈 看起來正在(緩慢)向這個方面發展。
如果你的應用是高并發長連接的,那么事件循環很容你幫你實現。
如果你的應用不是高訪問量的網站,那么使用多進程的方式就以及足夠好了。
當然,還有一種可能是在多進程嵌套多線程,在多線程中再使用事件循環。

原文鏈接

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容