포스트

H2 Server

리눅스 환경에서 Modern C++(C++17)을 활용하여 개발한 epoll, mmap, NGHTTP2, OpenSSL 기반의 고성능 http/2 서버

H2 Server
구분내용
플랫폼Linux
개발 도구 및 사용 언어g++ 11.4.0, C++, Socket(epoll), nghttp2 v1.60.0, OpenSSL v3.0.2
개발 기간2025년 3월 ~ 2025년 10월
저장소바로 가기

1. 개요

oveview

h2-serverModern C++(C++17) 기반의 고성능 HTTP/2 서버 이다.
Linux에서 epoll(Edge-Triggered) 로 비동기 통신을 처리하고, nghttp2 + OpenSSL 을 통해 HTTP/2의 요청/응답을 처리한다.
또한 H2C(평문) 모드와 mmap 기반 파일 캐시를 지원하여 저지연 업/다운로드 기능을 제공한다.
프로그램은 내부적으로 eventfd 기반의 worker 구조로써 acceptor와 worker로 나뉘어져 동작하며
acceptor에서 worker로의 작업 요청은 load balancer에 의해 분산 되어 SPSC(Single Producer Single Consumer) 구조의 lock-free 큐를 통해 전달 된다.

1.1. 빌드

1.1.1. 소스 코드 빌드

1
2
3
4
5
6
7
# (예) 빌드
cd src
make

# (예) 정리
cd src
make clean

1.1.2. 도커로 빌드

프로젝트를 도커 이미지로 빌드하려면 프로젝트 루트(최상위 디렉터리) 를 다음과 같이 빌드 컨텍스트 위치로 지정해야 한다.
(docker_build/src/가 함께 위치한 상위 경로)

1
docker build -t h2-server -f ./docker_build/Dockerfile .

1.2. 실행

1.2.1. 빌드 후 직접 실행

1
2
3
4
5
6
7
# TLS (기본값 포트 443)
cd src
./h2server --port 443 --key ./cert/server.key --cert ./cert/server.crt --threads 4

# H2C (평문)
cd src
./h2server --port 8080 --h2c --threads 4

1.2.2. 도커로 실행

도커로 실행할 때는 환경 변수로 기본 동작을 제어 한다.

환경 변수설명
RUN_MODE실행 모드: h2(TLS) 또는 h2c(평문)
PORT서버 리스닝 포트 (예: 443, 8080)
THREADS워커 스레드 수

1) 단일 컨테이너 실행

  • TLS(H2) 예시
1
docker run -d --name h2server -e RUN_MODE=h2 -e PORT=443 -e THREADS=4 -p 443:443  h2-server
  • 평문(H2C) 예시
1
docker run -d --name h2server-h2c -e RUN_MODE=h2c -e PORT=8080 -e THREADS=4   -p 8080:8080   h2-server

2) docker compose로 실행

docker_build/docker-compose.yml 예시:

1
2
3
4
5
6
7
8
9
  h2_server:
    image: h2-server
    environment:
      - RUN_MODE=h2
      - PORT=443
      - THREADS=4
    ports:
      - 0.0.0.0:443:443
      - :::443:443

실행:

1
2
cd docker_build
docker-compose up -d

H2C로 실행하려면 위 compose 파일에서 RUN_MODE: "h2c", PORT: "8080", ports: ["8080:8080"] 로 변경 하면 된다.

1.3 핸들러 사용법

등록

1
2
server.add_handler(GET,  "/files/{file_name}", downloader);
server.add_handler(POST, "/files",            uploader);

Request API

함수설명
reply_ok()바디 없이 :status=200 응답 전송
reply_ok_with_file()FileContext를 data source로 연결해 파일 응답
reply_404()간단한 404 HTML 바디와 함께 :status=404 전송

