
리눅스에서 서비스별 프로세스 수를 제한할 때 pids.max를 단순한 PID 번호 제한으로 이해하면 판단이 흐려집니다. cgroup v2의 pids controller는 특정 cgroup 안에서 새 task가 더 만들어지는 것을 제한합니다. 여기서 task는 커널이 세는 TID 단위라서 일반적인 프로세스뿐 아니라 스레드도 개별적으로 포함됩니다.
결론부터 말하면, pids.max는 fork 폭주나 과도한 스레드 생성이 한 서비스 밖으로 번지는 것을 막는 하드 경계입니다. systemd를 쓰는 환경에서는 대개 TasksMax=와 EffectiveTasksMax=를 먼저 보고, 필요할 때 해당 cgroup의 pids.current, pids.peak, pids.events를 같이 확인하면 됩니다.

pids.max는 무엇을 제한하나
Linux kernel의 cgroup v2 문서에서 PID controller는 지정한 제한에 도달한 뒤 새 task가 fork() 또는 clone()으로 만들어지는 것을 막는 controller입니다. 문서는 task 수가 메모리 같은 다른 controller보다 먼저 고갈될 수 있기 때문에 별도 controller가 필요하다고 설명합니다.
pids.max는 non-root cgroup에 존재하는 read-write 단일 값 파일이며 기본값은 max입니다. 값이 숫자라면 해당 cgroup과 하위 cgroup 전체에서 허용할 task 수의 하드 제한이 됩니다. 제한에 닿으면 새 task 생성은 실패할 수 있고, 일반적으로 애플리케이션 쪽에서는 Resource temporarily unavailable 같은 형태로 드러날 수 있습니다.
중요한 점은 이름의 pids가 사용자 공간에서 보는 프로세스 ID 하나만 뜻하지 않는다는 점입니다. kernel 문서는 이 controller에서 쓰는 PID가 커널의 task ID, 즉 TID를 가리킨다고 설명합니다. 스레드를 많이 만드는 프로그램이라면 프로세스 수가 적어 보여도 pids.current가 빠르게 올라갈 수 있습니다.
어떤 파일을 같이 봐야 하나
pids.max만 보면 “제한값”만 알 수 있습니다. 실제 운영 판단에는 현재 사용량, 최고점, 제한 도달 횟수가 같이 필요합니다.
| 파일 | 의미 | 확인 기준 |
|---|---|---|
pids.max |
cgroup의 task 수 하드 제한 | max인지 숫자 제한인지 확인 |
pids.current |
현재 cgroup과 하위 cgroup의 task 수 | 정상 상태와 피크 상태의 차이를 관찰 |
pids.peak |
지금까지 관측된 최대 task 수 | 제한값을 정할 때 여유 폭을 가늠 |
pids.events |
제한 도달 이벤트 카운터 | max 값 증가 여부로 차단 발생 확인 |
pids.events.local |
현재 cgroup 로컬 이벤트 카운터 | 하위 cgroup 포함 여부를 분리해서 볼 때 사용 |

kernel 문서에는 조직적인 이동 작업은 cgroup 정책으로 막히지 않기 때문에 pids.current가 pids.max보다 커질 수 있다고 되어 있습니다. 예를 들어 이미 많은 task가 있는 cgroup에 더 낮은 제한을 쓰거나, 다른 task를 붙이는 방식으로 그런 상태가 될 수 있습니다. 하지만 새로 fork()나 clone()을 해서 정책을 위반하는 것은 허용되지 않고, 이 경우 -EAGAIN으로 실패합니다.
systemd에서는 TasksMax를 본다
systemd unit을 운영한다면 pids.max를 직접 쓰기보다 systemd.resource-control의 TasksMax=를 먼저 보는 편이 일반적입니다. systemd 문서 기준 TasksMax=는 unified hierarchy에서 pids controller를 제어하며, unit 안에서 만들 수 있는 최대 task 수를 지정합니다. 이 설정은 cgroup의 pids.max 속성을 제어합니다.
TasksAccounting=은 해당 unit과 하위 unit의 task 수를 accounting하도록 켜는 설정입니다. systemd 문서는 이 수에 커널 스레드와 사용자 공간 프로세스가 모두 포함되고, 각 thread가 개별적으로 계산된다고 설명합니다. TasksMax=를 설정하면 EffectiveTasksMax=로 실제 적용값을 확인하는 것이 좋습니다.
[Service]
TasksAccounting=yes
TasksMax=512
위 숫자는 예시입니다. 실제 제한값은 서비스가 정상 상태에서 만드는 worker, thread pool, helper process, short-lived child process, reload 과정의 순간 증가량을 보고 정해야 합니다. 너무 낮게 잡으면 장애를 빠르게 드러낼 수 있지만 정상적인 피크도 막을 수 있습니다. 너무 높게 잡으면 폭주 방어선으로서 의미가 약해집니다.

