2010-08-19 5 views
4

학습 목적으로 Erlang에 간단한 TCP 프록시를 작성했습니다. 그것은 작동하지만 나는 많은 동시 요청을 만들기 위해 ab (Apache Bench)를 사용할 때 이상한 성능 저하를 경험합니다. 그 자체가 성능 하락 자체가 아니라 나를 경이롭게 만듭니다. 백엔드는 웹 서버로서 nginx입니다. 내 프록시가 ab와 nginx 사이에 앉아있다.얼랭 (Erlang) TCP 프록시가 많은 동시 요청을 받았을 때 성능이 그렇게 떨어지는 이유는 무엇입니까?

이것은 내 프록시 코드입니다. 내 프록시에서 64 개 연속 요청을 발사

-module(proxy). 
-export([start/3]). 

start(InPort, OutHost, OutPort) -> 
    {ok, Listen} = gen_tcp:listen(InPort, [binary, {packet, 0}, {active, once}]), 
    spawn(fun() -> connect(Listen, OutHost, OutPort) end). 

connect(Listen, OutHost, OutPort) -> 
    {ok, Client} = gen_tcp:accept(Listen), 
    spawn(fun() -> connect(Listen, OutHost, OutPort) end), 
    {ok, Server} = gen_tcp:connect(OutHost, OutPort, [binary, {packet, 0}, {active, once}]), 
    loop(Client, Server). 

loop(Client, Server) -> 
    receive 
    {tcp, Client, Data} -> 
     gen_tcp:send(Server, Data), 
     inet:setopts(Client, [{active, once}]), 
     loop(Client, Server); 
    {tcp, Server, Data} -> 
     gen_tcp:send(Client, Data), 
     inet:setopts(Server, [{active, once}]), 
     loop(Client, Server); 
    {tcp_closed, _} -> 
     ok 
    end. 

나는 아주 좋은 결과를 얻을.

ab -n 64 127.0.0.1:80/ 

