문제

Boost :: ASIO를 사용하여 C ++에서 미니 HTTP 서버를 개발했으며 이제 여러 클라이언트로로드 테스트를하고 CPU를 포화 할 수 없었습니다. Amazon EC2 인스턴스에서 테스트하고 있으며 한 CPU의 약 50% 사용량, 다른 CPU의 20%, 나머지 2 개는 유휴 상태입니다 (HTOP에 따라).

세부:

  • 서버는 코어 당 하나의 스레드를 발사합니다
  • 요청이 접수, 구문 분석, 처리 및 응답이 기록됩니다.
  • 요청은 데이터에 대한 것이며 메모리에서 읽습니다 (이 테스트의 경우 읽기 전용)
  • 나는 각각 Java 애플리케이션을 실행하고 25 개의 스레드를 실행하고 요청을 보내는 두 개의 기계를 사용하여 서버를 '로드'하고 있습니다.
  • 약 230 개의 요청/SEC 처리량을보고 있습니다 (이것은 신청 많은 HTTP 요청으로 구성된 요청)

그렇다면이 결과를 개선하려면 무엇을 살펴 봐야합니까? CPU가 대부분 유휴 상태이므로 800 개의 요청/초 등에서 더 높은 처리량을 얻기 위해 추가 용량을 활용하고 싶습니다.

내가 가진 아이디어 :

  • 요청은 매우 작으며 종종 몇 ms에서 충족되기 때문에 클라이언트가 더 큰 요청을 보내거나 작성하도록 수정할 수 있습니다 (아마도 배치 사용).
  • 선택 설계 패턴을 사용하도록 HTTP 서버를 수정할 수 있습니다. 여기에서 적절합니까?
  • 병목 현상이 무엇인지 이해하려고 프로파일 링을 할 수 있습니다.
도움이 되었습니까?

해결책

Boost :: Asio는 당신이 바라는 것처럼 스레드 친화적이지 않습니다. epoll 코드 주위에 boost/asio/detall/epoll_reactor.hpp의 큰 잠금 장치가있어 한 번만 커널의 epoll syscall을 한 번에 호출 할 수 있습니다. . 그리고 매우 작은 요청의 경우, 이것은 모든 차이를 만듭니다 (즉, 대략 단일 스레드 성능 만 볼 수 있습니다).

이것은 Boost :: Asio가 Linux 커널 자체가 아니라 Linux 커널 시설을 사용하는 방법의 한계입니다. Epoll Syscall은 에지 트리거 이벤트를 사용할 때 여러 스레드를 지원하지만 과도한 잠금없이 올바르게 얻는 것은 매우 까다로울 수 있습니다.

BTW, 나는이 영역에서 약간의 작업을 해왔으며 (완전 다중 스레드 에지 트리거 이벤트 루프를 사용자 예약 된 스레드/섬유와 결합) nginetd 프로젝트.

다른 팁

EC2를 사용하면 모든 베팅이 꺼져 있습니다.

실제 하드웨어를 사용하여 시도하면 무슨 일이 일어나고 있는지 확인할 수 있습니다. VM에서 성능 테스트를 시도하는 것은 기본적으로 불가능합니다.

EC2가 유용한 것을 아직 해결하지 못했습니다. 누군가가 알게되면 알려주십시오.

네트워크 활용에 대한 귀하의 의견에서
네트워크 움직임이 많지 않은 것 같습니다.

3 + 2.5 MiB/sec 주위에 있습니다 50Mbps 볼 파크 (1GBPS 포트와 비교).

다음 두 가지 문제 중 하나를 가지고 있다고 말하고 싶습니다.

  1. 부족한 작업로드 (클라이언트의 요청율이 낮음)
    • 서버 차단 (간섭 응답 생성)

보고 있습니다 cmeerw메모와 CPU 활용 수치
(유휴 상태 50% + 20% + 0% + 0%)
서버 구현에서 제한이있을 것 같습니다.
나는 두 번째 cmeerw대답 (+1).

