반응형

Linux 12

8편. Kafka 성능 문제는 JVM이 아니라 OS 문제일 때가 많다

7편에서 Kafka가 디스크를 빠르게 쓰는 이유를 스토리지 구조와 Page Cache 관점에서 살펴봤다. 이제 실무에서 가장 흔한 착각으로 넘어가 보자.“Kafka가 느린데, JVM 옵션을 더 만져야 하나?”많은 경우 이 질문은 방향이 틀려 있다. Kafka 성능 병목의 상당수는 JVM이 아니라 OS와 운영 환경에서 발생한다.왜 JVM부터 의심하게 될까Kafka는 JVM 위에서 동작한다. GC 로그도 있고, 힙도 있다. 그래서 문제가 생기면 자연스럽게 GC-힙-옵션부터 보게 된다.하지만 Kafka의 데이터 경로를 다시 떠올려보자.데이터는 파일로 append된다읽기-쓰기는 Page Cache를 통과한다네트워크 전송은 zero-copy를 활용한다즉, Kafka의 핫패스는 OS 커널 영역에 더 가깝다.CPU가..

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가 아주 빠르게 실행 대상을 바꾸..

반응형