2016-12-09 40 views
0

我有一個問題,我用根服務器做一些簡單的工作是這樣的:郵箱時得到更大的gen_server運行速度較慢

one handle_cast to do a long time work(takes 60 seconds) 
    one handle_cast to do a very fast work 

,一切都很好,當流量低。但是,當服務器進程在第一次長時間工作時,客戶端向服務器發送數千條消息(例如郵箱中的1000000條消息)時,長時間工作將變得非常緩慢,完成可能需要600秒。

問題就像這個問題上stackoverflow In Erlang, when a process's mailbox growth bigger, it runs slower, why?

但我還是不明白。如果由於垃圾收集,垃圾收集如何頻繁發生這麼長時間?

+0

你能顯示需要很長時間的'handle_cast'子句的代碼嗎?可能導致這種情況的一個原因是,如果有一個「接收」表達式匹配特定的消息。 – legoscia

+0

@legoscia哦,沒有。這個過程只需在循環中插入大約30,000個文檔到mongodb中。我的機器每秒可以寫入超過5000個文件,而且這也不是由mongodb磁盤IO造成的。 –

+0

@legoscia這個問題就像是什麼遇到http://stackoverflow.com/questions/36216246/in-erlang-when-a-processs-mailbox-growth-bigger-it-runs-slower-why –

回答

1

如果你有一個擁有這麼大郵箱的進程,你的系統在設計中可能有錯誤。

因爲所有的流量正在經歷一個單一的過程,並造成瓶頸。

Erlang的主要思想之一就是,創建新流程既快又便宜,所有的交易都應該有自己的。

只有在這些事務應具有對某些共享資源的序列化訪問權限(通常更新某些ETS表)的情況下,所有事務的一個進程纔是必需的。這個序列化訪問(使用消息)應儘可能短。

+0

Yah,系統設計可能是錯誤的。但是問題仍然在於爲什麼郵箱讓這個過程變得緩慢。 –

+0

這可能是由選擇性接收造成的。 – user8755563

+0

選擇性recive – user8755563

0

這不是因爲你使用的是一個句柄強制轉換,而強制轉換中的代碼沒有被阻塞,只有客戶端接口被釋放,所以它不會等待請求完成。

所以如果一個請求需要60秒完成,你必須從你的服務器產生一個單獨的進程來處理它。這是能夠繼續處理新的傳入消息的唯一途徑。

一個新的潛在問題上升:是否有可能真正處理新的請求並行在MongoDB中插入文檔?

如果是的話,一切都很好,

如果沒有,那麼你將不得不修改設計,比如返回一個否定確認到任何客戶端,其請求不與數據庫插入兼容(或忽略,如果該請求可能)。你必須儘可能快地清空信箱,60秒內積聚的消息是不是一個好的選擇,你是推二郎遠遠超出了其正常使用的,試想一下,你的使用情況:

  • 是收出長reaquest由服務器進入數據庫更新循環;
  • 在這段時間內,包含的郵件會在郵箱中累積,這意味着它們被複制到服務器的內存區域;
  • 很快,進程將會丟失內存,並且VM將不得不暫停進程(因此您的數據庫循環)來增加分配給服務器的內存,並最終創建一些數據副本。
  • 這種內存管理會降低服務器的性能,數據庫的更新需要更長的時間,而且會有更多的消息被累積,等等。
+0

謝謝你的回答。我會嘗試重新設計我的服務器。但是我仍然覺得這種內存管理很難將我的過程從60秒延遲到600秒。 –

0

最後,我發現我在this paper

答案在第3 二郎的內存架構是以流程爲中心。每個進程分配和管理自己的內存區域,通常包括PCB,私有堆棧和私有堆。

這種原因的缺點:高內存碎片

的方法不能利用,即使有大量的在該存儲區域中未使用的空間的另一過程的存儲器(例如,堆)。這通常意味着進程默認只能分配少量的內存。這反過來通常會導致對垃圾收集器的大量調用。

如此大的郵箱大小會導致整個系統變慢。

但是,這仍然不是主要觀點。遵循@pascal的巨大評論,處理數據庫的長時間成本,我忽略了gen_sever是關於發送和接收的。我碰到了gen_sever:撥打gen,顯然有選擇性接收!原諒我只是一點關於erlang的味道〜

+0

此外,我懷疑更新MongoDB的60秒請求包含強制服務器進程解析其郵箱的同步調用:對進程的同步訪問通過發送消息並等待響應完成。 receive語句在調用進程(您的服務器)中執行,並且每次到達時都必須解析郵箱。有一種機制可以優化這個解析,但我認爲如果來自數據庫和其他傳入請求的答案是交錯的,那麼優化效率就會降低。 – Pascal

+0

這真的是一個grep的帖子!我的mongo操作都是同步調用(由poolboy實現的db_pool),並且我碰到了erlang-opt gen_server https://github.com/erlang/otp/blob/OTP-18.3/lib/stdlib/src/gen.erl# L146。僅僅因爲選擇性接收,我的過程變慢了!再次感謝。 –