230 개의 요청/SEC는 이러한 간단한 ASYNC 요청에 대해 매우 낮은 것 같습니다. 따라서 여러 스레드를 사용하는 것은 아마도 조기 최적화 일 것입니다. 제대로 작동하고 단일 스레드로 조정하고 여전히 필요한지 확인하십시오. 필요없는 잠금을 제거하면 속도가 빨라질 수 있습니다.

이 기사 2003 년경 웹 서버 스타일 성능을위한 I/O 전략에 대한 세부 사항과 토론이 있습니다.

ASIO는 중소형 작업에 적합하지만 기본 시스템의 힘을 활용하는 데별로 능숙하지 않습니다. 원시 소켓 호출이나 창에서 IOCP도 아니지만 경험이 있다면 항상 ASIO보다 낫습니다. 어느 쪽이든 ASIO와 더 많은 방법으로 많은 오버 헤드가 있습니다.

가치가있는 것. 내 맞춤형 HTTP에서 원시 소켓 호출을 사용하면 4 개의 코어 i7로 초당 800K 동적 요청을 제공 할 수 있습니다. RAM에서 제공되는데,이 수준의 성능을 위해 필요한 곳입니다. 이 수준의 성능에서 네트워크 드라이버와 OS는 CPU의 약 40%를 소비하고 있습니다. ASIO를 사용하면 초당 약 50 ~ 100K 요청을받을 수 있습니다. 성능은 매우 가변적이며 대부분 내 앱에 묶여 있습니다. @cmeerw의 게시물은 주로 이유를 설명합니다.

성능을 향상시키는 한 가지 방법은 UDP 프록시를 구현하는 것입니다. HTTP 요청을 가로 채고 UDP를 통해 백엔드 UDP-HTTP 서버로 라우팅하면 운영 체제 스택에서 많은 TCP 오버 헤드를 우회 할 수 있습니다. 또한 UDP 자체에 파이프를 통과하는 프론트 엔드를 가질 수 있습니다. HTTP-UDP 프록시의 장점은 수정없이 좋은 프론트 엔드를 사용할 수 있으며 영향 없이도 마음대로 교환 할 수 있다는 것입니다. 구현하려면 몇 개의 서버가 더 필요합니다. 내 예에서 이러한 수정으로 OS CPU 사용량이 10%로 낮아져 초당 요청을 단일 백엔드에서 백만 명 이상으로 증가 시켰습니다. FWIW는 Prontends가 더 중요한 동적 요청 백엔드를 늦추지 않고 데이터를 캐시 할 수 있기 때문에 항상 모든 수행자 사이트에 대한 프론트 엔드-백엔드 설정이 있어야합니다.

미래는 자체 네트워크 스택을 구현하는 자체 드라이버를 작성하는 것으로 보이므로 가능한 한 요청에 가까워지고 자신의 프로토콜을 구현할 수 있습니다. 아마도 대부분의 프로그래머가 더 복잡하기 때문에 듣고 싶어하는 것이 아닐 것입니다. 제 경우에는 40% 더 많은 CPU를 사용하고 초당 백만 개 이상의 동적 요청으로 이동할 수 있습니다. UDP 프록시 방법을 사용하면이 작업을 수행 할 필요없이 최적의 성능에 가까워 질 수 있지만 더 많은 서버가 필요합니다.하지만 초당이 많은 요청을 수행하는 경우 일반적으로 대역폭을 처리하기 위해 여러 네트워크 카드와 여러 개의 프론트 엔드가 필요합니다. 거기의 가벼운 UDP 프록시는 큰 거래가 아닙니다.

이 중 일부가 당신에게 유용 할 수 있기를 바랍니다.

io_service의 인스턴스는 몇 개입니까? 부스트 ASIO에는 an이 있습니다 예시 그것은 CPU 당 io_service를 생성하고 라운드 로빈의 방식으로 사용합니다.

여전히 4 개의 스레드를 생성하고 CPU 당 하나를 할당 할 수 있지만 각 스레드는 자체 IO_Service에서 투표 할 수 있습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top