로드 테스트 : 초당 요청을 생성하는 방법?


14

Zeroc-ICE를 실행하는 서버 구성 요소가 있습니다. 로드 테스트를 원할 때 병렬 라이브러리를 사용하여 여러 요청을 만들면 가능하다고 생각했습니다. 그러나 그것은 결국 끝납니다. C #의 Parallel (Parallel.For) 라이브러리를 사용하는 것이 더 쉬웠지만 동일한 순간에 모든 것을 병렬로 정확하게 생성하는 것은 아닙니다. 따라서 초당 N 개의 요청을 작성하기위한 정의가 될 수 없습니다. 어떻게해야합니까? 로드 테스트를 먼저하고 싶은 사람은 실제로 이것에 대해 생각할 것입니다.

  1. 실제로 초당 N 개의 요청을 실제로 생성하는 효율적인 방법은 무엇입니까?

  2. 또 다른 신화는 병렬 프로그래밍에 관한 것입니다. 일반적으로 C # 또는 .Net에서 병렬 프로그래밍 패턴을 사용한 경우, 우리를 계몽하십시오. 5 개의 프로세스가 있다고 상상해보십시오. 다섯 프로세스를 동시에 시작하는 방법 자원 소비가 무엇을 의미합니까? 나는 인터넷을 통해 구할 수있는 많은 자료들을 읽으려고 노력했지만 그것들이 나의 질문에 대한 답인 것보다 더 많은 질문을 받는다.

  3. Parallel.For를 사용하여 N 스레드와 측정 시간을 만들었습니다. 그런 다음 Task 열거를 위해 Task.Factory.start를 사용하여 동일한 것을 시도했습니다. 측정 시간이 다릅니다. 그렇다면 이것들을 사용하는 것의 차이점은 정확히 무엇입니까? 해당 클래스를 사용해야 할 때와 목적은 정확히 무엇입니까? 우리는 종종 많은 부를 가지고 있지만 단지 우리는 서로를 구별하는 방법을 정확히 모릅니다. 이것은 나를 위해 하나의 경우이며, 왜 서로를 사용해서는 안되는지 찾을 수 없습니다.

  4. 나는 스톱워치 클래스를 사용하여 최고의 시간을 측정했습니다. 구성 요소를로드 테스트하는 시나리오에서 응답 시간을 측정하는 방법은 무엇입니까? 스톱워치는 저에게 가장 적합한 솔루션 인 것 같습니다. 모든 의견을 환영합니다.

추신 : 웹 응용 프로그램을위한 많은 부하 테스트 도구가 있습니다. 광산은 서버 구성 요소의 맞춤형 사례입니다. 그리고 내 질문은 초당 N 개의 스레드를 만드는 것과 관련이 있습니다.

모든 의견을 환영합니다. 프로그래밍 문제가 아니라고 생각하지 마십시오. 물론입니다. 직접 제품 자체의 성능을 파악하기 위해 QE를 직접하고 싶은 프로그래머라면 누구나 종을 울려 야합니다. 많은 옵션을 시도한 후 실제로 어떻게해야하는지에 대해 생각해보아야합니까?


FAQ는 특정 프로그래밍 문제와 관련이 있고 프로그래밍 직업에서 실질적으로 대답 할 수있는 문제가 있으면 요청할 수 있다고 말합니다. 회의론자이고 이것을 신고하는 사람들. 의견을주세요.

"같은 순간"은 무슨 뜻입니까? TPL 또는 PLinq를 강제로 달성 할 수 있는지 궁금합니다.
Gert Arnold

내 질문은 초당 N 개의 요청을 생성하는 것입니다. 따라서이 시나리오에서 동일한 순간은 병렬 사용에 대한 이해가 병렬 방식으로 스레드를 시작한다는 의미였습니다.
King

순차적 분석을 수행 했습니까?

3
프로그래밍과 관련이있을 수 있지만 게시물에 너무 많은 질문이 있습니다 (최소 4 개). 너무 광범위해서 닫히기 전에 묻고 싶은 한 가지 질문으로 줄였습니다. 방금 언급 한 10000과 같은 관련 정보를 테스트 머신의 코어 수로 제공하십시오. 코드 표시가 도움이됩니다.
Gert Arnold

답변:


10

나는 모든 대답이 없습니다. 잘만되면 나는 그것에 약간의 빛을 비출 수 있다.

