首先我想道歉,我提供了這麼多的信息,以儘可能清楚問題是什麼。請讓我知道是否還有什麼需要澄清的。Erlang插座直到第二個setopts纔會收到{active,once}
(運行二郎R13B04,內核2.6.18-194,CentOS的5.5)
我有一個很奇怪的問題。我有以下代碼傾聽和處理插座:
%Opts used to make listen socket
-define(TCP_OPTS, [binary, {packet, raw}, {nodelay, true}, {reuseaddr, true}, {active, false},{keepalive,true}]).
%Acceptor loop which spawns off sock processors when connections
%come in
accept_loop(Listen) ->
case gen_tcp:accept(Listen) of
{ok, Socket} ->
Pid = spawn(fun()->?MODULE:process_sock(Socket) end),
gen_tcp:controlling_process(Socket,Pid);
{error,_} -> do_nothing
end,
?MODULE:accept_loop(Listen).
%Probably not relevant
process_sock(Sock) ->
case inet:peername(Sock) of
{ok,{Ip,_Port}} ->
case Ip of
{172,16,_,_} -> Auth = true;
_ -> Auth = lists:member(Ip,?PUB_IPS)
end,
?MODULE:process_sock_loop(Sock,Auth);
_ -> gen_tcp:close(Sock)
end.
process_sock_loop(Sock,Auth) ->
try inet:setopts(Sock,[{active,once}]) of
ok ->
receive
{tcp_closed,_} ->
?MODULE:prepare_for_death(Sock,[]);
{tcp_error,_,etimedout} ->
?MODULE:prepare_for_death(Sock,[]);
%Not getting here
{tcp,Sock,Data} ->
?MODULE:do_stuff(Sock,Data);
_ ->
?MODULE:process_sock_loop(Sock,Auth)
after 60000 ->
?MODULE:process_sock_loop(Sock,Auth)
end;
{error,_} ->
?MODULE:prepare_for_death(Sock,[])
catch _:_ ->
?MODULE:prepare_for_death(Sock,[])
end.
這整個安裝工程奇妙正常,並一直工作在過去的幾個月。服務器作爲具有長時間tcp連接的消息傳遞服務器運行,並且平均擁有大約100k個連接。但是現在我們試圖更加嚴格地使用服務器。我們正在將兩個長期連接(將來可能更多)連接到erlang服務器,並且每個連接每秒創建幾百個命令。在通常情況下,這些命令中的每一個都產生了一個新的線程,這個線程可能會從mnesia讀取一些信息,並根據這些信息發送一些消息。
當我們嘗試測試這兩個命令連接時,會出現奇怪的現象。當我們打開命令流時,任何新的連接都有大約50%的掛起機會。例如,如果使用netcat連接併發送字符串「blahblahblah」,服務器應立即返回錯誤。在這樣做的時候,它不會在線程外進行任何調用(因爲它所做的一切都是試圖解析命令,因爲blahblahblah不是命令,所以命令會失敗)。但是大約有50%的時間(當兩個命令連接運行時)輸入blahblahblah導致服務器只是坐在那裏60秒,然後返回該錯誤。
在試圖調試這個我拉了wireshark。 tcp握手總是立即發生,當客戶端發送第一個數據包(netcat)時,它會立即進行確認,告訴我內核的tcp堆棧不是瓶頸。我唯一的猜測是問題在於process_sock_loop函數。它有一個接收將在60秒後返回到函數的頂部,並再次嘗試從套接字獲取更多信息。我最好的猜測是,下面發生的事情:
- 連接時,線程移動到process_sock_loop
- {活躍,一旦}設置
- 線程接收,但沒有得到數據,即使它的存在線程追溯到process_sock_loop頂部
- {活躍,一旦}再次
- 設置這一次的數據來通過,事情進行一個
- 後60秒s正常
爲什麼這是我不知道的,當我們關閉這兩個命令連接時,一切都恢復正常,問題消失。
任何想法?
感謝您的回覆!我最終試圖將我的erlang版本升級到R14,並且在升級到CentOS 6的過程中,問題在此之後還沒有出現。問題消失的唯一原因可能是由於新版本在CPU上的負載較小,一旦它再次出現,它會再次出現,但我無法再次發生。 –
原來升級並未完全解決問題。然而,在這個小小的修復中加入了。謝謝! –
如果有人檢查此答案,[ERL-90](http://bugs.erlang.org/browse/ERL-90)包含有關此掛起的實際原因的更多信息。 –