응답 시간이 갑자기 급상승하는 이유는 무엇입니까?


12

IIS에서 호스팅되는 ServiceStack을 사용하여 구현 된 API가 있습니다. API의로드 테스트를 수행하는 동안 응답 시간은 좋지만 서버 당 약 3,500 명의 동시 사용자를 공격하자마자 빠르게 저하되는 것을 발견했습니다. 우리는 두 대의 서버를 보유하고 있으며 7,000 명의 사용자로 서버를 공격 할 때 모든 엔드 포인트에서 평균 응답 시간이 500ms 미만입니다. 박스는로드 밸런서 뒤에 있으므로 서버 당 3,500 개의 동시성을 얻을 수 있습니다. 그러나 총 동시 사용자 수를 늘리면 응답 시간이 크게 증가합니다. 동시 사용자를 서버 당 5,000으로 늘리면 엔드 포인트 당 평균 응답 시간이 약 7 초가됩니다.

서버의 메모리와 CPU는 응답 시간이 좋을 때와 성능이 저하 된 후 모두 낮습니다. 동시 사용자가 10,000 명일 때 CPU의 평균은 평균 50 % 미만이며 RAM은 16 개 중 3-4GB 정도입니다. 아래 스크린 샷은 총 10,000 명의 동시 사용자와 함께로드 테스트 중에 perfmon의 일부 주요 카운터를 보여줍니다. 강조 표시된 카운터는 초당 요청입니다. 스크린 샷의 오른쪽에서 초당 요청 수 그래프가 실제로 불규칙 해지는 것을 볼 수 있습니다. 응답 시간이 느린 주요 지표입니다. 이 패턴을 보자 마자 부하 테스트에서 응답 시간이 느립니다.

초당 요청이 강조 표시된 perfmon 스크린 샷

이 성능 문제를 해결하려면 어떻게해야합니까? 코딩 문제인지 구성 문제인지 확인하려고합니다. web.config 또는 IIS에이 동작을 설명 할 수있는 설정이 있습니까? 응용 프로그램 풀이 .NET v4.0을 실행 중이고 IIS 버전은 7.5입니다. 기본 설정에서 변경된 유일한 사항은 응용 프로그램 풀 큐 길이 값을 1,000에서 5,000 으로 업데이트하는 것 입니다. 또한 Aspnet.config 파일에 다음 구성 설정을 추가했습니다.

<system.web>
    <applicationPool 
        maxConcurrentRequestsPerCPU="5000"
        maxConcurrentThreadsPerCPU="0" 
        requestQueueLimit="5000" />
</system.web>

자세한 내용은:

API의 목적은 다양한 외부 소스의 데이터를 결합하고 JSON으로 반환하는 것입니다. 현재 데이터 계층에서 개별 외부 호출을 캐시하기 위해 InMemory 캐시 구현을 사용하고 있습니다. 리소스에 대한 첫 번째 요청은 필요한 모든 데이터를 가져오고 동일한 리소스에 대한 후속 요청은 캐시에서 결과를 얻습니다. 우리는 특정 설정된 간격으로 캐시의 정보를 업데이트하는 백그라운드 프로세스로 구현되는 '캐시 러너'를 가지고 있습니다. 외부 리소스에서 데이터를 가져 오는 코드 주위에 잠금을 추가했습니다. 또한 외부 소스에서 데이터를 비동기 방식으로 가져 오는 서비스를 구현하여 엔드 포인트가 가장 느린 외부 호출만큼 느려 야합니다 (물론 캐시에 데이터가없는 경우). 이것은 System.Threading.Tasks.Task 클래스를 사용하여 수행됩니다.프로세스에서 사용할 수있는 스레드 수의 측면에서 제한을 맞출 수 있습니까?


5
CPU에는 몇 개의 코어가 있습니까? 아마도 하나의 코어를 최대한 사용하고있을 것입니다. 매직 수가 50 %, 25 % 또는 12.5 % 인 경우 코어를 최대로 사용 했으므로 유휴 상태 인 다른 코어를 사용할 수 없습니다. 최대 코어를 확인하십시오.
David Schwartz