.NET의 스레딩 모델에 대한 이전의 설명을 단순화하려면 Parallel Library가 Tasks를 사용하고 Task의 기본 TaskScheduler가 ThreadPool을 사용한다는 것을 알고 있습니다. 계층 구조에서 높을수록 (ThreadPool이 맨 아래에 있음) 항목을 만들 때 더 많은 오버 헤드가 발생합니다. 그 여분의 오버 헤드가 확실히 느리다는 것을 의미하지는 않지만 그것이 있다는 것을 아는 것이 좋습니다. 궁극적으로 다중 스레드 환경에서 알고리즘의 성능은 설계에 따릅니다. 순차적 으로 잘 수행되는 것은 병렬로 잘 수행되지 않을 수 있습니다 . 어렵고 빠른 규칙을 제공하기에는 너무 많은 요소가 관련되어 있으며, 수행하려는 작업에 따라 변경됩니다. 네트워크 요청을 다루기 때문에 간단한 예를 들어 보겠습니다.

소켓 전문가가 아니라고 Zeroc-Ice에 대해 아는 것이 없습니다. 비동기 작업에 대해 조금 알고 있으며 이것이 실제로 도움이 될 것입니다. 소켓을 통해 동기 요청을 보내면을 호출 Socket.Receive()하면 요청이 수신 될 때까지 스레드가 차단됩니다. 이건 좋지 않아 스레드가 차단되어 더 이상 요청을 할 수 없습니다. Socket.Beginxxxxxx ()를 사용하면 I / O 요청이 이루어지고 소켓의 IRP 대기열에 저장되며 스레드는 계속 진행됩니다. 즉, 스레드가 실제로 차단없이 수천 개의 요청을 루프로 만들 수 있습니다!

내가 당신을 올바르게 이해한다면 테스트 코드에서 Zeroc-Ice를 통한 호출을 사용하고 실제로 http 끝점에 도달하려고하지 않습니다. 이 경우 Zeroc-Ice의 작동 방식을 모른다는 것을 인정할 수 있습니다. 그러나 여기나열된 조언 , 특히 부분을 따르는 것이 좋습니다 Consider Asynchronous Method Invocation (AMI). 이 페이지는 이것을 보여줍니다 :

AMI를 사용하면 클라이언트는 호출이 전송 되 자마자 (또는 즉시 전송 될 수없는 경우 대기열에 놓인 즉시) 제어 스레드를 다시 확보하여 클라이언트가 해당 스레드를 사용하여 그 동안 다른 유용한 작업을 수행 할 수 있도록합니다. .

.NET 소켓을 사용하여 위에서 설명한 것과 동등한 것 같습니다. 많은 전송을 시도 할 때 성능을 향상시키는 다른 방법이있을 수 있지만 여기서 시작하거나 해당 페이지에 나열된 다른 제안으로 시작합니다. 귀하는 응용 프로그램의 디자인에 대해 매우 모호하여 위의 것보다 더 구체적 일 수 있습니다. 꼭 필요한 것을 얻는 데 꼭 필요한 것보다 많은 스레드를 사용하지 마십시오 . 그렇지 않으면 응용 프로그램이 원하는 것보다 훨씬 느리게 실행될 수 있습니다.

의사 코드의 일부 예 (실제로 그것을 배우지 않고도 가능한 한 얼음에 가깝게 만들려고 시도했습니다) :

var iterations = 100000;
for (int i = 0; i < iterations; i++)
{
    // The thread blocks here waiting for the response.
    // That slows down your loop and you're just wasting
    // CPU cycles that could instead be sending/receiving more objects
    MyObjectPrx obj = iceComm.stringToProxy("whateverissupposedtogohere");
    obj.DoStuff();
}

더 좋은 방법 :

public interface MyObjectPrx : Ice.ObjectPrx
{
    Ice.AsyncResult GetObject(int obj, Ice.AsyncCallback cb, object cookie);
    // other functions
}

public static void Finished(Ice.AsyncResult result)
{
    MyObjectPrx obj = (MyObjectPrx)result.GetProxy();
    obj.DoStuff();
}

static void Main(string[] args)
{
    // threaded code...
    var iterations = 100000;
    for (int i = 0; i < iterations; i++)
    {
        int num = //whatever
        MyObjectPrx prx = //whatever
        Ice.AsyncCallback cb = new Ice.AsyncCallback(Finished);
        // This function immediately gets called, and the loop continues
        // it doesn't wait for a response, it just continually sends out socket
        // requests as fast as your CPU can handle them.  The response from the
        // server will be handled in the callback function when the request
        // completes.  Hopefully you can see how this is much faster when 
        // sending sockets.  If your server does not use an Async model 
        // like this, however, it's quite possible that your server won't 
        // be able to handle the requests
        prx.GetObject(num, cb, null);
    }
}

