본문 바로가기

2.분석 및 설계

The C10k Problem

들어가기

재미있는 문서가 있어서 내용을 정리해보았다. 해당 문서는 Dan Kegel의 "The C10k problem" 이라는 문서로 C10k에 대한 문제를 다루고 있다. C10k는 한 시스템에서 1만 연결을 처리할 수 있을까에 대한 문제이다. 물론 I/O가 많거나 CPU 계산량이 많은 처리는 어려울 수 있지만, 시스템에 처리할 수 있는 처리량에 대한 문제을 검토하고 해결 방안을 살펴보는 내용이다. 오래된 자료이지만 어떤 부분은 참고할 만 하다.

작성자: ospace114@empal.com, http://ospace.tistory.com/

개요

시스템 사양이 1000MHz CPU이고 2G Ram와 1Gbps Ethernet을 가지고 가격은 $1200이 있다고 하자. 이 시스템은 20000명 사용자가 있고 동시에 시스템을 사용하게 된다면 사용자별 CPU는 50KHz, RAM은 100KB, Ethernet은 50Kbps을 사용하게 되고 개인당 $0.08 자원이 할당된다. 만약 디스크에서 4KB 읽어서 네트워크로 초당 2만번 전송은 어렵지않다.
하드웨어는 계속적인 발전으로 더 이상 병목점이 아니게 되지만 OS와 프로그램 자체의 문제가 더 커지고 있다.
이런 상황에서 어떻게 문제를 해결할지 접근법을 살펴보자.

해결하기 위한 I/O 전략

먼저 네트워깅 프로그램을 설계하는데 있어서 만은 선택할 수 있는 항목이 있다.
먼저 단일 쓰레드 환경에서 다중 I/O 요청에 대해 처리할 수 있는 방법으로는 블럭킹(동기호출), 넌블럭킹 호출과 비동기 호출이 있다.

  • 먼저 블록킹 사용은 절대 사용하지 말아야하는 방법이다. 멀티 쓰레드나 프로세스에서는 가능할 수도 있다.
  • 다음으로 넌블럭킹 호출로 읽기 감지로 언제 시작되는지 알아서 처리하는 방식이다. 일반적으로 이는 네트워크 I/O에서 사용되며 디스크 I/O에서는 사용되지 않는다.
  • 마지막으로 비동기 호출로 완료 감지로서 언제 I/O가 끝나는지 알 수 있으며 일반적으로 네트워크 I/O와 디스크 I/O에서 사용된다.

각 클라이언트 별로 어떻게 서비스를 처리할지에 대한 방법이다.

  • 클라이언트 별로 한 프로세스 또는 쓰레드 처리방식이다. 예전에 많이 사용했었다.
  • 한 OS 레벨 스레드로 여러 클라이언트 처리한다. 그리고 각 클라이언트는 다음과 같은 방식으로 제어된다.
    • 사용자 레벨 스레드
    • 상세 머신
    • continuation
  • 한 OS 레벨 스레드로 각 클라이언트 처리 (자체 스레드를 가진 자바)
  • 한 OS 레벨 스레드로 각 활성 클라이언트 처리 (아파치 기반 톰켓)

표준 O/S 서비스를 사용할지 커널을 수정할지에 대한 방안이 있다.

가장 인기 있는 5가지 조합이다.

  • 각 쓰레드에 여러 사용자, 논블럭킹 I/O와 level-triggered readiness
  • 각 쓰레드에 여러 사용자, 논블럭킹 I/O와 readiness change
  • 각 서버 쓰레드에 여러 사용자, 비동기 I/O 사용
  • 한 서버 쓰레드에 한 사용자, 블럭킹 I/O
  • 커널에 서버 코드 구성

각 쓰레드에 여러 사용자, 논블럭킹 I/O와 level-triggered

모든 네트워크 처리에는 넌블러킹 모드를 설정할 수 있다. select나 poll 사용하여 어떤 핸들에 데이터 대기 상태인지 알려준다. 이는 전통적으로 선호하는 방식이다. 커널에서 준비 알림은 단지 힌트 일뿐 실제로 준비되어 있지 않을 수 있다. 그래서 이 방식의 병목점은 디스크 I/O로 인한 병목이 발생할 수 있다. 이로 인해 프로세스는 블록되고 모든 클라인트는 대기해야 한다. 그리고 다양한 해결 방식도 존재한다. I/O 준비 완료임을 알려주는 대표적인 방법으로 select, poll, kqueue(BSD에서 poll 대체)가 있다.

각 쓰레드에 여러 사용자, 논블럭킹 I/O와 준비변경(readiness change) 알림

준비 변경 알림 (또는 엣지-트리거 준비 알림) 감지는 준비되었다고 알린다.커널에서 보내는 단순 힌트이기 때문에 읽을 시 준비가 안되어 있을 수 있다. 핸들에서 데이터가 유효한 시점에 알려준다. 준비 변경 알림을 사용할 경우 가짜 이벤트에 대비해야 한다. 또한 이벤트를 놓치면 영원히 중단된다. 대표적인 방법으로 kqueue, epoll, singal-per-fd 등이 있다.

