이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.
추천한다! 그림도 많아서 리눅스의 전체적인 흐름을 이해하는데 어렵지 않았다.
<[1장] 리눅스 개요>
-리눅스는 커널이라는 핵심 프로그램과 그 외로 나뉜다.
커널이 하는 일
- 접근제어, 명령 순서 제어, 자원 배분, 공유
- 프로세스가 저장 장치에 직접 접근하면 명령 순서 같은 게 깨질 수 있음. 그래서 커널을 통해 간접 접근 하도록 한다.
- 프로세스 스케줄링
- 메모리 관리
- 장치 접근
cpu 모드 2가지
- 커널 모드: 명령을 실행하는 데 아무 제약이 없다
- 사용자 모드: 명령 실행에 제약이 걸린다.
시스템 콜
- 시스템콜을 호출하면 사용자 모드에서 커널 모드로 변경이 돼 호출 처리가 된다.
OS 라이브러리
- OS 가 미리 공통된 기능을 묶어 라이브러리를 제공한다.
- 표준 C 라이브러리 (libc)
- ISO(국제 표준화 기구)에서 정한 표준 라이브러리가 있다.
- 리눅스는 GNU 프로젝트의 glibc(libc) 를 표준 라이브러리로 사용한다.
- python3 도 내부적으로 libc 를 링크한다. → OS 시스템콜 호출하기 위해
- libc 는 시스템콜 래퍼 함수도 제공한다.
- 시스템콜은 고급언어에서 호출 못 하고 어셈블리 코드로 호출할 수 있는데 시스템콜 래퍼 함수는 고급언어에서 시스템 콜 호출할 수 있게 지원해준다. 그래서 고급 언어에서 시스템콜 래퍼 함수를 호출하면 된다.
- 정적/동적(공유) 라이브러리
- 정적 라이브러리: 컴파일할 때 라이브러리 함수도 실행 파일에 넣는다.
- 동적 라이브러리: 라이브러리 함수 호출한다 정보만 실행 파일에 포함한다. 실행 중에 라브를 메모리에 로드한다.
<[2장] 프로세스 생성>
프로세스 생성하는 목적
- 동일한 처리를 여러 프로세스 생성해서 나누어 처리:
fork()
- 다른 프로그램 생성 (ex. bash 에서 각종 프로그램 생성):
fork()
&execve()
fork()
- 프로세스 복사본을 만든다. 자식 용 메로리 확보 후 부모의 메모리를 복사한다.
execv([실행할 프로그램])
fork()
를 먼저 실행해 프로세스 복사본을 만든다.- 실행할 프로그램 읽어서 메모리 맵(메모리 배치)에 필요한 정보 가져온다.
- 메모리에 새로운 프로세스 데이터로 덮어 쓴다.
초기 프로세스는 누가 생성하는가: 커널
- 전원을 키면 BIOS 같은 펌웨어를 기동하고 하드웨어를 초기화한다.
- 부트 로더가 OS 커널(리눅스 커널)을 기동한다.
- 리눅스 커널이 init 프로세스를 호출하면 걔가 자식 프로세스를 호출하여 트리 구조가 만들어진다.
모든 프로세스가 cpu 를 소모하는 건 아니다.
- 프로세스 상태에 따라 다르다.
Sleep
이면 소비 전력 억제하면서 대기한다.- CPU 를 사용하고 싶으면
Runnable
, 실제로 사용중이면Running
- 프로세스를 종료하면
Zombie
- 부모는 자식의 좀비 상태를 보고 회수해서 자원을 커널로 돌려준다.
ps aux
시그널
- 외부에서 실행 순서를 바꿈
- ex.
ctrl+c
누르면SIGINT
발생해 강종 됨
세션
- 사용자가 ssh 등을 사용해 로그인했을 때 로그인 세션에 대응하는 개념
- 세션 당 단말(터미널)이 존재한다. (터미널은 세션을 제어)
- ex. A 세션 ↔
pty/0
터미널
- ex. A 세션 ↔
데몬
- 상주하는 프로세스
- 단말이 필요없다. 단말 입출력이 필요 없기 때문
- 로그인 세션 종료해도 영향 받지 않는다.
- init 이 부모가 된다.
<[3장] 프로세스 스케줄러>
- 여러 실행가능한 프로세스가 존재 할 때 필요한 스케줄링
- 리눅스 커널이 CPU 자원 할당을 해주므로 스케줄러도 해준다.
컨텍스트 스위치
- 타임 슬라이스가 끝나서 프로세스가 전환되는 것
- 코드 상
foo();bar();
연속으로 돼있어도 중간에 컨텍스트 스위치가 발생하면 다른 프로세스가 동작할 수도 있다.
처리 성능
- 턴어라운드 타임: 처리 시간. 처리 요청해서 끝날 때까지의 시간
- 스루풋(throughput): 단위 시간당 몇 개 프로세스를 끝냈는가
<[4장] 메모리 관리 시스템>
- 메모리 관리도 커널이 해준다.
- 메모리 사용처: 커널 메모리, 프로세스 메모리, 비어있음
- shared (그림에 없지만): tmpfs 영역. 메모리 파일 시스템
- 만약 캐시 삭제해도 메모리 확보가 되지 않으면 OOM Killer 가 적당한 프로세스 골라 강종시킨다.
가상메모리
가상메모리가 없으면
- 메모리 공간이 군데군데 비어있는 메모리 단편화 현상 발생. 큰 메모리 단위를 할당할 수 없게 된다.
- 같은 메모리 주소를 사용하는 멀티 프로세스 구현이 어렵다. ↔ 프로세스마다 페이지 테이블이 존재하면 가능
- 커널 메모리 같이 비정상적인 영역에 접근할 수 있다.
물리 주소
- 가상 주소에 매핑된 실제 주소
페이지 테이블
- 가상 주소에서 물리 주소로 변환할 때 커널 메모리에 있는 페이지 테이블을 사용한다.
- CPU 는 페이지 단위로 메모리를 쪼개서 관리한다.
- 주소도 페이지 단위로 변환횐다.
- 한 페이지 : 페이지 테이블 엔트리
- 파이지 테이블은 커널이 작성하고, 실제 변환하는건 CPU가 한다.
- 만약 페이지 테이블에 없는 가상 주소에 접근하면 page fault 가 발생해서 페이지 폴트 핸들러가 실행된다.
두 단계로 메모리 할당함
- 메모리 영역 할당: 가상 주소 공간에 메모리 영역 매핑 by
mmap()
- 아직 물리 메모리 없음, 테이블 엔트리는 있음
- 이 때 접근하면 페이지 폴트 발생. 핸들러가 물리 주소 할당해줌 (Demand Paging)
- 메모리 할당: 확보한 영역에 물리 메모리 할당
<[5장] 프로세스 관리 (응용편)>
프로세스 생성 빨리하는 법
fork()
: copy on write (카피 온 라이트)- 쓸 때 메모리 복사한다고 하여
- 자식 복사할 때 페이지 테이블만 복사, 쓰기 권한은 X, 실제 물리 주소는 없음
- 후에 자식에서 쓸라그러면 페이지 폴트 발생하고 그 때 자식에게 물리 주소 할당하고 부모꺼 복사
execve()
: Demand Paging- execve() 호출 직후 물리 메모리는 할당 안돼있음
- 엔트리 포인트 접근할 때 페이지 폴트 발생해서 새 물리 주소 할당해줌
프로세스끼리 통신하는 법
- 공유 메모리: 프로세스마다 있는 페이지테이블에 가상 주소는 다르지만 같은 물리 주소 매핑
- 시그널: 프로세스끼리 시그널 주고받으며 통신
- 파이프: ex.
free | awk
- 소켓: 유닉스 도메인 소켓(같은 기기에 있는 프로세스 사이에서만 통신), TCP/UDP 소켓
베타적 제어
- 동시에 접근하면 동기화가 깨져 상호 배제 (mutual exclusion) 해야한다.
- critical section(임계구역) : 공유영역에 lock 걸기
- atomic 처리 : 중간에 다른 프로세스 못 끼어들게
<[6장] 장치 접근>
프로세스 대신 커널이 장치 접근해준다. 왜?
- 여러 프로그램이 동시에 접근하면 어떻게 동작할지 예상할 수 없다.
- 접근하면 안되는 데이터를 접근해 훼손시킬 수 있다.
디바이스 파일
- 커널이 디바이스 파일이라는 특수한 파일로 접근한다.
- ex.
/dev/sda
- 디바이스 파일을 통해 각 장치의 디바이스 드라이버가 접근한다.
디바이스 파일 종류
- 캐릭터 장치(키보드, 마우스):
/dev/tty
, 읽고 쓰기 가능, 탐색 불가 - 블록 장치(HDD, SDD):
/dev/nvme01n1
, 탐색도 가능
디바이스 파일명은 커널이 만들어주는거라 재부팅할때마다 이름 바뀔 수 있으므로 가능하면 uuid 같은 영구 장치명을 사용하자
- SATA, SSA:
/dev/sda
,/dev/sdb
- NVMe SSD:
/dev/nvme0n1
,/dev/nvme1n1
디바이스 드라이버
- 장치 안에 내장된 레지스터 영역에 써준다. 그렇게 장치를 조작한다.
프로세스가 장치 조작하는 법
- 프로세스가 디바이스 파일을 사용해 디바이스 드라이버에게 장치 조작하고 싶다고 요청
- CPU가 커널 모드로 전환되고 디바이스 드라이버가 레지스터 사용해 장치에 요청 전달
- 장치가 처리 후 디바이스 드라이버가 완료 결과 받음 (폴링이나 인터럽트로 결과 받음)
- CPU가 사용자 모드로 전환되고 프로세스가 결과 받음
<[7장] 파일 시스템>
대부분 저장장치는 디바이스 파일이 아니라 파일 시스템으로 접근한다.
- 없으면 디스크 어떤 위치에 써야할지 직접 정해야 한다.
- 커널 모드안의 파일 시스템 코드가 프로세스 ↔ 하드웨어 간 데이터 읽고 쓰기 해준다.
- 디바이스 파일 대신 파일 시스템이 대신 해줌
쿼터(quota)
- 파일 시스템이 무한정 시스템 용량 사용 못하게 막음
- 사용자 쿼터:
/home
디렉토리 가득 못 차게 방지
파일 시스템 오류 방지 기술: 저널링, 카피 온 라이트
- mv 같은 파일 옮기다 중간에 오류나면 어떻게 해결할거냐
저널링
- 갱신 필요한 아토믹 처리 목록을 트랜스로그 처럼 저널로그에 기록함
- 만약 중간에 에러나면 저널 로그 보고 처리함
카피 온 라이트
- 파일 새로 복사해서 거기다 작업 후 완료되면 오래된 파일 삭제한다.
- 중간에 오류나면 새로 복사한거 버리면 됨
메모리 기반 파일 시스템
- tmpfs
- 컴 끄면 내용 사라짐, 속도 빠름
/tmp
,/var/run
<[8장] 메모리 계층>
레지스터 > 캐시 메모리 > 메모리 > 저장 장치
캐시 메모리 (레지스터 ↔ 메모리)
- CPU 가 동작하는게 명령 내용에 따라 메모리에서 레지스터로 데이터를 읽어들이고, 계산 후 결과를 메모리에 다시 저장한다.
- 레지스터 계산 시간에 비해 메모리 접근 속도는 너무 느리다.
- 중간에 캐시 메모리를 CPU 내부에 둬서 버퍼 역할을 하면 수 배~수십 배 빨라진다.
- 메모리에서 캐시 메모리로 읽어들이는 단위: 캐시라인
- CPU 가 결과를 캐시 메모리에 쓰면 데이터가 변경됐다는
dirty
표시를 붙인다.- write-through (바로 쓰기) : 캐시 메모리 기록과 동시에 메모리에도 바로 기록한다.
- write-back (나중에 쓰기) : 정해진 때에 메모리에 기록한다.
- 캐시메모리가 꽉 찼다면
- dirty 는 메모리에 저장하고 clean 처리 후 버린다.
- 이렇게 계속해서 메모리 영역에 접근하게 되면 thrashing 상태(캐시라인 내부 데이터가 빈번히 교체됨) 돼서 처리 성능이 떨어진다.
- 참조 지역성: 캐시 메모리에 읽을거같은 걸 예측해서 미리 가져온다.
- 시간적 지역성: 최근에 접근한거
- 공간적 지역성: 가져온 근처에 있는 거
- 최근에는 캐시 메모리를 계층화된 구조로 관리한다.
- L1 캐시(레지스터에 제일 가까움, 빠르고 용량 적음) > L2 > L3 (느리고 용량 많음)
- SMT (Simultaneous Multi Threading)
- 캐시메모리라고 해도 CPU 계산시간이 역시 훨씬 빠르다.
- CPU 계산 자원 중에 정수 연산 유닛과 부동 소수점 연산 유닛이 있는데, 정수 연산만 하면 나머지 유닛은 놀고 있다.
- SMT 동시 멀티 스레딩 기능으로 시간 단축을 한다.
페이지 캐시 (메모리 ↔ 저장 장치)
- 저장장치에 접근하는 속도는 CPU의 메모리 접근 속도에 비해 HDD 는 1000배 이상 느리다
- 파일 데이터를 메모리에 캐시하고, 단위는 페이지 이다.
버퍼 캐시
- 디스크 데이터 중 파일 데이터 이외의 것을 캐시한다.
- 파일 시스템 안 쓰고 디바이스 파일로 저장장치 직접 접근할 때, 파일 크기 등 메타 데이터 접근할 때 쓴다.
<[9장] 블록 계층>
- : 블록 장치(=저장 장치) 성능 향상을 위한 커널 기능
- 파일 시스템이 블록 계층에 요청하고 블록 계층이 장치 드라이버에 접근한다.
기능
- 입출력 스케줄러: 블록 장치 접근 요청 잠시 보류 후 빨리 읽을 수 있게 읽는 방법을 최적화한다.
- 미리 읽기: 방금 읽은 영역 근처를 미리 읽어 페이지 캐시에 보관한다.
- HDD 에서 읽어야할 섹터들을 합치고 정렬(입출력 스케줄러)하거나 미리 읽어서 최소한의 암을 회전해 읽을 수 있게 최적화한다.
성능 측정
- throughput: 단위 시간 당 데이터 전송량
- latency: 응답 속도
- IOPS (IO Per Second): 초당 처리 가능한 입출력 횟수
<[10장] 가상화 기능>
CPU 모드
- VMX-root 모드: 물리 기기 처리
- VMX-nonroot 모드: 가상 머신 처리
<[11장] 컨테이너>
구현 방법
- 커널의 네임스페이스(ns) 기능 활용
- 네임스페이스에 소속된 프로세스들은 독립된 자원인 것처럼 만들어준다.
- root ns 에 소속된 프로세스는 하위 ns 를 접근할 수 있지만 하위 ns 는 상위 ns 에 접근 못 한다.
- 즉, 컨테이너는 독립된 네임스페이스를 가지고 다른 프로세스와 실행 환경이 나뉘는 프로세스를 뜻한다.
<[12장] cgroup>
- 메모리나 CPU 같은 자원을 어떤 프로세스에 얼마나 쓰게할지 제어할 수 있는 기능 (c: control)
cgroup 컨트롤러 종류
- cpu 컨트롤러, 메모리 컨트롤러, 네트워크 컨트롤러 등
/sys/fs/cgroup
에서 파일에 작성하는 형태로 설정
<[13장] 이 책에서 배운 내용과 활용법>
• sar
를 장애 났을 때 상태 파악 용으로 잘 활용하자
'SearchDeveloper > 책' 카테고리의 다른 글
[후기] 도메인 주도 개발 시작하기 (0) | 2023.03.19 |
---|