예시

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int downloader(Request& request) {
    StreamData* stream_data = request.stream_data;
    const std::string& rel_path = request.rel_path;

    if (rel_path.empty()) {
        return request.reply_404();
    }
    auto file = load_file_from_filecache(rel_path);
    if (!file) {
        return request.reply_404();
    }

    stream_data->file_ctx.data = file->get_data();
    stream_data->file_ctx.size = file->get_data_len();
    return request.reply_ok_with_file();
}

2. 자료 구조 (Data Structure Overview)

uml

2.1. 주요 자료 구조

1) StreamData — 스트림 레벨 컨텍스트

1
2
3
4
5
6
7
8
9
class StreamData {
public:
    uint32_t stream_id;
    METHOD method;
    std::string request_path;
    FileContext file_ctx;
    std::unique_ptr<MultipartFormParser> mime_parser;
    std::vector<uint8_t> upload_file_buffer;
};

2) SessionData — 세션(소켓) 레벨 컨텍스트

1
2
3
4
5
6
7
8
9
10
11
class SessionData {
public:
    const Router* router;
    std::list<std::unique_ptr<StreamData>> streams;
    nghttp2_session* session;
    std::vector<uint8_t> output_buffer;
    std::vector<uint8_t> input_buffer;
    uint32_t events;
    SessionState state;
    SSL* ssl;
};

3) Server — accept/분배 + 워커 관리

1
2
3
4
5
6
7
8
9
class Server {
private:
    Router router;
    std::vector<Worker> workers;
    std::vector<std::thread> threads;
    LoadBalancer load_balancer;
    int epfd, server_sock;
    struct sockaddr_in addr;
};

4) Worker — 이벤트 루프 & nghttp2/TLS I/O

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Worker {
private:
    const Router* router;
    std::function<bool(uint32_t)> check_rd_hup;
    std::function<void(int, std::shared_ptr<SessionData>)> update_events;
    std::function<IOResult(int, std::shared_ptr<SessionData>)> fill_input_buffer;
    std::function<IOResult(int, std::shared_ptr<SessionData>)> flush_output_buffer;

    std::mutex m;
    int signal_fd, epfd;
    bool use_tls;
    SSL_CTX* ssl_ctx;

    std::queue<int> socket_queue;
    std::unordered_map<int, std::shared_ptr<SessionData>> session_map;
};

5) Router — 정적/파라미터 경로 트리

1
2
3
4
5
6
7
8
9
10
11
12
class RouterNode {
public:
    std::unordered_map<std::string, std::unique_ptr<RouterNode>> static_children;
    std::unique_ptr<RouterNode> param_child;      // 같은 레벨에서 파라미터 노드는 1개 제한
    std::string param_child_name;                 // ex) "{id}" -> "id"
    std::array<Handler, METHOD_MAX> handlers;     // GET/POST 등
};

class Router {
private:
    RouterNode root_node;
};

6) File Cache — mmap 기반 zero-copy 지향

1
2
3
4
5
6
7
8
9
10
11
12
class FileContext {
public:
    size_t size;
    int offset;
    const char* data;
};

class MappedFile {
public:
    void*  data;     // mmap 주소
    size_t data_len;
};

3. 모듈 구조 (Module Architecture)

아래는 모듈 간 주요 데이터 플로우이다.

module flow

3.1. Server

  • --threads 개수만큼 Worker 생성 및 초기화
  • accept된 클라이언트 소켓을 LoadBalancer를 이용하여 각 Worker 큐에 분배
    (eventfd를 통해 워커를 깨워 즉시 처리)

3.1.1. LoadBalancer

다음은 Server 내에 위치하여 입력되는 client 연결 요청을 받아 각 Worker로 분배하는 로드 밸런서이다.

load_balancer

로드 밸런서는 입력된 요청을 받아 해시 연산을 통해 Indirect Table을 참조하여 요청을 전달 할 Worker Queue의 번호를 얻는다.
이때의 Worker Queue는 SPSC(Single Producer Single Consumer) 구조의 lock-free Queue 로써,
그 Worker Queue에 여유가 있는 경우 그대로 요청을 전달 한다.
그러나 만약 선택된 Worker Queue 가 full인 경우, 다른 여유가 있는 Worker Queue를 Round Robin 스케쥴링을 통해 찾아 작업을 요청한다.

