2016-12-02 47 views
1

您好我想實施分佈式緩存作爲練習。緩存模塊基於gen_server。緩存由CacheSupervisor模塊啓動。起初我試着在一個節點上運行它,這很好用。現在我試圖將我的緩存分佈在兩個節點上,這兩個節點位於筆記本電腦上的兩個打開的控制檯窗口中。如何分配受監督的gen_server工作人員?

PS:

在寫這個問題,我意識到,我忘了我的第三個窗口連接到其他節點。我修好了,但我仍然有原始錯誤。

控制檯:

Node consoles

在我的第三個窗口連接我的節點我打電話CacheSupervisor.start_link()之後,這導致在follwing錯誤消息。

錯誤:

** (EXIT from #PID<0.112.0>) shutdown: failed to start child: :de 
    ** (EXIT) an exception was raised: 
     ** (ArgumentError) argument error 
      erlang.erl:2619: :erlang.spawn(:[email protected]_XPS, {:ok, #PID<0.128.0>}) 
      (stdlib) supervisor.erl:365: :supervisor.do_start_child/2 
      (stdlib) supervisor.erl:348: :supervisor.start_children/3 
      (stdlib) supervisor.erl:314: :supervisor.init_children/2 
      (stdlib) gen_server.erl:328: :gen_server.init_it/6 
      (stdlib) proc_lib.erl:247: :proc_lib.init_p_do_apply/3 

我猜測的錯誤指示在我的緩存模塊的start_link(name):gen_server.start_link(..)解析{:ok, #PID<0.128.0>}這似乎是不正確的,但我不知道該放在哪裏Node.spawn()其他

模塊緩存:

defmodule Cache do 
use GenServer 
def handle_cast({:put, url, page}, {pages, size}) do 
    new_pages = Dict.put(pages, url, page) 
    new_size = size + byte_size(page) 
    {:noreply, {new_pages, new_size}} 
end 

def handle_call({:get, url}, _from, {pages, size}) do 
    {:reply, pages[url], {pages, size}} 
end 

def handle_call({:size}, _from, {pages, size}) do 
    {:reply, size, {pages, size}} 
end 
def start_link(name) do 
    IO.puts(elem(name,0)) 
    Node.spawn(String.to_atom(elem(name, 0)), :gen_server.start_link({:local,elem(name, 1)}, __MODULE__, {HashDict.new, 0}, [])) 
end 

def put(name, url, page) do 
    :gen_server.cast(name, {:put, url, page}) 
end 

def get(name, url) do 
    :gen_server.call(name, {:get, url}) 
end 

def size(name) do 
    :gen_server.call(name, {:size}) 
end 

end 

模塊CacheSupervisor:

defmodule CacheSupervisor do 
    use Supervisor 
def init(_args) do 

    workers = Enum.map([{"[email protected]_XPS", :de},{"[email protected]_XPS", :edu}, {"[email protected]_XPS", :com} ,{"[email protected]_XPS", :it}, {"[email protected]_XPS", :rest}], 
    fn(n)-> worker(Cache, [n], id: elem(n, 1)) end) 
    supervise(workers, strategy: :one_for_one) 
end 

def start_link() do 
    :supervisor.start_link(__MODULE__, []) 
end 

end 

回答

1
:erlang.spawn(:[email protected]_XPS, {:ok, #PID<0.128.0>}) 

:erlang.spawn/2是相同的功能,Node.spawn/2。該函數需要節點名稱(已提供)和函數。您的GenServer.start_link調用應該返回{:ok,Pid}。由於一個元組不能被當作函數Node.spawn/2崩潰。

我不會推薦像這樣的單獨節點上的產卵過程。如果遠程節點發生故障,您不僅會丟失集羣中的該節點,還需要處理所有衍生進程的後果。這會導致應用程序比其他應用程序更脆弱。如果你想讓你的緩存GenServers運行在多個節點上,我建議運行你在多個節點上構建的應用程序,並且在每個節點上都有一個你的CacheSupervisor的實例。然後每個CacheSupervisor啓動它下面的自己的GenServers。這更加健壯,因爲如果一個節點停機,剩下的節點將不受影響。當然,您的應用程序邏輯需要考慮到這一點,丟失節點可能意味着丟失緩存數據或客戶端連接。看到這個答案的詳細信息:How does an Erlang gen_server start_link a gen_server on another node?

如果你真的想在產卵過程在遠程節點上這樣你可以這樣做:

:erlang.spawn_link(:[email protected]_XPS, fun() -> 
    {:ok, #PID<0.128.0>} = :gen_server.start_link({:local,elem(name, 1)}, __MODULE__, {HashDict.new, 0}, []) 
    receive 
    % Block forever 
    :exit -> :ok 
    end 
end) 

請注意,您必須使用spawn_link,監事期待與他們的孩子聯繫在一起。如果管理員沒有鏈接,它不會知道孩子何時崩潰並且無法重新啓動進程。

+0

謝謝你,你的回答很有幫助。我決定修改程序邏輯。現在每個工人都有自己的主管 –