Concurrency Level:  1 
Time taken for tests: 0.097 seconds 
Complete requests:  64 
Failed requests:  0 
Write errors:   0 
Total transferred:  23168 bytes 
HTML transferred:  9664 bytes 
Requests per second: 659.79 [#/sec] (mean) 
Time per request:  1.516 [ms] (mean) 
Time per request:  1.516 [ms] (mean, across all concurrent requests) 
Transfer rate:   233.25 [Kbytes/sec] received 

Connection Times (ms) 
       min mean[+/-sd] median max 
Connect:  0 0 0.3  0  1 
Processing:  1 1 0.5  1  2 
Waiting:  0 1 0.4  1  2 
Total:   1 1 0.5  1  2 

Percentage of the requests served within a certain time (ms) 
    50%  1 
    66%  2 
    75%  2 
    80%  2 
    90%  2 
    95%  2 
    98%  2 
    99%  2 
100%  2 (longest request) 

nginx에 대해 Apache Bench를 직접 사용하는 것보다 약간 느립니다.

하지만 프록시에서 64 개 동시 요청을 발사 성능은

ab -n 64 -c 64 127.0.0.1:80/ 

Concurrency Level:  64 
Time taken for tests: 2.011 seconds 
Complete requests:  64 
Failed requests:  0 
Write errors:   0 
Total transferred:  23168 bytes 
HTML transferred:  9664 bytes 
Requests per second: 31.82 [#/sec] (mean) 
Time per request:  2011.000 [ms] (mean) 
Time per request:  31.422 [ms] (mean, across all concurrent requests) 
Transfer rate:   11.25 [Kbytes/sec] received 

Connection Times (ms) 
       min mean[+/-sd] median max 
Connect:  0 31 121.7  0  501 
Processing:  3 1135 714.4 1001 2006 
Waiting:  3 1134 714.3 1000 2005 
Total:   3 1167 707.8 1001 2006 

Percentage of the requests served within a certain time (ms) 
    50% 1001 
    66% 1502 
    75% 2003 
    80% 2004 
    90% 2005 
    95% 2005 
    98% 2005 
    99% 2006 
100% 2006 (longest request) 

/문제가 어디에서 무엇 미친 떨어? 낮은 성능을 기대했지만 왜 이렇게 많이 했습니까? 초당 요청을보십시오!

많은 수고 보인 것 같지 않습니다. 나는 + A를 사용하여 많은 스레드를 사용합니다. 나는 심지어 SMP를 시도했지만 결과는 거의 동일합니다.

제 설정 : Windows 7 64, Intel QuadCore, 8GB RAM. 우분투에서 128 개의 동시 요청을 사용하여 비슷한 결과를 얻었습니다.

편집 : 새로운 통찰력이 포함됩니다. 총 요청 수는 중요하지 않습니다. 동시 요청 수입니다.

+0

코드없이 도움을 하드 조금씩처럼, 더 높은 값으로 시도해야 추측, 5입니다. 우리가 알고있는 모든 것에 대해 당신은 모든 것을 순차적으로 썼습니다. –

+0

@Matt : 더 많은 코드가 필요합니까? :) 코드를보세요. 순차적이지 않습니다. –

+0

죄송합니다. Jan, 전에 코드를 보지 못했습니다! –

답변

4

connect/3의이 부분은 시리얼입니다 : 당신은 gen_tcp:accept/1가 준비하고있는 새로운 생성 된 프로세스까지 새 연결을 받아 들일 수 없다

connect(Listen, OutHost, OutPort) -> 
    {ok, Client} = gen_tcp:accept(Listen), 
    spawn(fun() -> connect(Listen, OutHost, OutPort) end), 

. 코드에 병목 현상이 발생할 수 있습니다. 이 경우 성능 향상을 위해 "수락 자"풀을 사용해 볼 수 있습니다. 나는 또한 우연히 우체통을 채우는 것을 피하기 위하여 loop/2receive에 붙잡기 위하여 모든 절을 추가 할 것입니다.

또한 erl 매개 변수는 무엇입니까? +A스레드+K true이 관련되어 있습니까?

+0

수락 자 풀을 구현하는 방법을 잘 모르겠습니다. Naively 나는 시작 함수에서 4 개의 연결 프로세스를 생성했습니다. (spawn (fun() -> connect (Listen, OutHost, OutPort) end)) 효과가 없습니다. 나는 catch all 절을 추가했다. 효과가 없습니다. 나는 + A를 시도했다. 4. 효과 없음. + K는 내 Windows에서 지원되지 않습니다. 내 Linux VM에서 사용해 보겠습니다. –

+1

나는 Windows를 모른다. 10 년 동안 데스크톱에서도 사용하지 않고있다. 어쨌든 + A 다음의 숫자는 조금 더 커야합니다. 비동기를 수행하는 스레드의 수입니다. IO. 그래서 나는 50, 100을 시도 할 것입니다. 어쨌든, 얼마나 많은 양의 요청을 초당 처리하고 있습니까? 대기 시간 만 표시하고 처리량은 표시하지 않습니다. 당신은 높은 가치를 지닐 수 있으며 상황에 따라 더 많은 것을 얻을 수 없을 수도 있습니다. –

+0

저는 지금 MacPro를 사용하고 있지만 높은 부하가 문제입니다. 초당 1000 건의 요청을 처리합니다. 나는 빠른 테스트 wih + A 100을 가졌으며 그것이 대기 시간을 향상시킨 것으로 보인다. –

1

동일한 테스트를 nginx에 직접 시도해 보셨나요? 올바르게 구성하지 않으면 성능 저하가 발생할 수 있습니다.

+0

예. ab를 nginx에 16 개의 동시 요청으로 직접 사용하면 멋진 결과를 얻을 수 있습니다. 요청의 100 %는 5ms 미만에서 제공됩니다. –

1

결과를 복제 할 수 없습니다. 웹 서버로 아파치, yaws 및 nginx를 사용하여 테스트를 시도했지만 그 중 일부와 함께 프록시없이 실행되는 거의 변주를 찾지 못했습니다. Linux에서 실행했기 때문에 Windows 나 Windows 버전의 erlang VM에서 문제가 발생할 수 있습니다.

+0

당신 말이 맞아요. 그것은 리눅스 (우분투)에서 훨씬 더 잘 수행됩니다. VirtualBox에서 실행 되더라도 Windows에서보다 성능이 좋습니다 :)하지만 128 개의 동시 요청을하면 Linux에서도 문제가 발생합니다. 홀수 ... 1000 회 중 900 회는 빠르게 처리되며, 마지막 100 회는 매우 느리게 처리됩니다 (> 3000ms). 메모리/사서함 문제가 있다고 가정합니다. 아마도 가비지 수집기가 정리할만큼 빠르지 않을 수도 있습니다. –

1

{backlog, B} 옵션이 gen_tcp:listen 인 청취 소켓의 백 로그를 늘려 보았습니까?

기본값은 당신이 30 아니면 50

관련 문제