이때, 선택된 Worker Queue의 번호는 hash 연산을 통해 접근된 indirect_table의 entry에 갱신 된다.
그리고 이후 이 entry에 접근하는 요청은 새롭게 선택된 Worker Queue로 전달 되게 된다.

만약, Round Robin 스케쥴링을 통해 Worker Queue 들을 한 바퀴 순회 하였음에도 여유 있는 Worker Queue를 발견하지 못하는 경우에는 해당 요청은 버려진다.

  • 새롭게 생성된 클라이언트 소켓에 대해 modular 연산을 수행하여 indirect_table의 인덱스 값으로 변환
  • indirect_table의 엔트리에 있는 Worker Queue 번호를 획득
    • 최초 indirect_table에는 Worker Queue의 번호가 순서대로 반복 입력 되어 있다.
  • Worker Queue 가 full이 아니라면, 해당 worker queue로 클라이언트 소켓을 전달한다.
    • 만약 Worker Queue 가 full 인 경우, Round Robin 스케쥴링을 통해 여분의 Worker Queue 를 찿는다.
      • 이것은 일종의 fallover 동작으로 볼 수 있다.
      • 여분의 Worker Queue 발견 시 방금 접근 했던 indirect_table의 엔트리에 Queue 번호 값을 갱신한다.
      • 새롭게 선택된 Worker Queue에 클라이언트 소켓을 전달 한다.
    • 만약 여력이 있는 Worker Queue 를 발견하지 못한 경우 생성된 소켓을 close 한다.

3.2. Worker

  • 큐로 전달받은 소켓을 epoll에 등록하고, TLS 핸드셰이크(옵션)nghttp2 세션을 초기화
  • 이벤트 처리:
    • handle_read: fill_input_bufferfeed_input_buffer(nghttp2_session_mem_recv2) → 콜백 체인
    • handle_write: fill_output_buffer(nghttp2_session_mem_send2)flush_output_buffer
    • check_rd_hup: FIN(RDHUP) 감지 시 안전 종료

3.2.1. worker 내 buffer 처리와 nghttp2 callback 함수들의 호출 flow

h2_server_worker_callback_flow

3.2.2. 주요 함수 호출 체인

| 함수명 | 의미 | 트리거 | | :—————————- | :——————- | :——————————- | | fill_input_buffer | 소켓을 통해 수신된 데이터들을 읽어 수신 버퍼에 저장 | 수신 소켓에서 이벤트 발생 시 | |feed_input_buffer| 채워진 수신 buffer 내 내용을 nghttp2 세션 데이터로 feed 할 준비| 더이상 소켓에서 수신할 데이터가 없는 경우 | | nghttp2_session_mem_recv2 | 채워진 buffer 내 데이터들을 nghttp2 라이브러리로 feed | 수신 버퍼에 데이터가 존재하는 경우 | | nghttp2_submit_response2 | 전송할 응답 프레임을 전송 대기큐로 큐잉, data_prd 존재 시 DATA 프레임 생성 | 응답 메시지 전송을 위해 직접 호출 | | nghttp2_session_mem_send2 | 전송 대기 큐 내 응답 프레임을 전송 할 수 있게 직렬화 화여 포인터 반환 | 응답할 수 있는 데이터 존재 시 | |fill_ouput_buffer|포인터가 가리키는 직렬화된 데이터를 출력 버퍼로 복사|| | flush_output_buffer | 출력 버퍼 내 데이터를 소켓을 통해 전송 | 직접 호출 |

3.2.3 .주요 nghttp2 콜백 함수들

함수명의미트리거
on_begin_headers_callback헤더 블록 수신 시작mem_recv2()
on_header_callback헤더 name/value 수신헤더 수신 때마다 반복
on_data_chunk_recv_callbackDATA 바디 청크 수신DATA 프레임 수신 중 반복
on_frame_recv_callback프레임 수신 완료요청 완료 시 Router→Handler 호출
on_stream_close_callback스트림 종료스트림 close 요청 수신 시

