
서비스 · 프로세스 관리 09 / 50 · Part 1. 프로세스 기초
실습 환경: Rocky Linux 9.8 · Ubuntu 24.04.5 (systemd로 부팅한 Docker 격리 컨테이너, 테스트 계정analyst)
백업이나 로그 압축처럼 CPU를 많이 쓰지만 급하지 않은 작업이 웹 서비스와 같은 서버에서 돌면 서비스 응답이 느려진다. 이럴 때 쓰는 가장 간단한 도구가 nice 값 이다. nice는 "이 프로세스는 CPU를 다른 프로세스에게 양보해도 된다"는 표시다.
이번 글에서는 nice 값의 범위와 권한 규칙을 확인하고, 같은 CPU 코어에서 nice 0과 nice 19를 경쟁시켜 실제 배분이 어떻게 달라지는지 측정한다.
| 항목 | 내용 |
|---|---|
| 범위 | -20 (가장 우선) ~ +19 (가장 양보), 기본값 0 |
| 이름의 의미 | 값이 클수록 다른 프로세스에게 "친절(nice)"하다 = 덜 받는다 |
| 적용 대상 | 일반 스케줄링 정책(SCHED_OTHER, ps에서 TS) 프로세스 |
| 상속 | fork한 자식은 부모의 nice 값을 물려받는다 |
| 작업 | 일반 사용자 | root (CAP_SYS_NICE) |
|---|---|---|
| 자기 프로세스 nice를 올리기 (0 → 10) | 가능 | 가능 |
| 자기 프로세스 nice를 내리기 (10 → 5) | 불가 | 가능 |
| 음수 nice 설정 | 불가 | 가능 |
| 다른 사용자의 프로세스 변경 | 불가 | 가능 |
일반 사용자가 한 번 양보한 CPU를 되찾지 못하게 한 이유는, 모든 사용자가 자기 작업을 최우선으로 올리는 경쟁을 막기 위해서다. 예외적으로 /etc/security/limits.conf의 priority/nice 항목으로 허용 범위를 줄 수 있다.
| 명령어 | 용도 |
|---|---|
nice | 현재 nice 값 출력 |
nice -n 10 CMD | nice 10으로 새로 실행 |
renice -n 15 -p PID | 실행 중인 프로세스 변경 (-u USER, -g PGID도 가능) |
ps -o ni,pri / top의 NI, PR | 확인 |

Linux의 일반 스케줄러(CFS, 6.6 이후 커널은 EEVDF)는 nice 값을 가중치(weight) 로 바꾼다. nice 한 단계마다 약 1.25배 차이가 나며, nice 0은 1024, nice 19는 15다. 같은 코어에서 경쟁하면 가중치 비율대로 CPU 시간을 나눈다.
nice 0 : 가중치 1024 ─┐
├─ 1024 / (1024 + 15) ≈ 98.6 %
nice 19 : 가중치 15 ─┘ 15 / (1024 + 15) ≈ 1.4 %
중요한 점은 nice가 CPU를 두고 경쟁할 때만 의미가 있다는 것이다. 코어가 남아 있으면 nice 19 프로세스도 CPU를 100% 쓸 수 있다. 실습에서 taskset -c 0으로 두 프로세스를 같은 코어에 고정 한 이유다.
ps의
PRI와 top의PR은 계산 방식이 다르다. top의 PR은20 + nice(nice 0 → 20), ps의pri열은 반대 방향 숫자(nice 10 → 9)를 보여 준다. 비교할 때는 NI 열 을 기준으로 한다.
# 1) 일반 사용자 (analyst)
nice # 현재 값
nice -n 10 sleep 100 & # nice 10으로 실행
ps -o pid,ni,pri,stat,cmd -p $!
nice -n -5 sleep 1 # 음수 → 실패
renice -n 15 -p $(jobs -p %1) # 10 → 15 (올리기) 성공
renice -n 5 -p $(jobs -p %1) # 15 → 5 (내리기) 실패
# 2) root: 같은 코어(CPU 0)에서 경쟁
taskset -c 0 timeout 12 sh -c 'while :; do :; done' &
taskset -c 0 nice -n 19 timeout 12 sh -c 'while :; do :; done' &
sleep 8; ps -o pid,ni,psr,%cpu,time,cmd -C sh --sort=ni
renice -n -5 -p $(pgrep -f 'while' | head -1)
# 3) (Ubuntu) 서비스의 nice 값
ps -eo pid,ni,pri,cls,comm --sort=ni | head -6
systemctl show systemd-journald -p Nice