1
요청 당 하나의 스레드가 있습니까? 5000 개의 요청에 대해 5000 개의 스레드가 있습니까? 그렇게하면 문제 일 가능성이 큽니다. 대신 스레드 풀을 작성하고 스레드 풀을 사용하여 요청을 처리하여 요청이 스레드 풀에 들어올 때 큐에 넣어야합니다. 스레드가 요청을 마치면 큐에서 요청을 처리 할 수 ​​있습니다. 이런 종류의 토론은 stackoverflow에 가장 적합합니다. 스레드가 너무 많으면 컨텍스트 스위치가 너무 많은 것입니다.
Matt

1
여기에 온전한 점검이 필요합니다. 모든 백그라운드 프로세스를 끄고 캐시에서 정적 데이터를 반환하는 JSON의 동작이 무엇인지 보셨습니까? 즉, JSON을 정적 데이터로 요청하고 캐시를 완전히 새로 고치는 "외부 비동기 호출"을 제거하십시오. 또한 모든 요청에서 제공되는 JSON 데이터의 양에 따라 네트워크 처리량과 서버가 데이터를 충분히 빨리 푸시 할 수 없기 때문에 요청이 백업되기 시작하는지에 대해 생각해 보셨습니까?
Robert

1
위의 Davids 제안에 +1. 실제로 테스트를 다시 실행하고 각 핵심 활용을주의 깊게 살펴 봐야합니다. 다른 것이 없다면 최대한 빨리 제거하는 것이 좋습니다. 두 번째로, 나는 당신의 캐시를 조금 의심합니다. 잠금 경합은 이러한 종류의 동작을 정확하게 보여줄 수 있습니다. 일부 임계점 잠금에서는 지연이 발생하여 잠금이 평상시보다 오랫동안 유지되어 내리막 길이 빠르게 내리는 지점이 발생합니다. 캐싱 및 잠금 코드를 공유 할 수 있습니까?
스티브 쿡

1
서버의 디스크 설정은 무엇입니까 (로드 균형 조정이 완료되었으므로 디스크 설정이 동일하다고 가정)? 초기 게시물에 드라이브 / 서버에 대한 모든 사양을 게시 할 수 있습니까? IIS 및 IIS 로그 파일이 존재하는 실제 드라이브의 디스크에서 perfmon을 발생 시켰습니까? 3,500 개의 요청 = 3,500 개 이상의 IIS 로그 전체에서 디스크에 문제가있을 수 있습니다. 동일한 디스크 / 파티션에 있으면 큰 문제가있을 수 있습니다.
Techie Joe

답변:


2

@DavidSchwartz 및 @Matt와 함께 이것은 스레드처럼 보이며 관리 문제를 잠급니다.

나는 제안한다 :

  1. 외부 호출과 호출을 위해 생성 된 캐시를 고정하고 정적 외부 정보로로드 테스트를 실행하여 서버와 관련이없는 문제를 버립니다.

  2. 스레드 풀을 사용하지 않는 경우 사용하십시오.

  3. 외부 통화 정보 "우리는 외부 소스에서 데이터를 비동기 방식으로 가져 오는 서비스를 구현하여 엔드 포인트가 가장 느린 외부 호출만큼 느려 야합니다 (물론 캐시에 데이터가없는 경우). "

질문은 다음과 같습니다.-외부 통화 중 또는 외부 통화 결과를 캐시에 쓸 때만 캐시 데이터가 잠겨 있는지 확인 했습니까? (너무 명백하지만 말해야 함). -당신은 전체 캐시 또는 작은 부분을 잠그나요? (너무 명백하지만 말해야 함). -비동기식이라하더라도 얼마나 자주 외부 호출이 실행됩니까? 자주 실행되지 않더라도 캐시가 잠겨있는 동안 사용자 호출에서 캐시에 대한 과도한 요청으로 인해 차단 될 수 있습니다. 이 시나리오는 많은 스레드가 고정 된 간격으로 대기하고 "잠금"도 관리해야하기 때문에 일반적으로 사용 된 고정 된 CPU 백분율을 보여줍니다. -느린 시나리오에 도달하면 외부 작업이 응답 시간도 증가하는지 확인 했습니까?

문제가 계속 지속되면 Task 클래스를 피하고 사용자 요청을 관리하는 동일한 스레드 풀을 통해 외부 호출을 수행하는 것이 좋습니다. 이것은 이전 시나리오를 피하기위한 것입니다.

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