LimitNPROC와는 어떻게 다른가
LimitNPROC=나 shell의 ulimit -u도 process 수 제한과 관련이 있지만, 서비스 단위 운영 기준으로는 TasksMax=가 더 직접적입니다. systemd 실행 환경에서 LimitNPROC=는 전통적인 resource limit 계열이고, TasksMax=는 cgroup pids controller를 통해 unit 단위 task 수를 제어합니다.
여러 서비스가 같은 사용자 계정으로 실행되는 환경에서는 사용자 단위 제한보다 unit 단위 제한이 원인 파악에 유리할 때가 많습니다. 특정 서비스가 task를 과도하게 만들었는지, slice 아래 다른 unit의 제한이 더 엄격한지, 부모 쪽 effective 값이 어디서 줄었는지를 systemd 속성으로 따라갈 수 있기 때문입니다.
운영 기준은 어떻게 잡나
첫째, 정상 상태의 task 수를 먼저 측정합니다. HTTP 서버라면 worker process와 thread pool, 애플리케이션 런타임의 내부 스레드, 백그라운드 작업 큐까지 포함해야 합니다. JVM, Go 런타임, 데이터베이스 클라이언트, 브라우저 자동화처럼 내부 스레드가 많은 프로그램은 겉으로 보이는 프로세스 수보다 task 수가 크게 나올 수 있습니다.
둘째, 제한값은 정상 피크보다 약간 위에 두되 무제한에 가깝게 두지 않습니다. pids.max는 CPU나 메모리 성능 튜닝 값이 아니라 새 task 생성의 안전 경계입니다. 제한에 자주 닿는다면 무조건 값을 올리기보다 thread pool 크기, worker 개수, 재시작 루프, 요청별 child process 생성 여부를 먼저 봐야 합니다.
셋째, 이벤트 카운터를 함께 봅니다. pids.events의 max가 증가했다면 실제로 제한에 닿은 적이 있다는 뜻입니다. 단순히 pids.current가 높다는 사실과, 제한 때문에 새 task 생성이 실패했다는 사실은 구분해야 합니다.
확인할 때 쓸 명령은 무엇인가
systemd unit이면 먼저 unit 속성부터 확인합니다. 배포판과 systemd 설정에 따라 cgroup 경로가 달라질 수 있기 때문입니다.
systemctl show my.service -p TasksAccounting -p TasksCurrent -p TasksMax -p EffectiveTasksMax
systemctl status my.service
cgroup 파일을 직접 볼 때는 해당 unit이 속한 cgroup 디렉터리에서 다음 파일을 함께 확인합니다.
cat pids.max
cat pids.current
cat pids.peak
cat pids.events
cat pids.events.local
로그에서는 task 생성 실패가 애플리케이션 오류로만 보일 수 있습니다. pids.events의 max 증가와 같은 시점의 애플리케이션 로그를 맞춰 보면, 실제로 제한에 닿은 문제인지 아니면 다른 resource limit이나 권한 문제인지 구분하기 쉽습니다.
자주 묻는 질문
pids.max는 PID 번호 최댓값을 바꾸는 설정인가?
아닙니다. 시스템 전체 PID 번호 범위를 정하는 설정과 다릅니다. pids.max는 특정 cgroup 안에서 새 task가 만들어질 수 있는 개수를 제한합니다.
스레드도 TasksMax에 포함되나?
systemd 문서 기준 TasksAccounting=은 각 thread를 개별적으로 계산합니다. kernel의 pids controller도 TID 단위로 설명됩니다. 그래서 스레드가 많은 서비스는 TasksCurrent가 예상보다 크게 보일 수 있습니다.
pids.current가 pids.max보다 크면 설정이 깨진 것인가?
항상 그렇지는 않습니다. kernel 문서는 조직적인 이동 작업이나 제한값 변경 때문에 pids.current가 pids.max보다 커질 수 있다고 설명합니다. 다만 그 상태에서 새 fork()나 clone()으로 제한을 더 위반하는 것은 허용되지 않습니다.
정리하면 pids.max는 서비스가 만들 수 있는 task 수의 하드 경계입니다. systemd 환경에서는 TasksMax=와 EffectiveTasksMax=로 먼저 보고, 실제 cgroup 파일에서는 pids.current, pids.peak, pids.events를 같이 확인하는 흐름이 실무적으로 가장 읽기 쉽습니다.
참고 문서
'프로그래밍 > 리눅스 커널' 카테고리의 다른 글
| 리눅스 cgroup v2 io.max 기준 (0) | 2026.09.30 |
|---|---|
| 리눅스 cgroup v2 memory.high 기준 (0) | 2026.09.27 |
| 리눅스 Landlock 기준 (0) | 2026.09.22 |
| 리눅스 Device Tree clocks 기준 (0) | 2026.09.20 |
| 리눅스 pidfd 기준 (0) | 2026.09.19 |





