2015-09-22 24 views
7

Sorunum var: 1M eşzamanlı açık tcp bağlantısını tutabilen bir Erlang sunucusu oluşturmak istiyorum. Dosya tanımlayıcılarını yükseltmek için işletim sistemimi (Oracle Linux 7) ayarladı. sunucuda i gen_tcp yapın: dinlemekErlang aynı anda 1M istemcilerini bağla

// point_1
Soket = gen_tcp:
spawn (sap (Soket)) // i bağlarsanız point_1

için
geri başka bir iş parçacığı kabul sırayla onun hiçbir sorun, 100 saniyede 100K istemcileri bağladım; ama daha fazla bir şey için hiç bir isteğim yoktu.

Bağlantısını bağlantı yolu ile bağlamak isterseniz, örneğin 100'den yalnızca 80 bağlantı yapılır.

Bu her şeyi çalıştırmak nasıl:

erlc *.erl 
erl +Q 134217727 +P 1000000 -env ERL_MAX_PORTS 40960000 -env ERTS_MAX_PORTS 40960000 

// 9999

ex:start(1, 9999) 

// 100 istemcileri noktası üzerinde bağlanmayı deneyin bağlantı noktasında dinleyecek bir sunucuyu başlatmak 9999

ex:connect_clients(100, 9999) 

Size bir kod göstereyim:

Burada
start(Num,LPort) -> 
    case gen_tcp:listen(LPort,[{active, false},{packet,2}]) of 
    {ok, ListenSock} -> 
     start_servers(Num,ListenSock), 
     {ok, Port} = inet:port(ListenSock), 
     Port; 
    {error,Reason} -> 
     {error,Reason} 
    end. 

start_servers(0,_) -> 
    ok; 
start_servers(Num,LS) -> 
    spawn(?MODULE,server,[LS,0]), 
    start_servers(Num-1,LS). 

server(LS, Nr) -> 
    io:format("before accept ~w~n",[Nr]), 
    case gen_tcp:accept(LS) of 
    {ok,S} -> 
     io:format("after accept ~w~n",[Nr]), 
     spawn(ex,loop,[S]), 
     server(LS, Nr+1); 
    Other -> 
     io:format("accept returned ~w - goodbye!~n",[Other]), 
     ok 
    end. 

loop(S) -> 
    inet:setopts(S,[{active,once}]), 
    receive 
    {tcp,S, _Data} -> 
     Answer = 1, 
     gen_tcp:send(S,Answer), 
     loop(S); 
    {tcp_closed,S} -> 
     io:format("Socket ~w closed [~w]~n",[S,self()]), 
     ok 
    end. 

client(PortNo) -> 
    {ok,Sock} = gen_tcp:connect("localhost", PortNo, 
    []). 

connect_clients(Number, Port) -> 
    spawn(ex, client, [Port]), 
    case Number of 
    0 -> ok; 
    _ -> connect_clients(Number-1, Port) 
    end. 

cevap

8

görüyorum en azından iki sorunlar: Sen birikim dinlemek için öncelikle yükseltmek gerekir

  • ; varsayılan olarak 5'dir. Dinleme seçeneklerinde {backlog, N} ayarını yaparak, örneğin {backlog, 1024}. Bir bağlantıyı kabul çünkü

  • Sizin server/2 fonksiyonu daha sonra loop/1 çalıştırmak için yeni bir işlemi olarak çoğaltılır ama bu yeni bir süreç kabul soket için controlling process yapmaz, arızalı. loop/1 işlevi, gelen iletileri alma girişimi sırasında sokete {active,once} modunu ayarlamaya çalışır, ancak denetleme sürecinde çalışmadığı için işe yaramaz. (Onun yerine orada ok = inet:setopts(S,[{active,once}]), diyerek inet_setopts/2 dönüş değerini doğrulamalıdır.)

yerine döngü yumurtlama, bunun yerine yeni bir akseptörü yumurtlamaya gerektiğini, bunun gibi:

server(LS, Nr) -> 
    io:format("before accept ~w~n",[Nr]), 
    case gen_tcp:accept(LS) of 
    {ok,S} -> 
     io:format("after accept ~w~n",[Nr]), 
     spawn(ex,server,[LS,Nr+1]), 
     loop(S); 
    Other -> 
     io:format("accept returned ~w - goodbye!~n",[Other]), 
     ok 
    end. 

Bu yaklaşımla Soketi kabul eden işlem loop/1 çalışır ve böylece soketin kontrol işlemini değiştirmeye gerek yoktur.

+0

Gerçekten de, bu iki konu hakkında haklıydınız. Onları tamir ettim. Şimdi connect_clients (1000, 9999) dediğimde, saniyede yaklaşık 100 bağlanır ve 800'e gider; o zaman durur. Sunucu çökmez, böylece tekrar arayabilirim, bir müşteri veya istediğim numarayı bağlarım. Ancak, çağrı başına yaklaşık 800'den fazla bağlantı kuramıyorum. Connect_clients (1000000, 9999) çağırabilirdim, ancak VM'im donuyor. Düşüncesi olan var mı? Bana şimdiden yardım ettiğin için teşekkürler. –

+1

Ayrıca, kabul ederken, daha iyi verim elde etmek için aynı dinleme soketinde 'gen_tcp: accept/1 'çağıran birkaç alıcı işlemine sahip olabileceğinizi unutmayın. –

+0

@ ȘtefanStan, vurduğunuz yeni sorunları söylemek zor. Sasl etkinken çalışıyor musunuz? Fark edilmeyecek herhangi bir sorunla karşılaşmadığınızdan emin olmak için başlatabilirsiniz. İhtiyacınız olan bağlantı sayısını sağlamak için işletim sisteminizin doğru şekilde kurulduğundan emin misiniz? Kabuğundaki ulimit -n 'neyi gösteriyor? Ayrıca, hangi Erlang/OTP sürümünü kullanıyorsunuz? –