소켓을 보내려고 할 때 (또는 실제로 무언가를 할 때) 더 많은 스레드! = 더 나은 성능을 명심하십시오. 스레드는 작업중 인 모든 문제를 자동으로 해결한다는 점에서 마술이 아닙니다. 스레드가 대기하는 데 많은 시간을 소비하지 않는 한 코어 당 1 개의 스레드를 원하는 것이 이상적입니다. 컨텍스트 전환이 발생하고 리소스가 낭비되므로 각 요청을 자체 스레드에서 실행하는 것은 좋지 않습니다. (내가 쓴 모든 내용을 보려면 편집을 클릭 하고이 게시물의 과거 개정판을 살펴보십시오. 주요 문제 만 흐리게 보이기 때문에 제거했습니다.)

초당 많은 수의 요청을하려면 스레드에서 이러한 요청을 확실히 수행 할 수 있습니다. 그러나 쓰레드 생성으로 오버 보드하지 마십시오. 균형을 찾아서 고수하십시오. 비동기 모델과 동기 모델을 사용하면 성능이 향상됩니다.

도움이 되길 바랍니다.


왜 성능에 대해 그렇게 많이 이야기하고 있습니까? 그것은 OP가 원하는 것이 아닌 것 같습니다.
svick

1
@svick은 ops 원래 게시물에 원래 4 가지 질문이 있었으며 병렬 대 작업의 성능에 대한 질문을 한 다음 편집 한 다음 다시 돌아 왔습니다. 따라서 읽은 내용의 대부분이 그 결과였습니다. 궁극적으로 그의 질문은 일반적인 아이디어가 정확하기 때문에 성능과 관련이 있지만 구현에는 부족한 것 같습니다. 나는 마지막에 내 대답이 그가 편집 하지 않은 질문에 대답한다고 생각 합니다.
Christopher Currens

1
그들이 질문을 마무리하기 위해 투표하고 싶었 기 때문에 질문을 줄여야했습니다. 이제는 여기에 유효한 것으로 보입니다. @ChristopherCurrens는 스레드 풀과 작업의 차이에 대한 +1의 좋은 점입니다. 그것은 나의 이해를 넓혔습니다. 그러나 나는 여전히 초당 N 개의 요청을 생성하는 것이 실제로 어떻게 가능합니까? 가장 좋은 방법은 무엇입니까?
King

@ King-내가 생각했던 것만 큼 명확하지 않은 것 같습니다. 내가 생각한 마지막 3-4 단락은 당신을 도울 것입니다. 나는 당신이 이미 일종의 루프를 사용하고 있다고 가정했습니다. 그렇게하는 경우 소켓 송신 / 수신이 차단되어 요청 속도가 느려집니다. 어쩌면 의사 코드 예제를 게시 할 시간이있을 것입니다.
Christopher Currens 2012 년

실제로 ICE로 전송하는 데 아무런 문제가 없습니다. 문제는 실제로 N 개의 요청을 생성하고 해당 숫자에 해당하는 N을 구현하는 것을 정의하는 것입니다.

2

질문 1)을 건너 뛰고 2 번으로 넘어갑니다. 일반적으로 원하는 것을 달성하는 데 허용되는 방법이기 때문입니다. 과거에는 초당 n 개의 메시지 를 달성하기 위해 단일 프로세스를 생성 한 다음 p 개의 AppDomain 을 시작할 수 있습니다 . 각 AppDomain은 기본적으로 특정 시점에 도달하면 (타이머 사용) 요청 루프를 실행하기 시작합니다. 이 시간은 각 AppDomain에서 동일한 시점에 서버를 시작하기 위해 동일해야합니다.

이와 같은 것이 요청을 보내는 데 효과적입니다.

WaitCallback del = state => 
{ 
    ManualResetEvent[] resetEvents = new ManualResetEvent[10000]; 
    WebClient[] clients = new WebClient[10000]; 

    for (int index = 0; index < 10000; index++) 
    { 
        resetEvents[index] = new ManualResetEvent(false); 
        clients[index] = new WebClient(); 

        clients[index].OpenReadCompleted += new OpenReadCompletedEventHandler (client_OpenReadCompleted); 

        clients[index].OpenReadAsync(new Uri(@"<REQUESTURL>"), resetEvents[index]); 
    } 

    bool succeeded = ManualResetEvent.WaitAll(resetEvents, 10000); 
    Complete(succeeded); 

    for (int index = 0; index < 10000; index++) 
    { 
        resetEvents[index].Dispose(); 
        clients[index].Dispose(); 
    } 
}; 

while(running)
{
    ThreadPool.QueueUserWorkItem(del);
    Thread.Sleep(1000);
}

이것은 아마도 어떤 컴퓨터에서 실행중인 시스템의 성능을 떨어 뜨릴 수 있으므로 리소스가있는 경우 (앱 도메인 대신 프로세스 사용) 항상 여러 다른 컴퓨터에서 유사한 유형의 루프를 구현할 수 있습니다.

