반응형

Operating System 11

12편. 리눅스를 이해하면 서버 장애가 보인다

Linux 공식문서로 다시 이해하는 JVM 서버 실행 환경1편부터 11편까지 우리는 Linux 커널이 JVM 서버를 어떻게 바라보고, 어떤 규칙으로 자원을 나누며, 언제 개입하고, 언제 프로세스를 종료하는지를 따라왔다.이 마지막 편에서는 지금까지의 내용을 하나로 묶는다.서버 장애를 “현상”이 아니라 “상태”로 읽는 법서버 장애는 갑자기 생기지 않는다운영 중 장애를 마주하면 보통 이렇게 느낀다.어제까지 잘 되던 서버가 갑자기 느려졌다로그 없이 서버가 죽었다특정 조건에서만 문제가 재현된다하지만 Linux 관점에서 보면,이런 장애는 “갑작스러운 사고”가 아니다.커널의 상태가 임계점에 도달했을 뿐이다.“느린 서버”를 Linux 상태로 번역하기“서버가 느리다”는 말은 너무 추상적이다.Linux 관점에서는 보통 다..

11편. JVM, Linux, 컨테이너가 충돌하는 지점들

Linux 공식문서로 다시 이해하는 JVM 서버 실행 환경1편부터 10편까지 우리는 Linux 커널이 JVM 서버를 어떻게 실행하고, 어떤 규칙으로 자원을 나누며, 어떻게 감시하고, 언제 죽이는지를 하나씩 살펴봤다.이번 편에서는 그 모든 요소가 한 지점에서 충돌하는 순간들을 정리한다.운영 중 자주 듣는 말들이 있다.“코드는 멀쩡한데 서버가 느리다”“메모리는 남아 있는데 죽었다”“배포할 때만 이상하다”이 말들은 대부분 JVM, Linux, 컨테이너의 가정이 서로 어긋나는 지점에서 나온다.충돌 1. JVM의 병렬성 가정 vs Linux 스케줄러JVM은 기본적으로 이렇게 가정한다.CPU 코어 수만큼 병렬 실행이 가능하다스레드를 늘리면 처리량이 늘어난다하지만 Linux 스케줄러(CFS)는 다르게 동작한다.CPU..

10편. epoll이 없었다면 서버는 존재할 수 없다

Linux 공식문서로 다시 이해하는 JVM 서버 실행 환경9편에서 우리는 서버의 모든 입출력이 파일 디스크립터 위에서 동작한다는 사실을 살펴봤다.이번 편에서는 그 수많은 파일 디스크립터를 어떻게 효율적으로 감시하고 처리하는지, 즉 현대 서버의 심장부라 할 수 있는 epoll을 다룬다.서버가 해야 하는 가장 어려운 일네트워크 서버의 핵심 과제는 단순해 보인다.요청이 오면 처리하고응답을 보낸다하지만 실제로 서버가 마주하는 질문은 훨씬 복잡하다.“수천, 수만 개의 연결 중에서 지금 당장 처리해야 할 소켓은 무엇인가”이 질문에 답하지 못하면, 서버는 확장될 수 없다.select - 가장 단순하지만 가장 먼저 한계에 부딪힌 방식초기의 Linux 서버는 select를 사용했다.select의 방식은 직관적이다.모든 ..

9편. 파일 디스크립터가 서버를 죽인다

Linux 공식문서로 다시 이해하는 JVM 서버 실행 환경8편에서 우리는 namespace가 컨테이너를 “다른 세계처럼 보이게” 만드는 기술이라는 점을 살펴봤다.이번 편에서는 그 세계 안에서 서버를 가장 조용히, 그리고 가장 자주 무너뜨리는 요소를 다룬다.파일 디스크립터(File Descriptor)이 개념은 너무 기본적이어서 종종 중요성을 잊는다.하지만 실무 장애에서 파일 디스크립터는 생각보다 자주, 그리고 치명적으로 등장한다.파일 디스크립터란 무엇인가Linux에서 파일 디스크립터는프로세스가 커널 리소스에 접근하기 위한 핸들이다.파일 디스크립터로 표현되는 대상은 생각보다 많다.일반 파일소켓파이프stdin / stdout / stderr즉,네트워크 서버는 파일 디스크립터 위에 세워진 프로그램이다.소켓도 ..

8편. namespace로 나뉜 세계

Linux 공식문서로 다시 이해하는 JVM 서버 실행 환경7편에서 cgroup은 리소스를 “제한”하는 기능이 아니라 프로세스가 어떤 규칙 아래에서 실행되는지 정의하는 시스템이라는 점을 살펴봤다.이번 편에서는 컨테이너의 또 다른 핵심 축인 namespace를 다룬다.cgroup이 “얼마나 쓸 수 있는가”를 정한다면,namespace는 “무엇을 볼 수 있는가”를 정한다.namespace가 없었다면 컨테이너는 존재할 수 없다컨테이너를 처음 접하면 이런 착각을 하기 쉽다.컨테이너는 가벼운 VM이다컨테이너마다 OS가 따로 있다하지만 Linux 관점에서 이는 사실이 아니다.컨테이너는 같은 커널을 공유한다.그럼에도 컨테이너가 서로 완전히 분리된 것처럼 보이는 이유가 바로 namespace다.namespace의 본질n..

