

기계 번역으로 제공되는 번역입니다. 제공된 번역과 원본 영어의 내용이 상충하는 경우에는 영어 버전이 우선합니다.

# systemd를 사용하여 AL2023에서 프로세스 리소스 사용 제한
<a name="resource-limiting-systemd"></a>

 Amazon Linux 2023(AL2023)에서는 `systemd`를 사용하여 프로세스 또는 프로세스 그룹에서 사용할 수 있는 리소스를 제어하는 것이 좋습니다. `systemd` 사용은 `cgroups`를 수동으로 조작하거나, 이전에는 타사 [EPEL](epel.md) 리포지토리의 Amazon Linux에서만 사용할 수 있었던 [`cpulimit`](epel.md#cpulimit) 같은 유틸리티의 사용을 대체할 수 있는 강력하고 간편한 방법입니다.

 자세한 내용은 [systemd.resource-control](https://www.freedesktop.org/software/systemd/man/latest/systemd.resource-control.html)에 대한 업스트림 `systemd` 설명서 또는 AL2023 인스턴스의 `systemd.resource-control`에 대한 man 페이지를 참조하세요.

 아래 예제에서는 `stress-ng` CPU 스트레스 테스트(`stress-ng` 패키지)를 사용하여 CPU 사용량이 많은 애플리케이션을 시뮬레이션하고, `memcached`를 사용하여 메모리 사용량이 많은 애플리케이션을 시뮬레이션합니다.

 아래 예제에서는 일회성 명령에 CPU 제한을 적용하고 서비스에 메모리 제한을 적용하는 방법을 다룹니다. `systemd`에서 제공하는 대부분의 리소스 제약 조건은 `systemd`가 프로세스를 실행할 모든 위치에서 사용할 수 있으며 여러 개를 동시에 사용할 수 있습니다. 아래 예제는 설명을 위한 단일 제약으로 제한됩니다.

## 일회성 명령 실행을 위한 `systemd-run`을 사용한 리소스 제어
<a name="resource-limiting-systemd-interactive"></a>

 일반적으로 시스템 서비스와 연결되지만 `systemd`는 루트 사용자가 아닌 사용자가 서비스를 실행하거나 타이머를 예약하거나 일회성 프로세스를 실행하는 데도 사용할 수 있습니다. 다음 예제에서는 `stress-ng`를 예제 애플리케이션으로 사용합니다. 첫 번째 예제에서는 `ec2-user` 기본 계정에서 `systemd-run`을 사용하여 실행하고, 두 번째 예제에서는 CPU 사용량에 제한을 둡니다.

**Example 명령줄에서 `systemd-run`을 사용하여 리소스 사용량을 제한하지 않고 프로세스를 실행합니다.**  

1.  `stress-ng` 패키지를 예제에 사용할 예정이므로 해당 패키지가 설치되어 있는지 확인합니다.

   ```
   [ec2-user ~]$ sudo dnf install -y stress-ng
   ```

1.  사용 가능한 CPU 양을 제한하지 않고 `systemd-run`으로 10초 CPU 스트레스 테스트를 실행합니다.

   ```
   [ec2-user ~]$ systemd-run --user --tty --wait --property=CPUAccounting=1 stress-ng --cpu 1 --timeout 10
   Running as unit: run-u6.service
   Press ^] three times within 1s to disconnect TTY.
   stress-ng: info:  [339368] setting to a 10 second run per stressor
   stress-ng: info:  [339368] dispatching hogs: 1 cpu
   stress-ng: info:  [339368] successful run completed in 10.00s
   Finished with result: success
   Main processes terminated with: code=exited/status=0
   Service runtime: 10.068s
   CPU time consumed: 9.060s
   ```

    `--user` 옵션은 `systemd-run`에 로그인한 사용자로 명령을 실행하도록 지시하고, `--tty` 옵션은 TTY가 연결되어 있음을 의미하며, `--wait`는 서비스가 완료될 때까지 기다리는 것을 의미하고, `--property=CPUAccounting=1` 옵션은 `systemd-run`에 프로세스를 실행하는 데 사용되는 CPU 시간을 기록하도록 지시합니다. `--property` 명령줄 옵션을 사용하여 `systemd.unit` 구성 파일에서 구성할 수 있는 `systemd-run` 설정을 전달할 수 있습니다.

 CPU에 로드를 배치하라는 지시를 받으면 `stress-ng` 프로그램은 실행을 요청하는 기간 동안 사용 가능한 모든 CPU 시간을 사용하여 테스트를 수행합니다. 실제 애플리케이션의 경우 프로세스의 총 런타임에 제한을 두는 것이 좋습니다. 아래 예제에서는 `systemd-run`을 사용하여 최대 기간 제한보다 더 오래 `stress-ng`를 실행하도록 요청합니다.

**Example 명령줄에서 `systemd-run`을 사용하여 프로세스를 실행하고 CPU 사용량을 1초로 제한합니다.**  

1. 이 예제를 실행하려면 `stress-ng`가 설치되어 있는지 확인합니다.

1.  `LimitCPU` 속성은 이 프로세스가 사용할 수 있는 CPU의 최대 시간을 제한하는 `ulimit -t`와 동일합니다. 이 경우 10초 스트레스 실행을 요청하고 CPU 사용량을 1초로 제한하므로 명령은 `SIGXCPU` 신호를 수신하고 실패합니다.

   ```
   [ec2-user ~]$ systemd-run --user --tty --wait --property=CPUAccounting=1 --property=LimitCPU=1 stress-ng --cpu 1 --timeout 10
   Running as unit: run-u12.service
   Press ^] three times within 1s to disconnect TTY.
   stress-ng: info:  [340349] setting to a 10 second run per stressor
   stress-ng: info:  [340349] dispatching hogs: 1 cpu
   stress-ng: fail:  [340349] cpu instance 0 corrupted bogo-ops counter, 1370 vs 0
   stress-ng: fail:  [340349] cpu instance 0 hash error in bogo-ops counter and run flag, 3250129726 vs 0
   stress-ng: fail:  [340349] metrics-check: stressor metrics corrupted, data is compromised
   stress-ng: info:  [340349] unsuccessful run completed in 1.14s
   Finished with result: exit-code
   Main processes terminated with: code=exited/status=2
   Service runtime: 1.201s
   CPU time consumed: 1.008s
   ```

 더 일반적으로는 특정 프로세스에서 사용할 수 있는 CPU 시간 비율을 제한할 수 있습니다. 아래 예제에서는 `stress-ng`에서 사용할 수 있는 CPU 시간의 비율을 제한합니다. 실제 서비스의 경우 사용자 요청을 처리하는 프로세스에 리소스를 자유롭게 두기 위해 백그라운드 프로세스에서 사용할 수 있는 최대 CPU 시간 비율을 제한하는 것이 좋습니다.

**Example 하나의 CPU에서 프로세스를 CPU 시간의 10%로 제한하는 데 `systemd-run` 사용**  

1. 이 예제를 실행하려면 `stress-ng`가 설치되어 있는지 확인합니다.

1.  `CPUQuota` 속성을 사용하여 `systemd-run`에 실행할 명령의 CPU 사용량을 제한하도록 지시합니다. 프로세스가 실행할 수 있는 시간만 제한하는 것이 아니라 사용할 수 있는 CPU 양을 제한합니다.

   ```
   [ec2-user ~]$ systemd-run --user --tty --wait --property=CPUAccounting=1 --property=CPUQuota=10% stress-ng --cpu 1 --timeout 10
   Running as unit: run-u13.service
   Press ^] three times within 1s to disconnect TTY.
   stress-ng: info:  [340664] setting to a 10 second run per stressor
   stress-ng: info:  [340664] dispatching hogs: 1 cpu
   stress-ng: info:  [340664] successful run completed in 10.08s
   Finished with result: success
   Main processes terminated with: code=exited/status=0
   Service runtime: 10.140s
   CPU time consumed: 1.014s
   ```

    CPU 회계를 통해 서비스가 10초 동안 실행되었지만 실제 CPU 시간 중 1초만 소비되었음을 알 수 있습니다.

 CPU, 메모리, 네트워킹 및 IO에 대한 리소스 사용을 제한하도록 `systemd`를 구성하는 방법에는 여러 가지가 있습니다. 포괄적인 설명서는 [systemd.resource-control](https://www.freedesktop.org/software/systemd/man/latest/systemd.resource-control.html)에 대한 업스트림 `systemd` 설명서 또는 AL2023 인스턴스의 `systemd.resource-control`에 대한 man 페이지를 참조하세요.

 백그라운드에서 `systemd`는 `cgroups` 같은 Linux 커널의 기능을 사용하여 이러한 제한을 구현하는 동시에 수동으로 구성할 필요가 없도록 합니다. [`cgroup-v2`용 Linux 커널 설명서](https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html)에는 `cgroups` 작동 방식에 대한 광범위한 세부 정보가 포함되어 있습니다.

## `systemd` 서비스의 리소스 제어
<a name="resource-limiting-systemd-service"></a>

 시스템 리소스 사용을 제어하기 위해 `systemd` 서비스의 `[Service]` 섹션에 추가할 수 있는 몇 가지 파라미터가 있습니다. 여기에는 하드 제한과 소프트 제한이 모두 포함됩니다. 각 옵션의 정확한 동작은 [systemd.resource-control](https://www.freedesktop.org/software/systemd/man/latest/systemd.resource-control.html)에 대한 업스트림 `systemd` 설명서 또는 AL2023 인스턴스의 `systemd.resource-control`에 대한 man 페이지를 참조하세요.

 일반적으로 사용되는 제한은 메모리 사용량에 대한 스로틀링 제한을 지정하는 `MemoryHigh`, 하드 상한(이에 도달하면 OOM 킬러가 간접 호출됨)을 설정하는 `MemoryMax` 및 `CPUQuota`(이전 섹션에서 설명)입니다. 고정된 숫자 대신 가중치와 우선순위를 구성할 수도 있습니다.

**Example `systemd`를 사용하여 서비스에 대한 메모리 사용량 제한 설정**  
 이 예제에서는 간단한 키-값 캐시인 `memcached`에 대한 하드 메모리 사용량 제한을 설정하고 전체 시스템이 아닌 해당 서비스에 대해 OOM 킬러가 간접 호출되는 방법을 보여줍니다.  

1.  먼저 이 예제에 필요한 패키지를 설치해야 합니다.

   ```
   [ec2-user ~]$ sudo dnf install -y memcached libmemcached-awesome-tools
   ```

1.  `memcached.service`를 활성화한 다음 `memcached`가 실행되도록 서비스를 시작합니다.

   ```
   [ec2-user ~]$ sudo systemctl enable memcached.service
   Created symlink /etc/systemd/system/multi-user.target.wants/memcached.service → /usr/lib/systemd/system/memcached.service.
   [ec2-user ~]$ sudo systemctl start memcached.service
   ```

1.  `memcached.service`가 실행 중인지 확인합니다.

   ```
   [ec2-user ~]$ sudo systemctl status memcached.service
   ● memcached.service - memcached daemon
        Loaded: loaded (/usr/lib/systemd/system/memcached.service; enabled; preset: disabled)
        Active: active (running) since Fri 2025-01-31 22:36:42 UTC; 1s ago
      Main PID: 356294 (memcached)
         Tasks: 10 (limit: 18907)
        Memory: 1.8M
           CPU: 20ms
        CGroup: /system.slice/memcached.service
        └─356294 /usr/bin/memcached -p 11211 -u memcached -m 64 -c 1024 -l 127.0.0.1,::1
   
   Jan 31 22:35:36 ip-1-2-3-4.us-west-2.compute.internal systemd[1]: Started memcached.service - memcached daemon.
   ```

1.  `memcached`가 설치되고 실행 중이므로 일부 무작위 데이터를 캐시에 삽입하여 작동하는지 확인할 수 있습니다.

    `/etc/sysconfig/memcached`에서 `CACHESIZE` 변수는 기본적으로 64로 설정되며, 이는 64메가바이트를 의미합니다. 최대 캐시 크기보다 더 많은 데이터를 캐시에 삽입하면 캐시를 채우고 일부 항목은 `memcached-tool`을 사용하여 제거되며 `memcached.service`가 약 64MB의 메모리를 사용하고 있음을 알 수 있습니다.

   ```
   [ec2-user ~]$ for i in $(seq 1 150); do dd if=/dev/random of=$i bs=512k count=1; memcp -s localhost $i; done
   [ec2-user ~]$ memcached-tool localhost display
     #  Item_Size  Max_age   Pages   Count   Full?  Evicted Evict_Time OOM
     2     120B         0s       1       0      no        0        0    0
    39   512.0K         4s      63     126     yes       24        2    0
   [ec2-user ~]$ sudo systemctl status memcached.service
   ● memcached.service - memcached daemon
        Loaded: loaded (/usr/lib/systemd/system/memcached.service; enabled; preset: disabled)
        Active: active (running) since Fri 2025-01-31 22:36:42 UTC; 7min ago
      Main PID: 356294 (memcached)
         Tasks: 10 (limit: 18907)
        Memory: 66.7M
           CPU: 203ms
        CGroup: /system.slice/memcached.service
                └─356294 /usr/bin/memcached -p 11211 -u memcached -m 64 -c 1024 -l 127.0.0.1,::1
   
   Jan 31 22:36:42 ip-1-2-3-4.us-west-2.compute.internal systemd[1]: Started memcached.service - memcached daemon.
   ```

1.  `MemoryMax` 속성을 사용하여 `memcached.service`에 대한 하드 제한을 설정하며, 이 제한에 도달하면 OOM 킬러가 간접 호출됩니다. 재정의 파일에 추가하여 서비스에 대한 추가 옵션을 설정할 수 있습니다. 이 작업은 `/etc/systemd/system/memcached.service.d/override.conf` 파일을 직접 편집하거나 `systemctl`의 `edit` 명령을 사용하여 대화식으로 수행할 수 있습니다.

   ```
   [ec2-user ~]$ sudo systemctl edit memcached.service
   ```

   아래를 재정의에 추가하여 서비스에 대한 메모리 하드 제한을 32MB로 설정합니다.

   ```
   [Service]
   MemoryMax=32M
   ```

1. `systemd`에 구성을 다시 로드하도록 지시

   ```
   [ec2-user ~]$ sudo systemctl daemon-reload
   ```

1. 이제 `memcached.service`가 32MB의 메모리 제한으로 실행 중인지 확인합니다.

   ```
   [ec2-user ~]$ sudo systemctl status memcached.service
   ● memcached.service - memcached daemon
        Loaded: loaded (/usr/lib/systemd/system/memcached.service; enabled; preset: disabled)
       Drop-In: /etc/systemd/system/memcached.service.d
                └─override.conf
        Active: active (running) since Fri 2025-01-31 23:09:13 UTC; 49s ago
      Main PID: 358423 (memcached)
         Tasks: 10 (limit: 18907)
        Memory: 1.8M (max: 32.0M available: 30.1M)
           CPU: 25ms
        CGroup: /system.slice/memcached.service
                └─358423 /usr/bin/memcached -p 11211 -u memcached -m 64 -c 1024 -l 127.0.0.1,::1
   
   Jan 31 23:09:13 ip-1-2-3-4.us-west-2.compute.internal systemd[1]: Started memcached.service - memcached daemon.
   ```

1.  서비스는 32MB 미만의 메모리를 사용하는 동안 정상적으로 작동하며, 32MB 미만의 임의 데이터를 캐시에 로드한 다음 서비스 상태를 확인하여 확인할 수 있습니다.

   ```
   [ec2-user ~]$ for i in $(seq 1 30); do dd if=/dev/random of=$i bs=512k count=1; memcp -s localhost $i; done
   ```

   ```
   [ec2-user ~]$ sudo systemctl status memcached.service
   ● memcached.service - memcached daemon
        Loaded: loaded (/usr/lib/systemd/system/memcached.service; enabled; preset: disabled)
       Drop-In: /etc/systemd/system/memcached.service.d
                └─override.conf
        Active: active (running) since Fri 2025-01-31 23:14:48 UTC; 3s ago
      Main PID: 359492 (memcached)
         Tasks: 10 (limit: 18907)
        Memory: 18.2M (max: 32.0M available: 13.7M)
           CPU: 42ms
        CGroup: /system.slice/memcached.service
                └─359492 /usr/bin/memcached -p 11211 -u memcached -m 64 -c 1024 -l 127.0.0.1,::1
   
   Jan 31 23:14:48 ip-1-2-3-4.us-west-2.compute.internal systemd[1]: Started memcached.service - memcached daemon.
   ```

1.  이제 기본 `memcached` 구성인 64MB의 전체 캐시를 사용하려고 시도하여 `memcached`가 32MB 이상의 메모리를 사용하도록 할 수 있습니다.

   ```
   [ec2-user ~]$ for i in $(seq 1 150); do dd if=/dev/random of=$i bs=512k count=1; memcp -s localhost $i; done
   ```

    위 명령 중 어느 시점에 `memcached` 서버에 연결 오류가 있는 것을 확인할 수 있습니다. 이는 OOM Killer가 프로세스에 적용한 제한으로 인해 프로세스를 종료했기 때문입니다. 나머지 시스템은 정상적으로 작동하며 OOM Killer는 다른 프로세스를 고려하지 않습니다. 제한한 대상이 `memcached.service`뿐이기 때문입니다.

   ```
   [ec2-user ~]$ sudo systemctl status memcached.service
   ● memcached.service - memcached daemon
        Loaded: loaded (/usr/lib/systemd/system/memcached.service; enabled; preset: disabled)
       Drop-In: /etc/systemd/system/memcached.service.d
                └─override.conf
        Active: failed (Result: oom-kill) since Fri 2025-01-31 23:20:28 UTC; 2s ago
      Duration: 2.901s
       Process: 360130 ExecStart=/usr/bin/memcached -p ${PORT} -u ${USER} -m ${CACHESIZE} -c ${MAXCONN} $OPTIONS (code=killed, signal=KILL)
      Main PID: 360130 (code=killed, signal=KILL)
           CPU: 94ms
   
   Jan 31 23:20:25 ip-1-2-3-4.us-west-2.compute.internal systemd[1]: Started memcached.service - memcached daemon.
   Jan 31 23:20:28 ip-1-2-3-4.us-west-2.compute.internal systemd[1]: memcached.service: A process of this unit has been killed by the OOM killer.
   Jan 31 23:20:28 ip-1-2-3-4.us-west-2.compute.internal systemd[1]: memcached.service: Main process exited, code=killed, status=9/KILL
   Jan 31 23:20:28 ip-1-2-3-4.us-west-2.compute.internal systemd[1]: memcached.service: Failed with result 'oom-kill'.
   ```