부팅 과정과 커널 패닉
전원이 들어와 서비스가 뜨기까지 각 단계가 다음 단계를 찾아 넘기는 사슬
순서
| 순서 | 단계 | 하는 일 |
|---|
| 1 | 펌웨어 (BIOS 또는 UEFI) | 하드웨어를 점검하고 부팅 장치를 찾는다 |
| 2 | 부트로더 (GRUB) | 커널 이미지를 메모리에 올린다 |
| 3 | 커널 초기화 | 메모리 관리, 스케줄러, 드라이버를 올린다 |
| 4 | 임시 루트 파일시스템 | 실제 루트를 마운트할 드라이버를 담고 있다 |
| 5 | 실제 루트 마운트 | 디스크의 파일시스템을 붙인다 |
| 6 | 첫 프로세스 (init, systemd) | PID 1. 나머지 서비스를 띄운다 |
| 7 | 서비스 시작 | 의존 순서대로 데몬을 올린다 |
각 단계가 다음을 찾지 못하면 그 지점에서 멈춥니다. 그래서 부팅 실패는 어디까지 진행됐는지로 원인을 좁힙니다.
| 멈춘 지점 | 원인 |
|---|
| 화면에 아무것도 없다 | 하드웨어나 펌웨어 |
| 부트로더 화면이 안 뜬다 | 부트 레코드 손상, 부팅 순서 설정 |
| 커널이 안 올라간다 | 커널 이미지 손상, 잘못된 부팅 옵션 |
| 루트를 못 찾는다 | 디스크 인식 실패, 파일시스템 손상, 잘못된 장치 지정 |
| 서비스가 안 뜬다 | 의존 서비스 실패, 설정 오류 |
부팅 시간을 줄이려면
| 방법 | 내용 |
|---|
| 불필요한 서비스 제거 | 안 쓰는 데몬을 시작 목록에서 뺀다 |
| 병렬 시작 | 의존이 없는 서비스는 동시에. 최신 init 은 기본으로 한다 |
| 지연 시작 | 즉시 필요 없는 것은 요청이 올 때 띄운다 |
| 대기 시간 확인 | 네트워크나 마운트를 기다리는 시간이 대부분인 경우가 많다 |
| 컨테이너로 전환 | 커널 부팅이 없어 수백 밀리초에 시작한다 |
네 번째가 실제로 가장 큰 몫입니다. 특정 서비스가 네트워크나 원격 마운트를 기다리며 수십 초를 쓰는 경우가 흔합니다. 단계별 소요 시간을 측정해 확인합니다.
커널 패닉
커널이 더 진행하면 데이터를 망가뜨릴 수 있다고 판단해 멈추는 상태입니다. 응용 프로그램의 오류와 다릅니다.
| 구분 | 응용 오류 | 커널 패닉 |
|---|
| 영향 | 그 프로세스만 죽는다 | 시스템 전체가 멈춘다 |
| 복구 | 재시작하면 된다 | 재부팅이 필요하다 |
| 원인 | 코드 버그, 예외 | 커널이나 드라이버, 하드웨어 |
| 흔한 원인 | 내용 |
|---|
| 루트 파일시스템을 못 찾음 | 디스크 인식 실패, 잘못된 장치 지정 |
| 드라이버 문제 | 결함 있는 커널 모듈 |
| 메모리 오류 | 물리 메모리 결함 |
| 파일시스템 손상 | 마운트 중 오류 |
진단
| 확인 | 내용 |
|---|
| 패닉 메시지 | 어느 함수에서 멈췄는지 호출 흐름이 찍힌다 |
| 콘솔 로그 | 화면에만 찍히고 디스크에는 안 남을 수 있다. 원격 콘솔 확보 |
| 크래시 덤프 | 미리 설정해 두면 메모리 상태를 파일로 남긴다 |
| 최근 변경 | 커널 업데이트, 드라이버 설치, 하드웨어 교체 |
| 메모리 검사 | 재현이 불규칙하면 물리 메모리를 의심한다 |
두 번째가 실무의 어려움입니다. 패닉이 나면 디스크에 쓸 수 없으므로 로그가 남지 않습니다. 원격 콘솔이나 시리얼 콘솔을 미리 준비해야 원인을 볼 수 있습니다.
Q.리눅스 부팅 순서를 설명해주세요
각 단계가 다음 단계를 찾아 넘기는 사슬입니다.
| 순서 | 단계 | 하는 일 |
|---|
| 1 | 펌웨어 | 하드웨어 점검, 부팅 장치 탐색 |
| 2 | 부트로더 | 커널을 메모리에 올린다 |
| 3 | 커널 초기화 | 메모리 관리, 스케줄러, 드라이버 |
| 4 | 임시 루트 파일시스템 | 실제 루트를 붙일 드라이버를 담는다 |
| 5 | 실제 루트 마운트 | |
| 6 | 첫 프로세스 (PID 1) | 나머지 서비스를 띄운다 |
| 7 | 서비스 시작 | 의존 순서대로 |
4번이 왜 필요한지가 자주 빠집니다. 실제 루트가 담긴 디스크를 읽으려면 그 디스크의 드라이버가 필요한데, 그 드라이버는 디스크 안에 있습니다. 순환을 끊으려고 필요한 최소 드라이버만 담은 임시 파일시스템을 메모리에 먼저 올립니다.
6번의 PID 1 은 특별합니다. 고아가 된 프로세스를 입양해 종료 상태를 거두고, 이것이 죽으면 시스템이 멈춥니다.
흔한 실수: 부트로더가 운영체제를 실행한다고 답하는 것. 부트로더는 커널을 메모리에 올려놓고 제어를 넘기는 것까지 합니다. 그 뒤는 커널이 스스로 진행합니다.
Q.커널 패닉과 응용 프로그램 오류는 어떻게 다른가요?
| 구분 | 응용 오류 | 커널 패닉 |
|---|
| 실행 모드 | 사용자 모드 | 커널 모드 |
| 영향 범위 | 그 프로세스만 | 시스템 전체 |
| 복구 | 프로세스 재시작 | 재부팅 |
| 원인 | 코드 버그, 처리 안 된 예외 | 커널, 드라이버, 하드웨어 |
| 로그 | 파일에 남는다 | 디스크에 못 쓸 수 있다 |
차이의 근원은 권한입니다. 사용자 모드 프로그램의 잘못된 메모리 접근은 커널이 잡아 그 프로세스만 종료시킵니다. 커널 자신이 그런 상태에 빠지면 잡아줄 상위 계층이 없습니다.
패닉은 고장이 아니라 판단이라는 점도 중요합니다. 커널이 "더 진행하면 데이터를 망가뜨린다"고 보고 스스로 멈추는 것입니다. 계속 돌게 두면 디스크에 잘못된 내용을 쓸 수 있습니다.
| 흔한 원인 | 내용 |
|---|
| 루트 파일시스템을 못 찾음 | 잘못된 장치 지정, 디스크 인식 실패 |
| 드라이버 결함 | 최근 설치한 모듈 |
| 물리 메모리 오류 | 재현이 불규칙하다 |
흔한 실수: 패닉 원인을 애플리케이션에서 찾는 것. 응용 프로그램은 커널 모드 코드를 실행할 수 없으므로 직접 패닉을 만들 수 없습니다. 드라이버나 커널 버그를 자극한 경우가 아니라면 원인은 그 아래에 있습니다.
Q.부팅 시간을 줄이려면 무엇을 보나요?
추측하지 않고 단계별 소요 시간을 먼저 측정합니다. 대개 특정 서비스의 대기가 대부분입니다.
| 확인 | 내용 |
|---|
| 단계별 시간 | 펌웨어, 커널, 사용자 공간을 나눠 본다 |
| 서비스별 시간 | 오래 걸리는 서비스를 찾는다 |
| 대기 원인 | 네트워크, 원격 마운트, 타임아웃 |
| 줄이는 방법 | 내용 |
|---|
| 불필요한 서비스 제거 | 안 쓰는 데몬을 시작 목록에서 뺀다 |
| 지연 시작 | 요청이 올 때 띄운다 |
| 병렬 시작 | 의존이 없는 것은 동시에 |
| 대기 타임아웃 축소 | 네트워크 대기 시간을 줄인다 |
| 커널을 안 거치기 | 컨테이너로 전환하면 수백 밀리초 |
네 번째가 종종 가장 큰 몫입니다. 네트워크가 준비되기를 기다리는 서비스가 90초 타임아웃을 다 쓰는 경우가 있습니다. 그 서비스가 정말 네트워크를 기다려야 하는지부터 봅니다.
마지막이 근본적인 답입니다. 서버 부팅이 자주 필요한 요구라면(자동 확장 등) 컨테이너나 미리 만들어 둔 이미지로 옮기는 편이 낫습니다.
흔한 실수: 커널 옵션 조정부터 시작하는 것. 커널 초기화는 대개 몇 초이고, 수십 초는 사용자 공간의 서비스 시작에서 나옵니다.
Q.PID 1 프로세스는 무엇이 특별한가요?
| 특성 | 내용 |
|---|
| 첫 프로세스 | 커널이 직접 띄우는 유일한 프로세스 |
| 고아 입양 | 부모가 먼저 죽은 프로세스를 물려받아 종료 상태를 거둔다 |
| 죽으면 시스템 정지 | 이 프로세스가 종료되면 커널이 패닉에 빠진다 |
| 신호 기본 동작 없음 | 처리기를 등록하지 않은 신호는 무시된다 |
두 번째가 컨테이너에서 실제 문제를 만듭니다. 컨테이너 안에서 애플리케이션이 PID 1 이 되는데, 대부분의 애플리케이션은 고아 프로세스를 거두는 일을 하지 않습니다. 그러면 좀비 프로세스가 쌓입니다.
| 컨테이너에서 주의할 것 | 내용 |
|---|
| 좀비 누적 | 자식을 만드는 애플리케이션이면 거두는 코드가 필요하다 |
| 신호 전달 | 종료 신호를 받아 정리하는 처리기를 등록해야 한다 |
| 초기화 프로세스 사용 | 작은 init 을 PID 1 로 두고 그 아래에 애플리케이션을 둔다 |
세 번째가 실무의 답입니다. 컨테이너 실행 옵션으로 최소한의 init 을 넣으면 고아 수거와 신호 전달을 대신 해줍니다.
네 번째도 놓치기 쉽습니다. 일반 프로세스는 종료 신호를 받으면 기본 동작으로 종료되지만, PID 1 은 처리기가 없으면 무시합니다. 그래서 컨테이너가 종료 신호에 반응하지 않고 강제 종료까지 기다리는 일이 생깁니다.
흔한 실수: 셸 스크립트로 애플리케이션을 감싸 실행하는 것. 셸이 PID 1 이 되고 신호를 자식에게 전달하지 않아, 종료 신호가 애플리케이션에 닿지 않습니다.
먼저 스스로 답해보고 아래 답변과 견줘보세요. 막히는 부분은 문제로 확인할 수 있어요.
읽었으면 문제로 확인해보세요
운영체제 문제를 풀면 틀린 문제가 자동으로 노트에 쌓입니다. 가입 없이 5문제를 먼저 풀어볼 수도 있어요.