| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | |||
| 5 | 6 | 7 | 8 | 9 | 10 | 11 |
| 12 | 13 | 14 | 15 | 16 | 17 | 18 |
| 19 | 20 | 21 | 22 | 23 | 24 | 25 |
| 26 | 27 | 28 | 29 | 30 | 31 |
- MVC
- model
- 냄새라도
- 이벤트핸들러등록
- 로그백
- 공통기술
- 설정세팅
- 클린아키텍처
- 공통규약
- 커뮤니티서버
- TDD
- JDBC
- 문제선택근거
- 사면초가
- Transaction
- JPA
- string
- SEQUENCE
- 디스크i/o
- OOP
- SpringLegacy
- MVC요청플로우
- 이벤트핸들러this
- index
- 전전긍긍
- Ajax
- springsecurity
- DDD
- 단위테스트
- AOP
- Today
- Total
개발이군고구마
리눅스 운영체제 본문
0. 들어가며
catalina.out이 왜 무한히 커지는지, 2>&1이 무슨 뜻인지, systemd가 왜 필요한지
— 이 질문들의 답은 전부 "프로세스(Process)"와 "파일 디스크립터(File Descriptor)"라는 단 두 개의 뿌리 개념에서 나옴.

1. 리눅스의 근본 철학: "모든 것은 파일이다"
리눅스를 이해하는 첫 번째 열쇠는 "Everything is a file" 이라는 설계 철학임.
여기서 말하는 "파일"은 우리가 아는 텍스트 문서만이 아님. 리눅스는 아래의 모든 것을 파일이라는 동일한 인터페이스로 다룸.
| 종류 | 예시 | 설명 |
| 일반 파일 | /etc/hosts |
실제 데이터를 담은 파일 |
| 디렉터리 | /home |
다른 파일들의 목록을 담은 특수 파일 |
| 장치 파일 | /dev/sda, /dev/null |
디스크, 키보드 같은 하드웨어를 파일처럼 표현 |
| 소켓 · 파이프 | /var/run/*.sock |
프로세스 간 통신 통로 |
| 프로세스 정보 | /proc/1234/ |
실행 중인 프로세스의 상태를 파일로 표현 |
핵심 함의: 리눅스에서는 디스크에 쓰든, 화면에 출력하든, 네트워크로 보내든 — 프로그램 입장에서는 전부 "파일에 읽고 쓰는" 동일한 동작임. 이 통일성이 다음에 나올 파일 디스크립터를 이해하는 전제가 됨.
2. 파일 디스크립터(File Descriptor): 0, 1, 2의 정체
JVM(자바 프로그램)을 실행하는 순간의 OS 내부 모습
- 프로세스 메모리 할당: OS가 JVM을 위한 메모리 공간을 만들고 프로세스 ID(PID)를 부여
- FD 테이블 생성: 이때 이 JVM 전용의 FD 테이블(배열)도 커널 공간에 함께 생성
- 기본 티켓(0, 1, 2) 발급: OS는 묻지도 따지지도 않고 이 테이블의 앞자리 3개를 채워줌.
- 0번(표준 입력) ➔ 시스템의 키보드 입력 스트림과 연결
- 1번(표준 출력) ➔ 시스템의 모니터 콘솔 출력 스트림과 연결
- 2번(표준 에러) ➔ 시스템의 모니터 콘솔 에러 스트림과 연결

2.1 파일 디스크립터란
프로세스가 파일을 열면, 운영체제(커널)는 그 파일에 접근할 수 있는 정수 번호표(티켓)를 발급함. 이 번호가 바로 파일 디스크립터(FD)임. 프로세스는 파일의 실제 경로를 매번 들고 다니지 않고, 이 번호만으로 "3번 파일에 써줘"라고 커널에 요청함. 각 프로세스는 자신만의 FD 테이블을 가짐.
- FD 테이블은 프로세스가 커널에게 일을 시키기 위한 '주문서 ID 목록'
- "내가 가진 0번에 있는 거 읽어줘", "내가 가진 3번에 이거 적어줘"처럼 프로세스가 주도적으로 자기 테이블의 번호를 커널에 던지며 요청
- 커널은 요청을 받으면 그 요청을 보낸 프로세스가 누구인지 확인(PID)하고, 그 프로세스의 FD 테이블을 열어서 해당 번호에 연결된 진짜 물리 장치(키보드/모니터/디스크)에 명령을 전달합니다.
[JVM 프로세스] [운영체제 커널]
│ │
│ 1. "recipe.txt 파일 좀 열어줘" │
└──────────────────────────────────────────>│
│ 2. 하드디스크에서 파일 위치 탐색 및 권한 체크
│ 3. JVM의 FD 테이블에서 비어있는 가장 작은
│ 번호(예: 3번)에 파일 정보 연결
<───────────────────────────────────────────┤
│ 4. "너의 3번 티켓에 등록해뒀어. 3 받아라." │
│ │
│ │
│ 5. "방금 받은 3번 파일에 '설탕 2스푼' 써줘" │
└──────────────────────────────────────────>│
│ 6. JVM의 FD 테이블 3번 확인 ➔ recipe.txt 매핑
│ 7. 실제 하드디스크의 해당 구역에 데이터 기록
<───────────────────────────────────────────┤
│ 8. "기록 완료" 응답 │
2.2 0, 1, 2는 예약된 자리
리눅스는 프로세스가 시작될 때 FD 0, 1, 2를 자동으로 미리 열어둠. 이것이 그토록 자주 보이는 0, 1, 2의 정체임.
| FD | 이름 | 표준 명칭 | 기본 연결 대상 | 용도 |
0 |
표준 입력 | stdin | 키보드 | 프로그램이 입력을 받는 통로 |
1 |
표준 출력 | stdout | 화면(터미널) 모니터 콘솔 | 정상 결과를 내보내는 통로 |
2 |
표준 에러 | stderr | 화면(터미널) 에러 콘솔 | 에러 메시지를 내보내는 통로 |

2.3 왜 stdout과 stderr를 나눴는가
가장 자주 나오는 질문임. 화면에 찍히는 건 똑같아 보이는데 왜 굳이 통로를 두 개로 나눴을까?
정상 결과와 에러를 따로 처리할 수 있게 하려고 나눔. 예를 들어 아래처럼 활용함.
- 정상 결과(
1)만 파일로 저장하고, 에러(2)는 화면에 그대로 보여주고 싶을 때 - 반대로 에러(
2)만 별도 로그 파일로 모으고 싶을 때 - 스크립트에서 "성공 결과"와 "실패 원인"을 다른 시스템으로 보내야 할 때
이 분리 덕분에 다음 장의 리다이렉션이 강력해짐.
3. 표준 스트림과 리다이렉션: catalina.out의 비밀
리다이렉션(Redirection)은 FD가 가리키는 대상을 바꿔치기하는 것임. 기본적으로 화면을 가리키는 1, 2를 파일 쪽으로 돌려버리는 동작임.
3.1 기본 리다이렉션 기호
| 기호 | 의미 | 비고 |
> file |
stdout(1)을 file로 (덮어쓰기) | 1>의 축약형 |
>> file |
stdout(1)을 file로 (이어쓰기) | 기존 내용 보존 |
2> file |
stderr(2)를 file로 | 에러만 저장 |
< file |
stdin(0)을 file에서 읽기 | 입력 리다이렉션 |
2>&1 |
stderr(2)를 현재 stdout(1)이 가리키는 곳으로 | 아래에서 상세 설명 |
&> file |
stdout·stderr를 동시에 file로 | bash 확장 문법 |
3.2 2>&1을 정확히 읽는 법
가장 헷갈리는 부분임. 2>&1은 "2번을, 현재 1번이 가리키는 곳과 같은 곳으로 보내라"는 뜻임. 여기서 &1은 "숫자 1인 파일"이 아니라 "FD 1"을 의미하는 표기임. (&가 없으면 1이라는 이름의 파일로 인식됨.)
순서가 결정적으로 중요함. 리다이렉션은 왼쪽에서 오른쪽으로 순차 적용되기 때문임.
# (O) 올바른 경우: 1을 먼저 file로 보내고, 그다음 2를 "1이 가리키는 곳(=file)"으로 보냄
command > file 2>&1
# 결과: stdout, stderr 모두 file로 저장됨
# (X) 흔한 실수: 2를 먼저 "1이 가리키는 곳(=화면)"으로 보내고, 그다음 1만 file로 바꿈
command 2>&1 > file
# 결과: stderr는 여전히 화면으로, stdout만 file로 감

3.3 /dev/null: 출력 버리기
/dev/null은 무엇을 써도 즉시 사라지는 특수 장치 파일(블랙홀)임. 불필요한 출력을 버릴 때 사용함.
command > /dev/null 2>&1 # 정상·에러 출력 모두 버림 (조용히 실행)
3.4 이제 catalina.out을 해석함
Tomcat을 실행하면 catalina.out이라는 파일이 생기고, 운영이 길어질수록 이 파일이 수 GB까지 무한히 커져서 디스크를 채우는 문제를 겪게 됨. 그 원인이 위 개념으로 완벽히 설명됨.
Tomcat의 실행 스크립트(catalina.sh)는 내부적으로 애플리케이션의 stdout(1)과 stderr(2)를 전부 catalina.out으로 리다이렉션함. 구조적으로 아래와 같음.
# catalina.sh 내부의 동작을 단순화한 형태
java org.apache.catalina.startup.Bootstrap start >> "$CATALINA_OUT" 2>&1 &
여기서 발생하는 핵심 문제:
catalina.out은 애플리케이션의 모든 stdout/stderr가 이어쓰기(>>)로 쌓이는 파일임.System.out.println, 스택 트레이스, 서드파티 라이브러리 출력이 전부 여기로 감.- 그런데
catalina.out은 Tomcat이 자동으로 로테이션(잘라내기)하지 않음. Log4j/Logback으로 설정한 애플리케이션 로그는 날짜별로 잘리지만,catalina.out은 그 관리 대상 밖임. - 결과적으로 파일이 무한정 커지다가 디스크를 가득 채움 → 서버 장애로 이어짐.
💡 이는 예전에 겪은 Vector의 nohup.out 누적으로 인한 디스크 풀 장애와 정확히 같은 메커니즘임.
"stdout/stderr가 로테이션되지 않는 단일 파일로 무한히 쌓임" — 이것이 문제의 본질임.
해결책은 8장의 logrotate에서 다룸.
4. 프로세스(Process): 실행 중인 프로그램의 실체
FD가 파일 쪽 뿌리라면, 프로세스는 실행 쪽 뿌리임.
4.1 프로세스의 정의
프로세스 = 메모리에 올라가 실행 중인 프로그램의 인스턴스임. 디스크에 있는 java 실행 파일은 "프로그램"이고, 그것을 실행해서 메모리에 올라간 상태가 "프로세스"임.
모든 프로세스는 아래 정보를 가짐.
- PID (Process ID): 프로세스 고유 번호
- PPID (Parent PID): 자신을 실행시킨 부모 프로세스의 번호
- FD 테이블: 앞서 본 0/1/2를 포함한, 이 프로세스가 연 파일 목록
- 소유자(UID): 어떤 사용자 권한으로 실행 중인지
4.2 프로세스는 나무처럼 이어짐 (부모-자식)
리눅스의 모든 프로세스는 부모가 자식을 낳는 트리 구조임. 최상위 조상은 부팅 시 커널이 만드는 PID 1임. (요즘 배포판에서는 이 PID 1이 바로 systemd임 — 7장 연결점.)

이 부모-자식 관계가 다음 장의 nohup, &, 그리고 시그널(signal)을 이해하는 열쇠임.
4.3 프로세스 확인 명령어
ps aux # 전체 프로세스 목록 (소유자, CPU, 메모리 포함)
ps -ef # 부모-자식(PPID) 관계 확인에 유용
top / htop # 실시간 리소스 사용량 모니터링
pstree # 프로세스 트리 구조를 시각적으로 표시
lsof -p <PID> # 특정 프로세스가 연 파일(FD) 목록 확인
💡 lsof -p <PID>로 catalina.out처럼 이미 삭제됐지만 프로세스가 아직 붙잡고 있어 디스크가 안 비는(deleted 표시) 파일을 찾아낼 수 있음. 디스크 풀 트러블슈팅의 필수 도구임.
4.4 시그널(Signal): 프로세스에게 보내는 신호
프로세스를 제어할 때 커널을 통해 시그널을 보냄. kill 명령어는 "죽이는 것"이 아니라 "시그널을 전달하는 것"임.
| 시그널 | 번호 | 의미 | 특징 |
SIGTERM |
15 | 정상 종료 요청 | 프로세스가 뒷정리 후 종료 (기본값) |
SIGKILL |
9 | 강제 종료 | 무시 불가, 뒷정리 없이 즉시 죽음 (최후의 수단) |
SIGHUP |
1 | 터미널 연결 끊김 | 다음 장의 핵심 |
SIGINT |
2 | 인터럽트 | Ctrl + C가 보내는 시그널 |
kill <PID> # 기본 SIGTERM (정상 종료) — 먼저 시도할 것
kill -9 <PID> # SIGKILL (강제 종료) — 정말 안 죽을 때만
⚠️ 운영에서 무조건 kill -9부터 쓰는 습관은 위험함. SIGKILL은 프로세스가 진행 중이던 트랜잭션이나 파일 쓰기를 마무리할 기회를 주지 않아 데이터 손상을 유발할 수 있음. SIGTERM → 안 되면 SIGKILL 순서를 지킬 것.
5. 데몬과 백그라운드 실행: nohup, &, 그리고 그 한계
5.1 데몬(Daemon)이란
데몬 = 사용자와 직접 상호작용하지 않고 백그라운드에서 계속 도는 서비스 프로세스임. 웹 서버(nginx), DB, sshd 등이 데몬임. 관례적으로 이름 끝에 d가 붙음(systemd, sshd, httpd).
5.2 &와 nohup: 초보가 서비스를 띄우는 방식
터미널에서 프로그램을 백그라운드로 띄우는 가장 원시적인 방법임.
./start.sh & # & : 백그라운드로 실행 (터미널을 다시 쓸 수 있음)
nohup ./start.sh & # nohup : 터미널이 끊겨도 계속 실행되게 함
여기서 4.4의 SIGHUP이 등장함. 터미널(SSH 세션)을 닫으면, 그 세션에 속한 자식 프로세스들에게 SIGHUP(연결 끊김) 시그널이 전달되어 함께 죽음. nohup은 이 SIGHUP을 무시(no hang up)하도록 만들어서 세션이 끊겨도 프로세스가 살아남게 함.
5.3 nohup.out은 왜 생기는가 (그리고 왜 위험한가)
nohup으로 실행하면, 터미널(화면)로 향하던 stdout/stderr가 갈 곳을 잃음. 그래서 nohup은 출력을 nohup.out이라는 파일로 자동 리다이렉션함. 즉 아래와 사실상 동일함.
nohup ./start.sh > nohup.out 2>&1 &
이제 문제가 보임. nohup.out도 catalina.out과 똑같이 로테이션되지 않는 단일 파일에 무한히 쌓이는 구조임. 이것이 예전에 겪은 Vector 프로세스의 nohup.out 누적 → 디스크 풀 장애의 근본 원인임.
5.4 nohup/& 방식의 근본적 한계
nohup & 방식은 급할 때 임시로 쓰기엔 편하지만, 운영 서비스를 이 방식으로 띄우면 안 됨. 이유는 다음과 같음.
- 자동 재시작 안 됨: 프로세스가 죽으면 그대로 끝임. 누군가 수동으로 다시 띄워야 함.
- 부팅 시 자동 실행 안 됨: 서버가 재부팅되면 서비스가 안 올라옴.
- 로그 관리 안 됨:
nohup.out이 무한히 커짐. - 상태 관리 불가: 표준화된 시작/중지/상태 확인 방법이 없음.
이 모든 한계를 해결하기 위해 등장한 것이 바로 systemd임.
6. systemd: 현대 리눅스의 서비스 관리자
6.1 systemd의 위치
systemd는 부팅 직후 커널이 가장 먼저 실행하는 PID 1 프로세스이며, 시스템의 모든 서비스를 관리하는 최상위 관리자임. 앞서 본 nohup &의 모든 한계(재시작, 부팅 실행, 로그, 상태 관리)를 표준화된 방식으로 해결함.

6.2 유닛 파일(Unit File): 서비스의 설계도
systemd는 각 서비스를 유닛 파일(.service)로 정의함. 이 파일 하나에 "어떻게 실행하고, 죽으면 어떻게 할지"를 전부 선언함. nohup &을 여러 줄로 흩어놓던 것을 하나의 명세로 대체하는 개념임.
# /etc/systemd/system/myapp.service
[Unit]
Description=My Application
After=network.target # 네트워크가 준비된 후 실행
[Service]
User=appuser # 실행할 사용자 (권한 관리)
ExecStart=/opt/app/start.sh # 실행 명령
Restart=on-failure # 비정상 종료 시 자동 재시작 ★
RestartSec=5 # 5초 후 재시작
StandardOutput=journal # stdout을 journald로 (★ nohup.out 문제 해결)
StandardError=journal # stderr을 journald로
[Install]
WantedBy=multi-user.target # 부팅 시 자동 시작 대상에 포함
여기서 StandardOutput=journal이 중요함. nohup.out/catalina.out처럼 파일로 무한히 쌓는 대신, systemd의 로깅 시스템(journald)이 출력을 받아 자동으로 용량 관리해줌.
6.3 systemctl: 서비스 제어 명령어
systemctl start myapp # 시작
systemctl stop myapp # 중지 (내부적으로 SIGTERM 전달)
systemctl restart myapp # 재시작
systemctl status myapp # 현재 상태·최근 로그 확인 (가장 자주 씀)
systemctl enable myapp # 부팅 시 자동 시작 등록
systemctl daemon-reload # 유닛 파일 수정 후 반드시 실행 (설정 재적용)
6.4 journalctl: systemd의 로그 조회
systemd로 띄운 서비스의 로그는 journalctl로 조회함. catalina.out을 tail로 뒤지던 것을 대체하는, 훨씬 강력한 방식임.
journalctl -u myapp # 특정 서비스의 로그 전체
journalctl -u myapp -f # 실시간 로그 추적 (tail -f 와 유사)
journalctl -u myapp --since "1 hour ago" # 시간 필터
journalctl -u myapp -p err # 에러 레벨만 필터
💡 정리: nohup ./app & → catalina.out을 tail -f로 보던 방식에서, systemctl start app → journalctl -u app -f로 보는 방식으로 넘어가는 것이 주니어에서 인프라 엔지니어로 가는 핵심 전환점임.
7. 로그와 디스크: 왜 서버가 꽉 차는가 (logrotate)
3장·5장에서 본 catalina.out/nohup.out 무한 증식 문제의 정석 해결책이 logrotate임.
7.1 logrotate란
logrotate = 로그 파일을 주기적으로 잘라내고(rotate), 오래된 것은 압축·삭제하는 도구임. 대부분의 리눅스에 기본 설치되어 있고, 매일 cron으로 자동 실행됨.
"로테이션"의 동작은 다음과 같음.
graph LR
A["app.log (현재)"] -->|"매일 자정"| B["app.log.1"]
B --> C["app.log.2.gz (압축)"]
C --> D["app.log.3.gz"]
D --> E["30일 지나면 삭제"]
7.2 catalina.out을 위한 설정 예시
# /etc/logrotate.d/tomcat
/opt/tomcat/logs/catalina.out {
daily # 매일 로테이션
rotate 14 # 14개(14일치)까지 보관
compress # 오래된 로그는 gzip 압축
missingok # 파일 없어도 에러 안 냄
notifempty # 비어 있으면 로테이션 안 함
copytruncate # ★ 아래 설명 참조
}
7.3 copytruncate가 중요한 이유
catalina.out처럼 프로세스가 파일을 계속 붙잡고 쓰고 있는 경우 특별한 주의가 필요함.
일반적인 로테이션은 파일 이름을 바꿈(mv). 그런데 4장에서 봤듯 프로세스는 파일 이름이 아니라 FD(번호표)로 파일을 붙잡고 있음. 이름을 바꿔도 프로세스는 여전히 같은 FD로 옛 파일에 계속 씀 → 새 catalina.out은 안 생기고 디스크는 계속 참.
copytruncate는 이를 우회함. 원본을 복사한 뒤, 원본 파일의 내용만 0으로 비움(truncate). 프로세스가 붙잡은 FD는 그대로 유지되므로, 프로세스는 눈치채지 못하고 비워진 파일에 계속 씀. 이것이 재시작 없이 catalina.out을 안전하게 관리하는 핵심 옵션임.
💡 더 나은 해결책: 애초에 catalina.out에 stdout/stderr를 몰아넣지 않고, 애플리케이션 로그를 Logback/Log4j2로 파일 롤링 정책과 함께 설정하는 것임. catalina.out은 최소한의 부트 로그만 남게 하고, 나머지는 로깅 프레임워크가 관리하도록 분리하는 것이 정석임.
8. 권한과 소유권: 운영의 기본 안전장치
인프라 운영에서 "Permission denied"는 매일 마주치는 문제임. 권한 모델을 정확히 알아야 함.
8.1 소유권과 권한 3분할
모든 파일은 소유자(User) / 그룹(Group) / 그 외(Others) 세 주체에 대해 각각 읽기(r) / 쓰기(w) / 실행(x) 권한을 가짐.
-rwxr-xr-- 1 appuser devops 4096 Jul 12 10:00 start.sh
│└┬┘└┬┘└┬┘ └──┬──┘ └─┬─┘
│ │ │ │ 소유자 그룹
│ │ │ └─ others: r-- (읽기만)
│ │ └──── group: r-x (읽기·실행)
│ └─────── user: rwx (읽기·쓰기·실행)
└───────── 파일 타입 (- 일반파일, d 디렉터리, l 링크)
8.2 숫자(8진수) 표기
권한은 r=4, w=2, x=1의 합으로 숫자화함.
| 숫자 | 권한 | 의미 |
7 |
rwx |
읽기+쓰기+실행 (4+2+1) |
6 |
rw- |
읽기+쓰기 (4+2) |
5 |
r-x |
읽기+실행 (4+1) |
755 |
rwxr-xr-x |
소유자 전체, 그룹·기타는 읽기·실행 (실행 파일 표준) |
644 |
rw-r--r-- |
소유자 읽기·쓰기, 나머지 읽기만 (설정·문서 표준) |
chmod 755 start.sh # 권한 변경
chown appuser:devops file # 소유자·그룹 변경
⚠️ 운영에서 chmod 777(모두에게 전체 권한)을 남발하는 것은 심각한 보안 위험임. "권한 문제 같으니 일단 777" 습관은 반드시 버려야 함. 필요한 최소 권한만 부여하는 것이 원칙(최소 권한 원칙)임.
9. 셸과 환경: 명령어가 실행되는 맥락
9.1 셸(Shell)이란
셸은 사용자의 명령을 받아 커널에 전달하는 해석기임. bash, zsh 등이 있음. 우리가 터미널에 치는 모든 명령어는 셸이 해석해서 프로세스로 실행함.
9.2 환경 변수(Environment Variable)
프로세스가 실행될 때 참조하는 설정값들임. 4장에서 본 것처럼 자식 프로세스는 부모의 환경 변수를 물려받음.
echo $PATH # 명령어를 찾는 디렉터리 목록
echo $JAVA_HOME # 자바 설치 경로
export APP_ENV=prod # 환경 변수 설정 (자식 프로세스에 상속됨)
env # 현재 모든 환경 변수 출력
💡 PATH는 특히 중요함. java라고만 쳐도 실행되는 이유는 셸이 $PATH에 나열된 디렉터리들을 순서대로 뒤져 java 실행 파일을 찾기 때문임. "command not found"는 대부분 PATH 문제임.
9.3 파이프(|)와 명령어 조합
파이프는 한 명령어의 stdout(1)을 다음 명령어의 stdin(0)으로 연결하는 것임. 2장의 FD 개념이 여기서도 그대로 쓰임.
# tomcat 프로세스의 PID만 뽑아내는 조합
ps -ef | grep tomcat | grep -v grep | awk '{print $2}'

9.4 실무에서 자주 쓰는 필수 명령어
| 목적 | 명령어 |
| 디스크 사용량 확인 | df -h (파티션별), du -sh * (디렉터리별) |
| 큰 파일 찾기 | find / -type f -size +1G |
| 메모리 확인 | free -h |
| 포트·연결 확인 | ss -tnlp (구 netstat) |
| 로그 실시간 추적 | tail -f app.log |
| 텍스트 검색 | grep -r "keyword" /path |
| 네트워크 응답 확인 | curl -I https://... |
'SERVER > CS' 카테고리의 다른 글
| [리눅스 심화 ①] 프로세스는 어떻게 태어나고, 격리되고, 컨테이너가 되는가 (0) | 2026.07.12 |
|---|---|
| EC2 리눅스 OS 서버 데이터 저장 구조 (1) | 2026.07.12 |
| 로그 (0) | 2026.06.07 |
| PuTTY로 SSH 접속하면 서버에서 무슨 일이 일어날까 (0) | 2026.03.27 |
| OS와 CPU의 작동 원리, 그리고 CPU 100% 문제 해결 (0) | 2026.03.27 |