天天看點

akka設計模式系列-慎用ask

  慎用ask應該是Akka設計的一個準則,很多時候我們應該禁用ask。之是以單獨把ask拎出來作為一篇博文,主要是akka的初學者往往對ask的使用比較疑惑。

  "Using ask will send a message to the receiving Actor as with tell, and the receiving actor must reply with sender() ! reply in order to complete the returned Future with a value.

  The ask operation involves creating an internal actor for handling this reply, which needs to have a timeout after which it is destroyed in order not to leak resources"

  上面是官方文檔對ask的一個描述,很明顯,調用ask的時候會建立一個臨時的actor和一個future。這看起來問題也不大。初學者總是忍不住使用ask,因為這比較符合平時的開發思維:像調用函數那樣調用actor。

  一旦用akka來實作系統的功能,那麼我們一定要記住三個準則:一切皆異步、一切皆actor、沒有阻塞。ask并不符合這三個準則。也許你會說不使用ask,把一次調用分成兩個階段有點啰嗦。嗯,某種意義上說,你是對的。本來一次調用就完成的業務邏輯,現在必須用兩種類型的消息進行通信來完成。不過,這是一切皆異步的微小代價。使用akka開發系統,其實就是在面向消息程式設計。一切皆異步、actor,就意味着需要很多類型不同的消息。消息設計的好壞,很大程度上決定你akka系統的品質!

  我們來試想在系統中用到了ask,會出現什麼的影響。當然,影響有很多,我隻挑其中一點來說。在系統中用到了ask模式,就意味着在服務端會多建立一個臨時actor出來。那麼如果有1億次同樣的調用,就意味着多出1億個臨時actor,官方說250萬個actor大概消耗1GB記憶體,那究竟多出了多少記憶體還請你自己計算。這還是隻有一個ask調用的時候,如果ask調用多了,就意味着整個系統占用的記憶體會翻倍!想想都可怕。

  不過,存在即合理。既然官方實作了ask模式,那自有其适用的場景。ask可以在client中使用!client是在akka系統外部,它隻負責與akka系統通信,并擷取對應的結果,沒有其他複雜的功能,你可以把client了解為akka系統的邊界。

  那麼用戶端使用ask會不會出現上面的記憶體消耗的情況呢?當然會有,隻不過情況會很樂觀。假如隻有一個client,如果它發起了1億次調用,就會在本地建立1億個臨時actor,對于伺服器沒有任何額外的影響。即使用戶端因為記憶體消耗爆掉了,也不會影響伺服器的運作。最樂觀的情況是有1億個用戶端,發起了1億次ask,那麼同樣會建立1億個臨時actor,隻不過所有的臨時actor平均分布在每個用戶端,對伺服器仍然沒有影響。看到這其中的奧妙了嘛?其實把ask放到client,就是把資源消耗的壓力分散到了client!

  那麼伺服器端的akka系統可以沒有ask調用嗎?完全可以,如果你仍然沒有辦法消除伺服器端的ask調用,請參考我《akka設計模式系列》的其他文章。

繼續閱讀