3.2.2 TLS(SSL_CTX)

  • ALPN 협상에서 h2만 수락(미지원 시 종료)
  • TLS 미사용(H2C) 모드에서는 ALPN 협상 생략

3.3 Router

다음 4개 경로가 등록되면 트리는 다음과 같은 형태로 구성된다.

1
2
3
4
POST /files/images/{file_name} : handler_b
GET  /files/docs/{file_name}   : handler_c
POST /users/{user_num}         : handler_d
GET  /files/images/{file_name} : handler_a

routing_tree

  • 정적 경로 우선 → 없으면 파라미터 경로 탐색
  • 핸들러는 프로그램 구동 시에만 등록(런타임엔 읽기 전용)

3.4 File Cache

filecache

  • 디스크 병목 완화 목적의 mmap 캐시
  • 주의: 동일 파일에 대한 동시 쓰기 시 경쟁/일관성 문제가 발생할 수 있으므로 운영 시 동기화 정책이 필요하다.

3.5 Multipart Form Parser

  • 업로드 요청 처리: multipart/form-data → 파일 추출
  • 플로우: boundary 파싱 → filename 추출 → temp 쓰기 → 종료 시 rename
  • temp 파일명: h2_tmp_<thread_id>_<count>

3.6 Config Option

FlagType / DefaultDescription
-p, --port <NUM>integer / 443리스닝 포트
-k, --key <PATH>path / ./cert/server.keyTLS 개인키(PEM). --h2c면 불필요
-c, --cert <PATH>path / ./cert/server.crtTLS 인증서(PEM). --h2c면 불필요
-n, --threads <NUM>integer / 1워커 스레드 수
--h2cflagHTTP/2 cleartext 모드
-h, --helpflag도움말 출력

4. 성능 측정 (Benchmark)

4.1 개선 단계별 성능 변화

Prototype → mmap(파일 캐시) 적용 → TLS(https) 적용 → Router 적용 → socket port reuse 멀티스레딩 구조 적용 → acceptor/worker 멀티스레딩 구조 적용 -> Load Balancer 적

주: mmap 도입 전 -c1000 -m100에서는 FD 제한(기본 1024)으로 성공률이 0.1%에 불과.
동일 이슈는 libevent-server, nghttpd(≥8 threads)에서도 관측되어 ulimit -n 상향으로 대응.

1) h2load -c100 -m10


ServerQPSP99 Latency (ms)P90 Latency (ms)P50 Latency (ms)CPU Usage (%)Mem Usage (MB)
Prototype122060.23210.6748.92488.067498.4127.451171875
with MMAP (h2c)224543.53.78082.91482.481689.63220.30703125
with MMAP + TLS190543.6346.3274.6263.07492.72815.84726563
Router (TLS)175203.9347.38685.81764.742498.97415.94824219
Router (h2c)199643.80.0063270.0046260.00307492.7280.015475845
LoadBalancer (TLS)173702.0987.3065.95625.024899.20818.12
LoadBalancer (h2c)192895.7666.70445.50924.521899.0789.565039063

http2 서버 스크린샷 1
http2 서버 스크린샷 2
http2 서버 스크린샷 3
http2 서버 스크린샷 4

2) h2load -c1000 -m100


ServerQPSP99 Latency (ms)P90 Latency (ms)P50 Latency (ms)CPU Usage (%)Mem Usage (MB)
Prototype108745.666968.666891.9512740.180485.97876.84316406
with MMAP (h2c)361051.334290.2608276.253270.298899.23684.17207031
with MMAP + TLS340922.308324.6172290.5728277.594899.892125.9441406
Router (TLS)218128.414505.9948473.1074458.96899.81140.4175781
Router (h2c)226110.666486.169453.9088448.780699.53698.51445313
Load Balancer (TLS)205574.332547.7828508.3812486.718299.942141.19
Load Balancer (h2c)221886.068514.821474.6454445.100699.93896.4296875

http2 서버 스크린샷 5
http2 서버 스크린샷 6
http2 서버 스크린샷 7
http2 서버 스크린샷 8

4.1.1 Socket Port Reusing vs Acceptor/Worker

개요

SO_REUSEPORT 옵션을 사용하면 동일한 포트 번호에 대해 여러 개의 리스닝 소켓을 동시에 bind 할 수 있다.
본 HTTP/2 서버 아키텍처에서는 다음 두 가지 모델을 비교하였다.

  • Socket Port Reusing 방식 (커밋 해시: b2985a2d81e4db92e00b7171dd9ebb93b4bc2df3)
  • Acceptor/Worker 방식 (커밋 해시: db6af3ddcdcf329e5a72bc0df9b7c236284df795)

💡 참고: 본 절의 내용과 수치는 Load Balancer 도입 이전 버전을 기준으로 한다.

Socket Port Reusing 방식

http2 서버 스크린 57

참고: Socket Port Reusing 방식은 현재 버전의 구조를 갖추기 이전에 사용되었던 설계이며,
해당 구현은 커밋 해시 e4c03916b3ca61d2a82fe72fe4b67f0ddd75ab05 에 포함되어 있다.

특징

  • 각 스레드 또는 프로세스가 독립적인 리스닝 소켓을 생성하고 SO_REUSEPORT를 설정함.
  • 커널은 동일 포트에 바인딩된 소켓들을 reuseport 그룹으로 묶어 관리.
  • 커널이 접속 요청을 리스닝 소켓 단위로 로드밸런싱해 분배함.

장점

  • 구현 난이도가 낮고 구조가 단순함.
  • Accept 경합을 줄여 락 경쟁이 거의 없음.
  • 커널 내에서 로드밸런싱이 수행 됨.

단점

  • 애플리케이션 레벨에서 연결 분배를 직접 제어하기 어려움.
  • 서버 구조가 커지면 역할 분리·모듈성 측면에서 확장성이 떨어짐.

Acceptor/Worker 방식

http2 서버 스크린 58

특징

  • Acceptor 스레드
    • 오직 accept()만 담당
    • 새 연결 생성 후 그 FD를 worker에 전달
  • Worker 스레드
    • Session(HTTP/2 프레임 처리, SSL, I/O 등) 전담

장점

  • 역할 분리가 명확해 구조적 일관성/가독성 우수.
  • 애플리케이션 레벨에서 connection dispatch 전략을 자유롭게 설계 가능.
  • 확장성 및 유지보수성이 매우 높음.

단점

  • 구현 복잡도가 socket reuseport 방식보다 높음.
  • inter-thread communication(파이프/lock-free 큐 등) 필요.

결론

두 구조는 성능적으로 유사하지만, 본 프로젝트에서는 다음과 같은 이유로 Acceptor/Worker 구조를 택함.

  • 역할 분리 및 모듈성 우수
  • 유지보수 용이
  • 구조 확장에 유리
  • Session 핸들링 로직이 Worker로 집중되어 코드 가독성 및 명확성 증가

4.1.1.1 H2

1) h2load -c100 -m10

Port reusing

ThreadsQPSP99 Latency (ms)CPU Usage (%)Mem Usage (MB)
1170082.7687.883898.85216.43515625
2191969.94.9168138.79215.86367188
4185166.9684.157146.41815.86210938
8179178.12753.8758162.19615.91289063

Acceptor/worker

ThreadsQPSP99 Latency (ms)CPU Usage (%)Mem Usage (MB)
1186105.49.007698.95615.99785156
2195737.55.7036143.21415.89492188
4179277.3683.4026149.85615.87246094
8183349.3683.3312169.315.98984375

http2 서버 스크린샷 9
http2 서버 스크린샷 11
http2 서버 스크린샷 13
http2 서버 스크린샷 15


2) h2load -c1000 -m100

Port reusing

ThreadsQPSP99 Latency (ms)CPU Usage (%)Mem Usage (MB)
1220103.334495.866699.726141.2958984
2399747.666298.155187.066136
4421299.026160.2804204.244126.6503906
8417792.915157.9678209.762126.0441406

Acceptor/worker

ThreadsQPSP99 Latency (ms)CPU Usage (%)Mem Usage (MB)
1217159.334510.086899.846140.0394531
2389953.44295.7502186.524139.2839844
4426597.082153.9212208.794128.4552734
8423505.2148.8116210.396128.0207031

http2 서버 스크린샷 10
http2 서버 스크린샷 12
http2 서버 스크린샷 14
http2 서버 스크린샷 16


4.1.1.2 H2C

1) h2load -c100 -m10

Port reusing

ThreadsQPSP99 Latency (ms)CPU Usage (%)Mem Usage (MB)
1196712.6666.994898.7589.514257813
2220055.0944.6052146.1569.423828125
4214679.3343.329151.4049.4296875
8207702.4943.5508164.4889.51796875

Acceptor/worker

ThreadsQPSP99 Latency (ms)CPU Usage (%)Mem Usage (MB)
1199005.8346.342899.079.519335938
2219053.9344.0376140.3089.49453125
4210013.1023.3358143.3449.295898438
8209466.563.5956166.5629.462109375

http2 서버 스크린샷 17
http2 서버 스크린샷 19
http2 서버 스크린샷 21
http2 서버 스크린샷 23

2) h2load -c1000 -m100

Port reusing

ThreadsQPSP99 Latency (ms)CPU Usage (%)Mem Usage (MB)
1224862.99384.241699.62676.52480469
2404943.208307.5908192.0694.28222656
4438058.332160.4104217.45489.04765625
8435534156.368218.66681.909375

Acceptor/worker

ThreadsQPSP99 Latency (ms)CPU Usage (%)Mem Usage (MB)
1225519.504501.166899.72497.57636719
2406958.212281.1706187.63294.61152344
4451179153.3158214.99889.13046875
8445782.332146.397219.95880.2796875

http2 서버 스크린샷 18
http2 서버 스크린샷 20
http2 서버 스크린샷 22
http2 서버 스크린샷 24

4.2 서버 프로그램 간 성능 비교

  • h2server commit: c34cd1d9ce9
  • nghttpd: nghttp2 v1.60.0
  • libevent-server: nghttp2 v1.60.0

요약:

  • nghttpd는 스레드 증가에 따른 메모리 안정성이 높지만 성능 스케일링 이득은 제한적
  • h2server는 스레드 증가와 함께 CPU/메모리 사용량이 증가하나 처리량도 동반 증가

4.2.1. Single Thread

2server, nghttpd, libevent 간 성능을 비교.
libevent의 경우 h2c 모드를 지원하지 않으므로 h2 테스트에서는 제외.

4.2.1.1. H2


1) h2load -c100 -m10

ServerQPSP99 Latency (ms)P90 Latency (ms)P50 Latency (ms)CPU Usage (%)Mem Usage (MB)
h2server173702.097.305.95625.0299.2018.12
Libevent-server154655.110.077.185.5098.0215.41
nghttpd1816806.084.152.7990.94218.23

http2 서버 스크린샷 25
http2 서버 스크린샷 26
http2 서버 스크린샷 27
http2 서버 스크린샷 28

2) h2load -c1000 -m100

ServerQPSP99 Latency (ms)P90 Latency (ms)P50 Latency (ms)CPU Usage (%)Mem Usage (MB)
h2server205574.33547.78508.38486.7199.94141.19
Libevent-server204798.99541.53507.15479.8999.9195.45
nghttpd321848.43235.78166.42157.6185.59112.38

http2 서버 스크린샷 29
http2 서버 스크린샷 30
http2 서버 스크린샷 31
http2 서버 스크린샷 32

4.2.1.2. H2C


1) h2load -c100 -m10