텍스트 원본(실제 출력):
[analyst@rocky9-lab ~]$ nice
0
[analyst@rocky9-lab ~]$ nice -n 10 sleep 100 & sleep 0.2; ps -o pid,ni,pri,stat,cmd -p $!
PID NI PRI STAT CMD
527 10 9 SN+ sleep 100
[analyst@rocky9-lab ~]$ nice -n -5 sleep 1
nice: cannot set niceness: Permission denied
[analyst@rocky9-lab ~]$ renice -n 15 -p $(jobs -p %1)
527 (process ID) old priority 10, new priority 15
[analyst@rocky9-lab ~]$ renice -n 5 -p $(jobs -p %1)
renice: failed to set priority for 527 (process ID): Permission denied
[analyst@rocky9-lab ~]$ kill %1
[root@rocky9-lab ~]# taskset -c 0 timeout 12 sh -c 'while :; do :; done' &
[root@rocky9-lab ~]# taskset -c 0 nice -n 19 timeout 12 sh -c 'while :; do :; done' &
[root@rocky9-lab ~]# sleep 8; ps -o pid,ni,psr,%cpu,time,cmd -C sh --sort=ni
PID NI PSR %CPU TIME CMD
583 0 0 97.6 00:00:07 sh -c while :; do :; done
584 19 0 1.3 00:00:00 sh -c while :; do :; done
[root@rocky9-lab ~]# renice -n -5 -p $(pgrep -f 'while' | head -1) >/dev/null; ps -o pid,ni,pri,cmd -p $(pgrep -f 'while' | head -1)
PID NI PRI CMD
580 -5 24 timeout 12 sh -c while :; do :; done
[root@rocky9-lab ~]# wait 2>/dev/null; true
root@ubuntu-lab:~# ps -eo pid,ni,pri,cls,comm --sort=ni | head -6
PID NI PRI CLS COMMAND
25 -1 20 TS systemd-journal
1 0 19 TS systemd
67 0 19 TS systemd-resolve
80 0 19 TS cron
81 0 19 TS dbus-daemon
root@ubuntu-lab:~# systemctl show systemd-journald -p Nice
Nice=-1
| 관찰 | 의미 |
|---|---|
nice → 0 | 로그인 셸의 기본값 |
NI 10, STAT SN+ | nice 10으로 실행되었고, 04편의 N(낮은 우선순위) 플래그가 붙었다 |
nice -n -5 → Permission denied | 일반 사용자는 음수를 설정할 수 없다 |
old priority 10, new priority 15 | 양보를 늘리는 방향은 허용된다 |
15 → 5 Permission denied | 한 번 올린 값을 되돌리는 것은 root만 가능하다 |
PSR 0 두 프로세스, %CPU 97.6 vs 1.3 | 같은 코어에서 nice 0이 거의 모든 시간을 가져갔다. 이론값(98.6 : 1.4)과 거의 같다 |
TIME 00:00:07 vs 00:00:00 | 8초 동안의 누적 CPU 시간 차이. nice 19 쪽은 1초도 받지 못했다 |
renice 결과가 timeout 12 sh -c ... (PID 580) | pgrep -f 'while'이 timeout 래퍼 프로세스까지 매칭해 엉뚱한 PID를 바꿨다. 실제 루프(sh)는 그대로다 |
Ubuntu journald NI -1, Nice=-1 | 서비스 우선순위는 unit 파일의 Nice=로 설정된다. 로그 수집이 밀리지 않도록 한 기본 설정이다 |
CLS TS | 스케줄링 클래스 SCHED_OTHER(Time Sharing). nice가 적용되는 일반 정책 |
renice 결과의 교훈은 12편에서 다시 다룬다.
pgrep -f는 명령 인자 전체를 검색하므로, 대상 인자를 포함한 다른 프로세스까지 매칭 될 수 있다. 조치 전에는 항상pgrep -a로 먼저 확인한다.
| 주제 | 내용 |
|---|---|
| 마이너의 위장 | 일부 크립토마이너는 nice 19로 실행 해 서비스 영향(응답 지연)을 줄이고 발각을 늦춘다. top의 ni 항목이 계속 높다면 낮은 우선순위의 CPU 과다 사용을 의심한다 |
| 권한 상승 흔적 | 일반 계정 프로세스의 nice가 음수 라면 root 권한으로 설정된 것이다. 누가 설정했는지 확인한다 |
| 보안 에이전트 보호 | EDR·로그 수집기는 부하 상황에서도 밀리지 않도록 음수 nice 또는 높은 CPUWeight=를 준다 |
| DoS 완화 | 사용자 작업 부하로 관리 접속(SSH)까지 느려지는 상황을 줄이려면 사용자 배치 작업에 nice·cgroup 제한을 건다 (18편) |
[Detection] top: %Cpu 의 ni 항목 97% 지속 (us 는 낮음)
↓
[확인] ps -eo pid,ni,user,%cpu,lstart,args --sort=-%cpu | awk '$2 > 0' | head
↓
[판단] nice 19 로 실행 중인 알 수 없는 프로세스가 CPU 대부분 사용
→ 백업 등 정상 배치 작업인지, 채굴 등 악성인지 확인
↓
[Evidence] /proc/PID/exe, cmdline(풀 주소·지갑 인자), 네트워크 연결
↓
[Response] 정상 작업이면 스케줄 조정 / 악성이면 수집 후 종료
| 확인 명령 | 목적 |
|---|---|
ps -eo ni,comm \| sort -n \| uniq -c | nice 값 분포 |
ps -eo pid,ni,user,args \| awk '$2 < 0' | 음수 nice 프로세스 (root가 설정) |
systemctl show SERVICE -p Nice,CPUWeight | 서비스 설정 확인 |
| 실수 | 결과 | 예방 |
|---|---|---|
| nice 19면 CPU를 거의 안 쓴다고 생각 | 코어가 남으면 100%도 쓴다 | nice는 경쟁 시 비율 이다. 절대 제한은 cgroup CPUQuota= |
| 일반 계정으로 renice 되돌리기 시도 | Permission denied | root 또는 처음부터 적절한 값으로 실행 |
pgrep -f로 찾은 PID에 바로 renice/kill | 래퍼·다른 프로세스까지 영향 | pgrep -a로 확인 후 적용 |
| ps PRI와 top PR을 같은 값으로 비교 | 해석 혼란 | NI 열 기준 |
| I/O가 많은 작업에 nice만 적용 | 디스크 경합은 그대로 | ionice -c3 병행 |
[ ] nice -n 10 으로 실행하고 NI, STAT N 을 확인했다
[ ] 일반 사용자가 음수 nice 와 값 되돌리기에 실패하는 것을 확인했다
[ ] taskset 으로 같은 코어에서 nice 0 과 19 를 경쟁시켰다
[ ] 측정 CPU 비율을 가중치 이론값과 비교했다
[ ] pgrep -f 가 래퍼 프로세스까지 매칭하는 문제를 확인했다
[ ] systemd 서비스의 Nice= 설정을 확인했다
CPUQuota=)을 쓴다.ni CPU 사용률과 음수 nice 프로세스를 이상 징후로 확인한다.다음 글 「10. 포그라운드·백그라운드와 Job Control」 에서는 &, jobs, bg, fg, Ctrl+Z의 동작을 프로세스 그룹과 함께 이해하고, 로그아웃 후에도 살아남는 작업(nohup, setsid, disown)의 차이를 실제 로그아웃으로 확인한다.