각 서버 쓰레드에 여러 사용자, 비동기 I/O 사용

비동기 I/O를 지원하는 O/S는 거의 없었다.(주. 현재는 대부분의 O/S에서 지원하고 있다) 비동기 I/S는 AIO(Asynchronous input and output) 인터페이스에 의해서 제공된다. 이는 신호와 같이 각 I/O 연산과 연관되어 있다. 큐에 있는 신호와 값을 사용자 프로세스로 전달한다. AIO는 일반적으로 edge-triggered로 사용된다. 대표적인 예로 IOCP, AIO가 있다.

한 서버 쓰레드에 한 사용자, 블럭킹 I/O

읽기와 쓰기가 블록되며 한 사용자에 많은 자원이 소모된다. 또한 많은 OS에서 많은 쓰레드로 인한 문제점이 존재한다. 각 스레드가 2MB 스택인 경우 32비트 시스템이라면 512개 스레드만 되도 가상 메모리가 부족해진다. 이를 해결하겨면 스택 사용을 최소화하도록 설계해야 한다. 64비트 프로세스에서는 어느 정도 해결할 수 있다. 대표적인 예로 LinuxThreads, NGPT, NPTL 등 다양한 쓰레드 라이브러리가 있다.

커널에 서버 코드 구성

커널에 직업 서버를 구현하는 방식이다. 커널이라는 제약사항으로 한계가 있지만 더 빠른 처리할 할 수 있다는 장점도 있다. 대표적인예로 khttpd(리눅스), TUX가 있다.

기타등등

열린 파일 핸들 제한

간혹 유닉스 시스템에서 열린 파일 개수를 제한하는 경우가 있다. 보통 ulimit, setrlimit 나 부팅설정 등으로 크기를 수정할 수 있다. 열린 파일 핸들 제한이 어떻게 되는지 반드시 확인해야할 부분이다.

스레드 제한

가상 메모리 방지를 위해 스레드 스택 공간을 설정할 수 있다. pthread인 경우 pthread_attr_init()로 설정 가능하다.

자바문제

JKD1.3까지 클라이언트당 한 스레드 모델이었지만 JDK1.4에서 NIO가 도입되면서 넌블럭킹이 가능해졌다.

제로복사(Zero-copy)

데이터를 여기저기 복사할 경우가 많다. 이런 복사복을 물리적 최소 수준까지 제거하는 방식을 말한다. 즉, 물리적 위치에서 최소의 복사로 CPU와 메모리 사용을 줄여 I/O를 처리한다고 보면 된다.

writev(or TCP_CORK)로 작은 프레임 방지

소켓 옵션 중에 TCP)CORK로 부분 프레임 정송을 방식한다. TCP_CORK 대안으로MSG_MORE도 있다.

과부하 발생할 경우

서버에 과부하가 발생할 경우 들어오는 연결을 끊으면 성능이 개선된다. 이는 select, pool 이나 호출당 준비 이벤트(readiness event)의 개수가 리턴되는 경우에 유용하다.

Posix 스레드가 아닌 스레드 이점

모든 스레드가 동일하게 생성되지 않는다. Linux의 clone()은 현재 작업 디렉토리가 있는 스레드를 생성하며 FTP 서버에 유용하다.

데이터 캐싱이 유리할 때도 있다

소프트웨어 아키텍처 차이로 인한 성능 차이는 거의 없을 수 있다. 이 것 보다 어플리케이션에서 캐싱으로 인한 성능 차이가 더 클 수 있다.

성능 측정

다음 두가지 테스트 방식이 간단하고 흥미롭고 어렵다.

  • 초당 로우(raw) 연결 개수 (초당 512 바이트 파일을 얼마나 많이 제공하나?)
  • 많은 느린 클라이언트(회선 속도가 느린 경우)에 대용량 파일의 전체 전송 속도(서버 성능 저하 전까지 얼마나 많은 클라이언트가 동시에 다운로드 받을 수 있나?)

결론

결론은 다수 사용자 처리위해 멀티쓰레드, 비동기와 논블럭킹은 필수이다. 내용을 간략하게 정리한 내용이고 기술적으로 세세한 설명이 생략되어 있어서 완벽하기 이해가 힘들 수 있다. 원문에 더 많은 내용과 관련 내용에 대한 링크들이 참고하면 좋을 듯 합니다. 더무 성의없게 정리한 듯 하네요. 아무쪼록 도움이 되었으면 합니다. 모두 즐거운 코딩생활하세요. ospace

참고

[1] Dan Kegel, The C10k problem, http://www.kegel.com/c10k.html

반응형

'2.분석 및 설계' 카테고리의 다른 글

전자서명  (0) 2024.03.06
CAP 이론 소개  (1) 2023.11.20
의사코드(pseudocode) 사용하기  (0) 2023.10.19
glTF 포멧  (0) 2023.06.08
[mybatis] Mybatis 내부동작 흐름  (0) 2022.01.26