7편. cgroup은 제한이 아니라 규칙이다

Linux 공식문서로 다시 이해하는 JVM 서버 실행 환경6편에서 우리는 OOMKill이 버그가 아니라 Linux 커널의 생존 전략이라는 점을 살펴봤다.이번 편에서는 그 OOMKill과 CPU 스로틀링의 근원이 되는 핵심 개념, cgroup(Control Group)을 다룬다.cgroup은 흔히 이렇게 설명된다.“컨테이너 리소스를 제한하는 기능”하지만 이 설명은 충분하지 않다.cgroup은 단순한 제한 장치가 아니라, 프로세스가 어떤 규칙 아래에서 실행되어야 하는지를 정의하는 시스템이다.cgroup이 등장한 이유cgroup이 도입되기 전의 Linux에서는 다음과 같은 문제가 반복적으로 발생했다.특정 프로세스가 메모리를 과도하게 사용다른 프로세스까지 함께 느려짐시스템 전체가 불안정해짐Linux 커널은 프로..

6편. OOMKill은 버그가 아니다

Linux 공식문서로 다시 이해하는 JVM 서버 실행 환경5편에서 Linux는 Heap을 모르고, 페이지와 가상 주소 공간만을 관리한다는 점을 살펴봤다.이번 편에서는 그 연장선에서 가장 당황스러운 현상 하나를 다룬다.“로그도 없이 프로세스가 죽었다”“JVM 예외는 없는데 컨테이너가 재시작됐다”이 현상의 주범은 대부분 OOMKill이다.OOMKill은 예외가 아니라 정책이다많은 개발자가 OOMKill을 이렇게 받아들인다.“메모리 버그가 터졌다”하지만 Linux 관점에서 OOMKill은 버그가 아니다.시스템을 살리기 위한 마지막 선택이다.Linux 커널의 우선순위는 명확하다.개별 프로세스보다시스템 전체의 생존메모리가 고갈되면, 커널은 프로세스를 선택해 제거한다.OutOfMemoryError와 OOMKill은..

5편. 리눅스 메모리는 Heap을 모른다

Linux 공식문서로 다시 이해하는 JVM 서버 실행 환경4편에서 CPU는 스레드를 많이 만든다고 빨라지지 않으며, 컨텍스트 스위칭과 run queue가 지연을 만든다는 것을 살펴봤다.이번 편의 주제는 그 다음으로 자주 오해되는 영역이다.“메모리는 충분한데 왜 느려질까”“Heap은 여유가 있는데 왜 문제가 생길까”이 질문의 답은 JVM이 아니라, Linux의 메모리 관점에 있다.리눅스는 Heap이라는 개념을 모른다JVM 개발자는 메모리를 이렇게 생각한다.HeapMetaspaceStack하지만 Linux 커널은 이 구분을 전혀 모른다.Linux가 아는 것은 오직 이것뿐이다.가상 주소 공간(Virtual Address Space)페이지(Page)물리 메모리Heap은 JVM의 논리적 개념이지, OS의 개념이 ..

4편. 스레드가 많아도 처리량이 늘지 않는 이유

Linux 공식문서로 다시 이해하는 JVM 서버 실행 환경3편에서 Linux 스케줄러는 “빠른 응답”이 아니라 공정함을 목표로 CPU를 나눈다는 점을 살펴봤다.이번 편에서는 그 공정함이 실제 서버 성능에서 어떤 비용으로 나타나는지, 즉 컨텍스트 스위칭과 run queue 관점에서 정리한다.스레드를 늘리면 왜 빨라질 것이라 기대할까서버 개발을 하다 보면 자연스럽게 이런 생각을 하게 된다.요청이 많다동시성이 부족하다그럼 스레드를 늘리자이 논리는 직관적으로는 맞아 보인다.하지만 Linux 관점에서는 이 선택이 항상 성능 향상으로 이어지지 않는다.컨텍스트 스위칭이란 무엇인가CPU는 한 시점에 하나의 스레드만 실행한다.여러 스레드가 동시에 “실행되는 것처럼” 보이는 이유는, CPU가 아주 빠르게 실행 대상을 바꾸..

3편. 리눅스 스케줄러는 공정하지 않다

Linux 공식문서로 다시 이해하는 JVM 서버 실행 환경2편에서 JVM 서버는 fork - exec를 거쳐 하나의 프로세스로 실행되고, 컨테이너 환경에서는 그 프로세스가 자연스럽게 PID 1이 된다는 것을 살펴봤다.이번 편에서는 그 프로세스가 실행된 이후의 이야기다.CPU는 어떻게 나뉘는가왜 스레드를 많이 만들어도 성능이 좋아지지 않을까이 질문의 답은 JVM이나 Spring이 아니라, Linux 스케줄러의 철학에 있다.CPU는 동시에 여러 개의 프로세스를 실행하지 않는다멀티코어 환경에서는 동시에 여러 작업이 실행되는 것처럼 보인다.하지만 단일 코어 기준으로 보면, CPU는 언제나 하나의 작업만 실행한다.Linux의 역할은 단순하다.“누구에게 지금 CPU를 줄 것인가”이 결정을 담당하는 것이 바로 스케줄..

반응형