簡體   English   中英

您如何設計基於Erlang / OTP的分布式容錯多核系統的架構?

[英]How do you design the architecture of an Erlang/OTP-based distributed fault-tolerant multicore system?

我想構建一個基於Erlang / OTP的系統,它解決了一個“令人難以置信的並行”問題。

我已閱讀/瀏覽過:

  • 了解一些Erlang;
  • Erlang編程(阿姆斯特朗);
  • Erlang編程(Cesarini);
  • Erlang / OTP在行動中。

我有進程,消息,監督,gen_servers,Logging等的要點。

我確實理解某些架構選擇取決於所關注的應用程序,但我仍然想知道ERlang / OTP系統設計的一些一般原則。

我應該從一個主管的幾個gen_servers開始,並逐步建立?

我應該有多少名主管? 如何確定系統的哪些部分應基於流程? 我該如何避免瓶頸?

我以后應該添加日志嗎?

Erlang / OTP分布式容錯多處理器系統架構的一般方法是什么?

我應該從一個主管的幾個gen_servers開始,並逐步建立?

你在這里錯過了Erlang架構中的一個關鍵組件:應用程序! (也就是說,OTP應用程序的概念,而不是軟件應用程序)。

將應用程序視為組件。 系統中的一個組件解決了一個特定的問題,負責一組連貫的資源或從系統中抽象一些重要或復雜的東西。

設計Erlang系統的第一步是確定需要哪些應用程序。 有些可以按原樣從網絡中提取,我們可以將其稱為庫。 您需要自己編寫的其他人(否則您不需要這個特定的系統)。 我們通常將這些應用程序稱為業務邏輯(通常您也需要自己編寫一些庫,但保持庫與將所有內容綁定在一起的核心業務應用程序之間的區別很有用)。

我應該有多少名主管?

您應該為要監控的每種流程都配備一名主管。

一堆相同的臨時工? 一位主管統治他們。

不同的流程有不同的職責和重啟策略? 每個不同類型的流程的主管,處於正確的層次結構中(取決於什么時候應該重新啟動以及其他流程需要與它們一起下去?)。

有時可以在同一個主管下放置一堆不同的流程類型。 當您有一些將始終運行的單個進程(例如,一個HTTP服務器管理程序,一個ETS表所有者進程,一個統計信息收集器)時,通常會出現這種情況。 在這種情況下,每個人都有一個主管可能太過殘忍,所以通常會在一個主管下面添加一個主管。 請注意在執行此操作時使用特定重新啟動策略的含義,因此您不會one_for_one統計信息過程,例如,萬一您的Web服務器崩潰( one_for_one是在這種情況下使用的最常見策略)。 注意不要在one_for_one主管中的進程之間存在任何依賴關系。 如果一個進程依賴於另一個崩潰的進程,它也會崩潰,過於頻繁地觸發主管的重啟強度,並且過早地使主管本身崩潰。 這可以通過具有兩個不同的監督器來避免,這些監督者將通過配置的強度和周期完全控制重啟( 更長的解釋 )。

如何確定系統的哪些部分應基於流程?

系統中的每個並發活動都應該在它自己的進程中。 錯誤的並發抽象是Erlang系統設計人員最常犯的錯誤。

有些人不習慣處理並發問題; 他們的系統往往太少了。 一個過程,或幾個巨大的過程,按順序運行一切。 這些系統通常充滿代碼氣味,代碼非常嚴格,難以重構。 它也使它們變慢,因為它們可能不會使用Erlang可用的所有核心。

其他人立即掌握並發概念,但未能以最佳方式應用它們; 他們的系統傾向於過度使用流程概念,使許多流程閑置等待正在工作的其他人。 這些系統往往不必要地復雜且難以調試。

從本質上講,在兩種變體中都會遇到同樣的問題,您不會使用所有可用的並發性,並且您無法獲得系統的最大性能。

如果您堅持單一責任原則並遵守規則為您的系統中的每個真正並發活動創建流程,那么您應該沒問題。

有正當理由有閑置進程。 有時他們會保持重要的狀態,有時你想暫時保留一些數據,然后放棄這個過程,有時他們會等待外部事件。 更大的缺陷是通過長鏈非常不活躍的進程傳遞重要消息,因為它會通過大量復制減慢系統速度並使用更多內存。

我該如何避免瓶頸?

很難說,很大程度上取決於你的系統以及它正在做什么。 但是,一般來說,如果您在應用程序之間有一個良好的責任分工,那么您應該能夠將與該系統其他部分分開的應用程序擴展為瓶頸。

這里的黃金法則是衡量,衡量,衡量 在你測量之前,不要認為你有什么需要改進的地方。

Erlang的優點在於它允許您隱藏接口后的並發(稱為隱式並發)。 例如,您使用功能模塊API,一個普通的module:function(Arguments)接口,它可以反過來生成數千個進程,而調用者不必知道這一點。 如果您的抽象和API正確,您可以在開始使用它之后始終並行化或優化庫。

話雖如此,這里有一些一般的指導方針:

  • 嘗試直接向收件人發送郵件,避免通過中間進程引導或路由郵件。 否則系統會花費時間移動消息(數據)而不會真正起作用。
  • 不要過度使用OTP設計模式,例如gen_servers。 在許多情況下,您只需要啟動一個進程,運行一些代碼,然后退出。 為此,gen_server是矯枉過正的。

還有一個好處是:不要重復使用流程。 在Erlang中生成一個進程是如此便宜和快速,一旦它的生命周期結束,重用一個進程是沒有意義的。 在某些情況下,重新使用狀態(例如,文件的復雜解析)可能是有意義的,但是更好地規范地存儲在其他地方(在ETS表,數據庫等中)。

我以后應該添加日志嗎?

您應該立即添加日志記錄! 有一個很棒的內置API,名為Logger ,它帶有版本21的Erlang / OTP:

logger:error("The file does not exist: ~ts",[Filename]),
logger:notice("Something strange happened!"),
logger:debug(#{got => connection_request, id => Id, state => State},
             #{report_cb => fun(R) -> {"~p",[R]} end}),

這個新API有幾個高級功能,應該涵蓋大多數需要記錄的情況。 還有較舊但仍廣泛使用的第三方圖書館Lager

Erlang / OTP分布式容錯多處理器系統架構的一般方法是什么?

總結一下上面說的:

  • 將您的系統划分為應用程序
  • 根據需求和依賴關系,將您的流程置於正確的監督層次結構中
  • 為系統中的每個真正並發活動創建一個流程
  • 維護系統中其他組件的功能API。 這可以讓你:
    • 重構代碼而不更改使用它的代碼
    • 之后優化代碼
    • 在需要時分發您的系統(只需調用API后面的另一個節點!調用者不會注意到!)
    • 更輕松地測試代碼(減少設置測試工具的工作量,更容易理解如何使用它)
  • 開始使用OTP中可用的庫,直到你需要不同的東西(你知道,到時候)

常見的陷阱:

  • 過程太多了
  • 流程太少了
  • 路由太多(轉發的消息,鏈接的進程)
  • 應用程序太少(實際上我從未見過相反的情況)
  • 沒有足夠的抽象(很難重構和推理。它也很難測試!)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM