# cgi-bin으로 하루 2억 리퀘스트 서비스하기

> Clean Markdown view of GeekNews topic #21845. Use the original source for factual precision when an external source URL is present.

## Metadata

- GeekNews HTML: [https://news.hada.io/topic?id=21845](https://news.hada.io/topic?id=21845)
- GeekNews Markdown: [https://news.hada.io/topic/21845.md](https://news.hada.io/topic/21845.md)
- Type: GN+
- Author: [xguru](https://news.hada.io/@xguru)
- Published: 2025-07-07T09:16:53+09:00
- Updated: 2025-07-07T09:16:53+09:00
- Original source: [jacob.gold](https://jacob.gold/posts/serving-200-million-requests-with-cgi-bin/)
- Points: 7
- Comments: 4

## Summary

현대 **서버 하드웨어**에서 테스트한 결과, **CGI 방식**이 별도의 프로세스 기반 처리로 **초당 2,400건 이상, 하루 2억 건**의 웹 요청을 안정적으로 소화함을 입증합니다. 실험에 활용한 **guestbook CGI 예제**와 관련 **소스코드**는 오픈소스로 공개되어 있습니다. CGI는 **단순한 배포**와 **운영체제 차원의 자원 처리**를 장점으로, 여전히 실용적인 선택지가 될 수 있음을 확인합니다.

## Topic Body

- **초기 웹 시대**에 널리 쓰였던 **CGI 프로그램**이 현대 하드웨어에서 여전히 높은 성능을 낼 수 있음을 실험으로 확인함  
- **CGI는 프로세스별로 요청을 처리**해 메모리 관리가 자동으로 이뤄지고, 배포가 단순한 장점이 있음  
- **벤치마크 결과**, 평범한 16스레드 CPU 서버에서도 초당 2400건 이상, 하루 2억 건 이상 **요청 처리 가능성**을 입증함  
- Go 언어와 SQLite로 작성된 **guestbook.cgi** 예제 코드 및 Dockerfile을 오픈소스로 공개함  
- CGI는 지금은 흔히 쓰이지 않지만, **여전히 실용적이고 현대적인 대안**이 될 수 있음을 보여줌  
  
---  
  
### CGI 프로그램과 동작 원리  
  
- 2000년대 초반에는 **CGI(Common Gateway Interface) 프로그램**이 동적 웹사이트 구축의 주요 방식이었음  
- 대부분 **Perl**이나 **C 언어**로 작성되었으며, 성능 향상을 위해 C가 선택되기도 했음  
- CGI의 개념은 간단하지만 강력함  
  - 웹서버는 환경 변수에 요청 메타데이터(HTTP 헤더, 쿼리 등) 설정  
  - 별도의 프로세스 생성하여 CGI 프로그램 실행  
  - 요청 본문을 stdin으로 전달  
  - 프로그램의 stdout을 HTTP 응답으로 캡처  
  - stderr 출력을 서버 에러 로그로 전달함  
  - 프로그램이 요청을 마치면 프로세스가 종료되어 **파일 디스크립터 및 메모리가 자동 해제**됨  
- 개발자 입장에서는 신규 버전 배포도 **cgi-bin/ 디렉터리에 파일만 복사하면 배포가 끝나 매우 간단**했음  
  
  
### Hug of death(트래픽 폭주)  
  
- 2000년대 초반 웹서버 대부분은 1~2 CPU, 1~4GB 메모리 환경이 일반적임  
- Apache 웹서버가 접속마다 httpd 프로세스를 fork하는 구조 특성상, 다수 접속 시 메모리 요구량이 증가함  
- 동시 접속이 100개를 넘기 힘들었고, **유명 사이트에 링크만 걸려도 서버가 쉽게 과부하**되는 경우가 많았음   
  - ( **[Slashdot Effect](https://en.wikipedia.org/wiki/Slashdot_effect)** : 그 당시 유명했던 Slashdot에 링크가 올라오면 트래픽이 쏟아짐. 요즘의 해커뉴스 탑에 오르는 것과 비슷)  
  
### 현대 서버 환경에서의 CGI  
  
- 현재는 **384개의 CPU 스레드**를 가진 서버도 출현, 비교적 작은 VM에서도 16개의 CPU 제공 가능  
- CPU 및 메모리 성능이 대폭 향상됨  
- CGI 프로그램은 별도 프로세스 기반이므로 **멀티코어를 자연스럽게 활용 가능함**  
- 이러한 점 때문에 현대 하드웨어에서 CGI 프로그램이 얼마나 빠른지 직접 벤치마크 테스트를 진행함  
- 실험은 **AMD 3700X(16스레드)** 서버에서 수행함  
  
### 벤치마크 주요 결과  
  
- 간단한 CGI 프로그램을 **Apache**와 **Go `net/http` 서버** 환경 모두에서 테스트  
- # guestbook.cgi 프로그램 설명  
  - 방문자가 웹사이트 하단에 댓글을 남길 수 있는 간단한 방명록 프로그램 구현  
  - Go 언어와 SQLite 사용, 최대한 단순하지만 현실성 있도록 설계  
  - [소스코드와 Dockerfile 모두 GitHub에 공개함](https://github.com/Jacob2161/cgi-bin)       
- HTTP 부하 생성 도구 `plow` 를 사용해 **16개 연결로 10만 건씩 요청** 수행  
- 평범한 하드웨어상에서도 **초당 2,400건 이상**, 즉 **하루 2억 건 이상 요청 처리** 가능함  
- 현재 CGI가 대세는 아니나, 여전히 실제 서비스 운영에서도 사용 가능함  
- # Apache 환경에서의 write 벤치마크  
  - 초당 **약 2468건**의 요청 처리, 평균 **6.47ms**의 응답 지연 시간  
  - 10만 건의 POST 요청을 40.5초 만에 처리  
  - 대부분 요청이 7ms 내 응답, 극소수만 100ms 초과  
  - 실질적으로 높은 쓰기 처리 성능 입증  
- # Apache 환경에서의 read 벤치마크  
  - 초당 **약 1959건**의 요청 처리, 평균 **8.16ms**의 응답 지연 시간  
  - 10만 건의 GET 요청을 51초 만에 처리  
  - 절반 이상의 요청은 8ms 이내, 최대 지연도 31ms에 그침  
  - 읽기 성능 역시 충분히 우수함  
- # Go net/http 환경에서의 write 벤치마크  
  - 초당 **약 2742건**의 요청 처리, 평균 **5.83ms**의 응답 지연 시간  
  - 10만 건의 POST 요청을 36.4초 만에 처리  
  - 처리량은 평균 2,742 RPS, 평균 지연 5.8ms로 Apache보다 수치상 더 나은 성능  
  - 95% 이상의 요청이 6ms 이내 처리됨  
  - Go 환경에서의 CGI도 충분한 실전 성능 보유  
- # Go net/http 환경에서의 read 벤치마크  
  - 초당 **약 2469건**의 요청 처리, 평균 **6.47ms**의 응답 지연 시간  
  - 10만 건의 GET 요청을 40.4초 만에 처리    
  - 대부분의 요청이 7ms 안에 서비스 가능  
  - 읽기 처리량과 응답 속도 모두 Apache와 비슷하거나 우수함  
  
### 결론 및 링크  
  
- CGI 프로그램은 **최신 하드웨어**에서 **초고속 동시성, 간단한 배포, 운영체제가 자동 자원 해제** 등의 **장점** 보유  
- 현대적인 프레임워크에 비해 극히 단순하지만, 일정 규모 서비스에는 지금도 실전 활용 가능  
- 방명록 예제 및 벤치마크 실험 데이터는 아래 깃허브에 공개  
  https://github.com/Jacob2161/cgi-bin

## Comments



### Comment 41168

- Author: kansm
- Created: 2025-07-09T22:58:34+09:00
- Points: 1

헐.. cgi를 다시 사용하게 되는건가요?? ㅎㅎ  
와.. 언제적 cgi인지..

### Comment 41117

- Author: tujuc
- Created: 2025-07-08T23:34:03+09:00
- Points: 1

7/7일자로 업데이트된 내용이있군요.  
  
[Serving a half billion requests per day with Rust + CGI](https://jacob.gold/posts/serving-half-billion-requests-with-rust-cgi/)  
  
5억 리퀘스트라니...

### Comment 41032

- Author: neo
- Created: 2025-07-07T09:16:54+09:00
- Points: 1

###### [Hacker News 의견](https://news.ycombinator.com/item?id=44464272) 
- 1990년대에도 C로 작성된 CGI 프로그램이 정말 빠른 속도를 보여줬던 환경 기억, 그러나 에러가 많이 발생하는 점이 단점이었던 점 인정, 기사에 언급된 Go 프로그램이나 Nim 같은 최신 언어, 데이터베이스 연결을 하지 않는 한 로컬호스트에서 굉장히 빠르고 지연시간이 적은 느낌, 마치 CLI 유틸리티에서 fork & exec을 사용하는 기분, 네트워크 레이턴시에 비하면 비용이 거의 무시할 만한 수준이었음  
  - 다만 특정 기술에 중독되기 쉬운 문화 언급, 예를 들어 파이썬 인터프리터 같이 시작 비용이 큰 언어에 익숙해지고 나면 멀티샷 혹은 영속적인 모델을 필요로 하게 됨  
  - 초창기 HTTP의 원샷 모델은 FTP 서버가 수백 개의 유휴 로그인 세션을 오래 유지할 만큼의 메모리가 부족했던 문제에서 출발한 것이었음

  - CGI에서 pre-forking(지연을 숨길 수 있음)과 Rust 같은 안전한 언어를 결합하면 뛰어난 시스템 설계 가능성 언급, TLS 종단 처리는 멀티스레드 웹 서버(또는 CloudFront 같은 레이어)에서 처리할 수 있어 편리성 강조  
    - 상태가 남지 않고, 코어 덤프 및 디버그가 매우 쉬운 환경, 주로 선형적인 요청 모델로 확장도 간단하게 가능  
    - stdin에서 읽고 stdout으로 쓰기만 하면 되는 간결함을 찬양, Websockets가 복잡도를 조금 높이긴 하지만 걱정할 수준 아님  
    - Java의 부상으로 인해 fork()의 비용과 C의 위험성 회피 목적에서 애플리케이션 서버로의 전환이 급격히 진행된 흐름 상기, 이제 다시 단순성으로 돌아갈 수 있음 주장  
    - Rust를 좋아하지 않지만 이런 방식의 웹 백엔드 코드가 손쉽게 작성될 수 있는 시대가 오면 node/js, php, python 개발자들에게도 매력적으로 다가올 것 기대

- CGI 시절부터 개발을 시작하며 짧게 실행되는 서브프로세스를 돌리는 것에 대한 강한 반감을 가지게 된 경험  
  - PHP와 FastCGI가 웹 요청마다 신규 프로세스를 만드는 성능 문제를 벗어나기 위해 만들어졌다는 배경 설명  
  - 최근 하드웨어의 발달 덕분에, 프로세스 시작 비용이 실제로 큰 문제는 아니라는 현실을 알게 됨  
  - 이 벤치마크가 초당 2000개의 요청을 처리할 수 있고, 수백 개 정도만 처리해도 여러 인스턴스로 확장하기 쉬운 현대적 환경 언급  
  - AWS Lambda를 CGI 모델의 재탄생으로 묘사한 의견에 동의, 꽤 적절한 비유라고 생각함

  - 만약 CGI 스크립트를 정적 링크된 C 바이너리로, 크기까지 신경 쓰며 배포했다면 실망이 덜했을 것이라 언급  
    - PHP 해석기나 각종 라이브러리 로딩, 파일 파싱 등 동적 링크의 프로세스 시작 비용이 훨씬 큼  
    - Go를 쓴다는 것은 25년 전에도 충분히 경쟁력이 있을 수 있었던 방식이라 확신  
    - SQLite 데이터베이스 오픈이 컨텍스트 스위치로 소켓을 넘기는 것과 거의 비슷한 성능이며, 원격 mysql 접속과 비교하면 훨씬 빠른 점 강조  
    - FastCGI가 새로운 애플리케이션에도 여전히 뛰어난 선택임을 주장

  - CGI는 저부하 환경에서 금전적·성능적으로 부담이 크지 않았음  
    - 고부하 상황에서는 FastCGI처럼 지속적으로 실행되는 프로세스가 더 유리  
    - CGI도 초당 2,000 rps까지 처리 가능하지만, FastCGI는 훨씬 높은 성능 달성 가능  
    - 별도 서버 프로세스 추가 및 업그레이드 시점에 재시작만 하면 되는데, 성능이 중요할 때 가치 있다고 밝힘

  - Go가 등장하기 전에는 CGI 프로그램을 C/C++로 만드는 게 안전성, 개발 난이도 모두 높았던 00년대 상황  
    - Perl과 Python은 해석기 시작 및 컴파일 비용이 상당히 컸고, Java는 실질적으로 더 느렸음  
    - AWS Lambda = CGI 모델의 환생에 가깝다는 점 동의  
    - 지금은 관리형 FastCGI와 거의 동일한 모델로 돌아온 느낌  
    - 단순히 실행파일만 업로드해서 돌리면 될 텐데 복잡도를 잔뜩 추가하는 기술의 홍수에 아쉬움

- 오늘날 서버에 384 CPU 스레드가 달려있고, 작은 VM조차 CPU 16개 가질 수 있는 시대  
  - 이런 하드웨어에서 Kestrel로 개발하면 하루에 수조 번의 요청도 무난히 처리 가능  
  - PHP와 비슷한 개발 경험을 string interpolation 연산자로 제공 가능  
  - LINQ와 String.Join()을 활용하면 HTML 테이블과 중첩 요소를 간단히 템플릿화  
  - 진짜 어려운 점은 MVC/Blazor/EF 같은 생태계의 지뢰밭을 잘 피하는 방법을 아는 것  
  - 프로그램 전체를 하나의 최상위 파일로 CLI에서 실행하는 방식도 가능한데, "Minimal APIs"라는 키워드를 모르면 잘못된 문서의 미로로 들어가기 쉬움

    - 코어 기술 위에 추상화 레이어를 덧씌워서 Director/VP 자리를 승진하는 사례가 무척 많다는 점에 놀라움

- CGI의 장점은 멀티테넌트 환경에서 격리 원시 기능을 새로 구축할 필요 없다는 점  
  - 한 요청에 버그가 있어도 프로세스 격리 덕분에 다른 요청에 영향 없음  
  - 무한 루프도 선점 스케줄링 덕에 서비스 거부(DoS)로 이어지지 않음  
  - rlimit으로 오래 걸리는 요청을 강제로 종료 가능  
  - cgroup을 사용해 테넌트별 메모리, CPU, 디스크/네트워크 IO 사용량을 공정하게 할당 가능  
  - 네임스페이스/감옥, 권한 분리로 요청마다 접근 권한을 제한할 수 있음

- CGI 스크립트 덕분에 perl이 빠른 시작 시간을 위해 최적화됐던 이유  
  - `time perl -e ''` 명령 실행 시 perl은 5ms, python3는 33ms, ruby는 77ms로 perl의 빠른 시작 시간 확인

    - tcc mob branch의 `#!/bin/tcc -run` 방식 스크립트가 perl보다 1.3배 빠르다는 점 언급  
    - Julia, Java VM, thread PHP 등도 시작 시간이 매우 길어지는 사례  
    - 사람들이 "큰 환경"에 습관적으로 의존하게 되는 현상  
    - Lisp 커뮤니티에서도 이미지를 사용함으로써 이게 반복되고, "emacs is bloated" 밈도 여기서 탄생  
    - 90년대 중후반 Perl의 전성기는 정말로 CGI 덕분에 가능했던 분위기  
    - 당시 getline조차 표준이 아니어서 서드파티 C 라이브러리를 몇백~몇천 라인으로 만들기도 했던 시기 회상  
    - 결국 "평판"에 따라 기술이 선택되고, 대부분 친구가 추천해주는 것으로 학습이 이뤄짐

- apache tomcat 11을 사용해보면 .jsp 파일이나 전체 java servlet 애플리케이션(.war)을 ssh로 업로드만 하면 그냥 동작함  
  - 하나의 공유 JVM으로 최대 성능 확보  
  - DB 커넥션 풀, 캐시 등도 어플리케이션끼리 공유 가능  
  - 정말 인상적인 경험

    - 실제 사용 패턴에 따라 다름  
    - 대용량 서비스에는 훌륭하지만, 50개의 소형 어플리케이션을 각각 하루 수백 건만 처리해야 한다면, Tomcat의 메모리 오버헤드는 CGI 스크립트 기반 Apache/Nginx에 비해 너무 크다는 점 지적

    - 파일을 단순히 복사해서 배포하는 시절이 그립다는 감상  
    - 왜 배포 과정이 이렇게 복잡해졌는지 아쉬움 토로

    - 지금도 Jetty로 백엔드 웹앱을 즐겁게 사용 중이라는 경험 공유

    - Tomcat/Jakarta EE/JSP 스택이 의외로 상당히 견고하다는 소감  
    - PHP처럼 HTML과 코드를 뒤섞어 쓸 수도 있고, 순수 Java 라우트도 가능  
    - Websockets 지원, 싱글 프로세스 멀티스레드 모델이라 실시간 통신에도 강점  
    - 필요하면 요청마다 데이터 공유 가능, JSP 코드는 기본적으로 요청 범위로 제한  
    - 배포가 정말 쉽고, webapps 디렉토리에 신규 파일만 업로드하면 Tomcat이 자동으로 새로운 앱을 로드 및 기존 앱을 언로드  
    - 단점으로는 클래스로더 누수로 인해 garbage collection에 실패할 수 있다는 점, 싱글프로세스 모델의 숙명

- apache 요청에 대한 시각화 도구 [ibrahimdiallo.com/reqvis](https://www.ibrahimdiallo.com/reqvis) 제작  
  - 데스크톱 브라우저에서 최고의 경험 제공  
  - HN 트래픽 데이터를 바탕으로 실제 동작 흐름을 웹에서 확인 가능

- 요즘 복잡한 아키텍처로 가고 있는 상황이 의심스러웠음, 사실 좋은 하드웨어로 충분히 기존 기술을 쓸 수도 있다는 가능성 언급  
  - 수백만 명에게 실시간 주가 정보를 알려주는 시스템 설계 질문에 처음에는 Kafka, pubsub 등 복잡한 스트림 구조를 떠올렸지만, 결국 서버에 정적 파일을 두는 단순한 방식도 고민  
  - 이런 방식의 실제 운용 비용 궁금

    - 실질적으로 모든 웹 API의 레이턴시는 DB 쿼리나 ML 모델 쿼리가 결정  
    - 나머지 프로세스는 Python 등 느린 언어를 써도 별 거 아닌 수준  
    - 변화가 드문 데이터만 반환하면 NIC 한계까지도 쉽게 도달 가능

- serverless 아키텍처와 비슷하지만, 훨씬 간단하고 저렴한 점 강조  
  - 실제로 비즈니스 현장에서 이렇게 사용하는 사례가 있는지 궁금

- 이런 전통적인 구조를 재고하지 않고 단순히 "serverless functions"라는 새로운 패러다임만 만들어낸 것에 아쉬움  
  - Lambda 같은 serverless function이 별도의 보호 메커니즘(마이크로 VM 등)이 있기는 하지만, 사실상 CGI와 권한 조정만으로도 훨씬 적은 복잡성으로 멀리 갈 수 있었을 것이라 생각

### Comment 41064

- Author: regentag
- Created: 2025-07-07T14:46:43+09:00
- Points: 1
- Parent comment: 41032
- Depth: 1

cgi는 그렇다 쳐도 jsp에 대한 반응이 놀랍네요 ㅋㅋ  
jsp가 벌써 그정도로의 고대 유물이 된걸까요.