ServerQPSP99 Latency (ms)P90 Latency (ms)P50 Latency (ms)CPU Usage (%)Mem Usage (MB)
h2server192895.766.705.504.5299.079.56
nghttpd205405.525.653.942.4891.7714.84

http2 서버 스크린샷 33
http2 서버 스크린샷 34
http2 서버 스크린샷 35
http2 서버 스크린샷 36

2) h2load -c1000 -m100

ServerQPSP99 Latency (ms)P90 Latency (ms)P50 Latency (ms)CPU Usage (%)Mem Usage (MB)
h2server221886.06514.82474.64445.1099.9396.42
nghttpd375828.33254.24213.16134.7991.0475.29

http2 서버 스크린샷 37
http2 서버 스크린샷 38
http2 서버 스크린샷 39
http2 서버 스크린샷 40

4.2.2 스레드 스케일링 비교

  • libevent-server는 멀티스레드 미지원 → 제외
  • nghttpd는 8스레드에서 FD 부족 이슈 → ulimit -n 65535로 상향하여 측정

4.2.2.1 H2

1) h2load -c100 -m10

h2server

ThreadsQPSP99 Latency (ms)CPU Usage (%)Mem Usage (MB)
1173702.0987.30699.20818.12363281
2187681.7344.2538139.28818.12070313
4178973.0324.4518155.9118.06914063
8172458.5854.4838166.85418.3203125

nghttpd

ThreadsQPSP99 Latency (ms)CPU Usage (%)Mem Usage (MB)
11816806.08390.94218.22597656
2179038.5664.3452108.58518.2668457
4174970.7644.2538119.61418.61054688
8171352.5024.23130.347519.821875

http2 서버 스크린샷 41
http2 서버 스크린샷 43
http2 서버 스크린샷 45
http2 서버 스크린샷 47


2) h2load -c1000 -m100

h2server

ThreadsQPSP99 Latency (ms)CPU Usage (%)Mem Usage (MB)
1205574.332547.782899.942141.1904297
2393091.732305.2898194.396136.2841797
4403797.186157.3542203.208141.8414063
8404569.212152.979214.93143.1271484

nghttpd

ThreadsQPSP99 Latency (ms)CPU Usage (%)Mem Usage (MB)
1321848.43235.78885.59112.3808594
2358788.664188.0264105.616116.7830078
4367662.9177.935113.07115.0414063
8348835.566182.8562122.024112.4423828

http2 서버 스크린샷 42
http2 서버 스크린샷 44
http2 서버 스크린샷 46
http2 서버 스크린샷 48


4.2.2.2 H2C

1) h2load -c100 -m10

h2server

ThreadsQPSP99 Latency (ms)CPU Usage (%)Mem Usage (MB)
1192895.7666.704499.0789.565039063
2216457.44.2202148.0569.491796875
4202325.6343.7672154.1269.574414063
8199447.333.4988168.019.599609375

nghttpd

ThreadsQPSP99 Latency (ms)CPU Usage (%)Mem Usage (MB)
1205405.5245.656291.7714.84101563
2198241.1983.7884104.03612.01835938
4195620.473.8596115.08212.3109375
8192671.31173.5740383118.582833311.59673754

http2 서버 스크린샷 49
http2 서버 스크린샷 51
http2 서버 스크린샷 53
http2 서버 스크린샷 55


2) h2load -c1000 -m100

h2server

ThreadsQPSP99 Latency (ms)CPU Usage (%)Mem Usage (MB)
1221886.068514.82199.93896.4296875
2410807.138274.1966193.75694.84179688
4428543.664154.3328219.2291.43515625
8429380144.1536225.90281.98554688

nghttpd

ThreadsQPSP99 Latency (ms)CPU Usage (%)Mem Usage (MB)
1375828.332254.246691.04875.29472656
2377719243.627687.61275.25371094
4400143.366241.793290.76875.19921875
8352529.364264.866285.35275.21660156

http2 서버 스크린샷 50
http2 서버 스크린샷 52
http2 서버 스크린샷 54
http2 서버 스크린샷 56

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.