Linux 시스템 콜(system call)은 사용자 공간 프로그램이 kernel에 파일, process, memory, network 같은 작업을 요청하는 ABI 경계다. 애플리케이션 코드의 함수 하나가 시스템 콜 하나와 반드시 일대일로 대응하는 것은 아니다. runtime·libc wrapper가 여러 시스템 콜을 조합하거나, 다른 이름의 시스템 콜을 선택하거나, vDSO로 kernel 진입을 피할 수도 있다.
운영에서 유용한 질문은 시스템 콜 이름을 많이 외우는 것이 아니라 “이 process가 어떤 kernel 요청에서 기다리거나 실패하는가”다. strace로 반환값, errno, file descriptor와 걸린 시간을 함께 보면 그 경계를 좁힐 수 있다.
사용자 함수에서 kernel까지의 흐름
애플리케이션 코드
↓
언어 runtime·표준 라이브러리·libc wrapper
↓
architecture별 system call ABI
↓
Linux kernel: 권한 검사와 자원 작업
↓
return value 또는 -1 + errno
예를 들어 C의 open()이나 Python의 open()을 추적했을 때 Linux에서는 openat()이 보일 수 있다. 고수준 함수의 이름과 실제 kernel entry point가 같을 것이라고 가정하면 trace를 잘못 읽는다.
시스템 콜 진입은 사용자 mode에서 kernel mode로 실행 권한을 전환하지만, 곧바로 다른 process로 바뀌는 scheduler context switch와 같은 말은 아니다. 같은 thread가 kernel code를 실행한 뒤 돌아올 수도 있고, I/O를 기다리며 잠들 때 scheduler가 다른 thread를 실행할 수도 있다.
자주 보는 시스템 콜을 작업별로 묶는다
| 질문 | 관련 시스템 콜 예 | 확인할 결과 |
|---|---|---|
| 어떤 파일을 열지 못했나 | openat, newfstatat, readlink |
ENOENT, EACCES, 실제 path |
| 어디에서 읽고 쓰나 | read, write, pread64, pwrite64 |
fd, byte 수, EOF, partial I/O |
| memory를 어떻게 확보하나 | mmap, munmap, mprotect, brk |
mapping 크기와 protection |
| process를 어떻게 만들고 바꾸나 | clone, fork, execve, wait4 |
child PID, executable, exit status |
| network 어디에서 막히나 | socket, bind, connect, accept4, sendto, recvfrom |
address, fd, ECONNREFUSED, timeout |
| 무엇을 기다리나 | futex, epoll_wait, poll, nanosleep |
wait 대상과 머문 시간 |
이름은 architecture와 kernel·libc version에 따라 다르게 보일 수 있다. 사용하는 host의 syscalls(2)와 개별 manual page를 기준으로 인자와 반환값을 확인한다.
strace 한 줄을 읽는 법
다음과 비슷한 출력이 있다고 하자.
openat(AT_FDCWD, "/etc/hosts", O_RDONLY|O_CLOEXEC) = 3</etc/hosts> <0.000042>
openat: 호출된 시스템 콜AT_FDCWD, path, flags: 인자= 3: 성공 반환값인 file descriptor</etc/hosts>:-yy가 덧붙인 fd 경로 정보<0.000042>:-T가 표시한 호출 안의 경과 시간
실패하면 -1 뒤에 errno가 나온다.
openat(AT_FDCWD, "/missing", O_RDONLY) = -1 ENOENT (No such file or directory)
애플리케이션 로그의 “설정 파일을 읽지 못했다”보다 실제로 시도한 path와 ENOENT를 보면 working directory, mount와 배포 누락을 구분하기 쉽다.
새 command를 좁혀 추적한다
파일·process·network 관련 호출만 보고 timestamp, 호출 시간과 fd 정보를 함께 표시한다.
strace -f -tt -T -yy \
-e trace=%file,%process,%network \
-- command arg1 arg2
-f: 생성된 child process·thread도 따라간다.-tt: 각 event의 wall-clock timestamp를 표시한다.-T: 각 system call 안에서 보낸 시간을 표시한다.-yy: file descriptor와 연결된 path·socket 정보를 더 보여 준다.-e trace=...: 필요한 범주만 남긴다.
호출 횟수와 시간 요약이 필요하면 별도 재현 환경에서 -c를 쓸 수 있다.
strace -f -c -- command arg1
이 수치는 tracer가 개입한 상태의 관측값이다. microbenchmark의 절대 성능이나 production latency를 그대로 대표한다고 보면 안 된다.
실행 중인 process에 attach할 때의 주의점
strace -f -p PID
strace는 ptrace를 이용해 tracee의 system call과 signal을 관찰한다. attach는 thread 실행을 멈추고 재개하는 과정을 추가하므로 timing과 성능에 영향을 줄 수 있다. 지연에 민감하거나 부하가 큰 production process라면 짧은 시간, 좁은 filter와 안전한 중단 절차를 먼저 정한다.
container에서는 user namespace, seccomp profile, Yama ptrace_scope, capability 설정 때문에 attach가 거부될 수 있다. 이를 해결하려고 곧바로 privileged container로 바꾸기보다 필요한 권한과 데이터 노출 범위를 검토한다.
trace에는 다음과 같은 민감 정보가 나타날 수 있다.
- command-line argument와 environment를 통해 전달된 secret
- 파일 경로와 사용자 이름
read·writebuffer의 일부- socket address와 프로토콜 payload
출력을 공유하기 전에 redaction하고, -s로 문자열 길이를 늘릴 때는 수집 범위가 커진다는 점을 인지한다.
strace에 안 보인다고 호출이 없었던 것은 아니다
Linux는 자주 쓰는 시간 조회 같은 기능을 vDSO로 사용자 공간에 제공할 수 있다. libc가 vDSO 함수를 사용하면 실제 system call trap이 발생하지 않으므로 strace에도 나타나지 않는다.
또한 buffered I/O는 애플리케이션의 여러 write()를 한 번의 kernel write로 합치거나, 한 번의 read로 가져온 데이터를 여러 고수준 호출에 나눠 줄 수 있다. JIT와 async runtime도 고수준 작업과 system call의 대응을 바꾼다.
따라서 trace가 없다는 사실은 “그 언어 함수가 실행되지 않았다”가 아니라 관찰한 kernel 경계에 해당 event가 없었다는 뜻으로 해석한다.
진단 순서
- 애플리케이션 로그에서 실패 시간과 process·thread를 정한다.
- 파일, process, network, memory 중 어느 system call 범주가 필요한지 고른다.
- 재현 가능한 command라면 새 process 추적부터 시작한다.
- 반환값과
errno, fd·path·address를 확인한다. -T가 긴 호출이 실제 대기인지 tracer overhead와 함께 판단한다.- system call 아래 kernel 내부가 필요할 때 tracepoint·eBPF로 범위를 더 좁힌다.
kernel 내부 관측 지점을 고르는 기준은 eBPF Hook 선택, socket API 흐름은 TCP·UDP 소켓 프로그래밍, 시스템 콜 약어를 빠르게 찾는 표는 시스템 콜 약어 및 의미에서 이어진다.
참고 자료
'배움과 성장 > 시스템·성능' 카테고리의 다른 글
| CPU와 메모리 차이: 프로그램이 실행될 때 실제로 일어나는 일 (2) | 2024.09.23 |
|---|---|
| Linux CPU 스케줄러 동작: task·run queue·dispatcher 구분하기 (6) | 2024.09.22 |
| macOS에서 smartctl·lspci·ethtool 대신 무엇을 쓸까 (3) | 2024.09.20 |
| macOS에서 free 대신 메모리 확인하기: vm_stat·memory_pressure·top (1) | 2024.09.19 |
| Meltdown·Spectre 차이: transient execution과 CPU 완화책 (0) | 2024.09.19 |
댓글