세 번째 질문은이 링크에 http://www.albahari.com/threading/

마지막으로, 스톱워치는 서버의 지속 시간 및 고유 적중을 모두 추적하기 위해 적중 카운터와 쌍을 이루어야합니다. 사실 후에 분석을 수행 할 수 있습니다.


2
여기에 별도의 AppDomain을 만들어야하는 가능한 이유는 무엇입니까? 그것은 완전히 불필요한 것 같습니다.
svick

0

N이 합리적으로 작 으면 스레드를 신경 쓰지 마십시오. 초당 N 개의 요청을 생성하려면 벽시계 시간 ( DateTime.Now)을 사용하십시오 . 요청 전후에 시간을 내고 Sleep다음 요청을 지연시키기 위해 a 를 추가하십시오 .

예를 들어 N = 5 (200ms) 인 경우 :

Before request: 12:33:05.014
After request: 12:33:05.077
Sleep(137)
Before request: 12:33:05.214
After request: 12:33:05.271
Sleep(131)

이것은 완벽하지 않습니다. 당신 Sleep은 그것이 정확하지 않을 수 있습니다 . (X '요청 전, 시간이 X-1 / N 이후 여야 함) 편차의 실행 횟수를 유지하고 그에 따라 절전 기간을 조정할 수 있습니다.

N이 너무 커지면 간단히 M 스레드를 작성하고 각 스레드가 동일한 방식으로 N / M 요청을 생성하게하십시오.


매우 많은 수의 요청을 생성해야합니다. 따라서 100 스레드 전에도 내 메모리 (4GB RAM)를 마실 수 있으므로 옵션이 될 수 없습니다.

250K 코드로 단일 스레드에서 초당 20.000 건의 요청을 작성했습니다. 어쨌든 100 개의 스레드를 실행할 충분한 CPU가 없습니다 (해당 클래스에는 4GB가 제공되지 않음). 다음 문제는 모든 요청을 밀어내는 것입니다. 로드 작성자와 서버 사이에 10Gbit / s 이더넷이 있습니까? 따라서 실제 요구 사항을 확인하고 싶을 수도 있습니다.
MSalters

명확히하기 위해 20 + Gbps와 같은 것이 있습니다. 그래서 그것은 문제가되지 않습니다. 기계류에 대해, 무엇을 언급 하시겠습니까? 프로세서 수?

@ 킹 : 100 스레드를 밀기 위해서는 48 코어 머신이 필요합니다. 예를 들어 SGI는 코어가 많은 머신을 판매하지만 일반적으로 32GB 이상인 머신을 판매합니다.
MSalters

0

.NET 프로젝트에 대한로드 테스트를 수행하는 가장 쉬운 방법은 Ultimate Edition의 Visual Studio를 구입하는 것입니다. 여기에는로드 테스트를 포함하여 모든 종류의 테스트를 수행 할 수있는 통합 테스트 도구가 제공됩니다. 단일 PC에서 가상 사용자를 작성하거나 더 많은 수의 사용자를 위해 여러 사용자에게 분산하여로드 테스트를 수행 할 수 있습니다. 또한 테스트 기간 동안 추가 데이터를 리턴하기 위해 대상 서버에 설치할 수있는 작은 프로그램도 있습니다.

이것은 비싸지 만 궁극적 인 버전에는 많은 기능이 제공되므로 모두 사용하면보다 합리적인 가격이됩니다.


0

X 스레드가 모두 동시에 동시에 리소스에 충돌하게하려면 각 스레드를 카운트 다운 래치 뒤에 놓고 세마포어 검사 사이에 짧은 대기 시간을 지정할 수 있습니다.

C #에는 구현이 있습니다 (http://msdn.microsoft.com/en-us/library/system.threading.countdownevent(VS.100).aspx).

동시에, 시스템의 스트레스 테스트를하는 경우 실제로 경쟁 조건을 확인하고 싶을 수도 있습니다.이 경우 시간이 지남에 따라 무작위 주파수 및 피크 / 퍼로 시추되는 각 스레드에 스레드 절전 기간을 설정하려고합니다.

마찬가지로 실제로 여러 요청을 빠르게 보내고 싶지 않을 수도 있습니다. 메시지를 보내고 보내는 데 더 많은 시간을 소비하는 더 적은 수의 스레드를 설정하여 서버를 나쁜 상태로 만들고 실제 성능을 테스트하는 데 더 나은 성공을 거둘 수 있습니다. 서버는 느리게 진행되는 메시지를 처리하기 위해 자체 스레드를 스핀 업해야 할 것이므로 소켓을 통해 처리해야합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.