Red Hat Training

A Red Hat training course is available for Red Hat Enterprise Linux

6.3. 구성 제안

Red Hat Enterprise Linux는 관리자가 시스템 구성을 지원하는 다양한 툴을 제공합니다. 이 섹션에서는 사용 가능한 툴을 간략하게 설명하고 Red Hat Enterprise Linux 7의 프로세서 관련 성능 문제를 해결하는 데 사용할 수 있는 방법에 대한 예를 제공합니다.

6.3.1. 커널 틱 시간 구성

기본적으로 Red Hat Enterprise Linux 7은 전원 사용량을 줄이고 최신 프로세서가 깊은 수면 상태를 활용할 수 있도록 유휴 CPU를 중단하지 않는 틱리스 커널을 사용합니다.
Red Hat Enterprise Linux 7에서는 동적 틱리스 옵션(기본적으로 비활성화)을 제공합니다. 이는 고성능 컴퓨팅 또는 실시간 컴퓨팅과 같은 대기 시간에 민감한 워크로드에 유용합니다.
특정 코어에서 동적 틱리스 동작을 활성화하려면 nohz_full 매개변수를 사용하여 커널 명령줄에 해당 코어를 지정합니다. 16코어 시스템에서 nohz_full=1-15 를 지정하면 코어 1에서 15까지 동적 틱리스 동작을 활성화할 수 있습니다. 모든 시간키를 지정되지 않은 코어(코어 0)로 이동합니다. 이 동작은 부팅 시 일시적으로 또는 /etc/default/grub 파일의 GRUB_CMDLINE_LINUX 옵션을 통해 영구적으로 활성화할 수 있습니다. 영구 동작의 경우 grub2-mkconfig -o /boot/grub2/grub.cfg 명령을 실행하여 구성을 저장합니다.
동적 틱리스 동작을 활성화하려면 몇 가지 수동 관리가 필요합니다.
  • 시스템이 부팅될 때 rcu 스레드를 수동으로 대기 시간에 민감한 코어(이 경우 core 0)로 이동해야 합니다.
    # for i in `pgrep rcu[^c]` ; do taskset -pc 0 $i ; done
  • 커널 명령줄의 isolcpus 매개변수를 사용하여 사용자 공간 작업에서 특정 코어를 분리합니다.
  • 선택적으로 커널의 write-back bdi-flush 스레드의 CPU 선호도를 하우스키핑 코어로 설정합니다.
    echo 1 > /sys/bus/workqueue/devices/writeback/cpumask
다음 명령을 실행하여 동적 틱리스 구성이 제대로 작동하는지 확인합니다. 여기서 stress 는 CPU에서 1초 동안 실행되는 프로그램입니다.
# perf stat -C 1 -e irq_vectors:local_timer_entry taskset -c 1 stress -t 1 -c 1
과부하 를 대체할 수 있는 한 가지 방법은 while :; do d=1; done 과 같은 것을 실행하는 스크립트입니다.
기본 커널 타이머 구성에는 사용 중인 CPU에 1000 틱이 표시됩니다.
# perf stat -C 1 -e irq_vectors:local_timer_entry taskset -c 1 stress -t 1 -c 1
1000 irq_vectors:local_timer_entry
동적 틱리스 커널이 구성되면 대신 1 눈금이 표시됩니다.
# perf stat -C 1 -e irq_vectors:local_timer_entry taskset -c 1 stress -t 1 -c 1
1 irq_vectors:local_timer_entry

6.3.2. 하드웨어 성능 정책 설정 (x86_energy_perf_policy)

x86_energy_perf_policy 툴을 사용하면 관리자가 성능 및 에너지 효율성의 상대적 중요성을 정의할 수 있습니다. 이 정보는 성능과 에너지 효율성 사이에서 거래되는 옵션을 선택할 때 이 기능을 지원하는 프로세서에 영향을 미칠 수 있습니다.
기본적으로 성능 모드의 모든 프로세서에서 작동합니다. CPUID.06H.ECX.bit3 이므로 루트 권한으로 실행해야 하는 프로세서 지원이 필요합니다.
x86_energy_perf_policykernel-tools 패키지에서 제공합니다. x86_energy_perf_policy 를 사용하는 방법에 대한 자세한 내용은 A.9절. “x86_energy_perf_policy” 또는 도움말 페이지를 참조하십시오.
$ man x86_energy_perf_policy

6.3.3. 작업 세트를 사용하여 프로세스 유사성 설정

작업 세트 툴은 util-linux 패키지에서 제공합니다. 관리자는 Taskset 을 사용하여 실행 중인 프로세스의 프로세서 선호도를 검색 및 설정하거나 지정된 프로세서 선호도로 프로세스를 시작할 수 있습니다.
중요
작업 세트는 로컬 메모리 할당을 보장하지 않습니다. 로컬 메모리 할당의 추가 성능 이점이 필요한 경우 작업 세트 대신 numactl 을 사용하는 것이 좋습니다.
작업 세트에 대한 자세한 내용은 A.15절. “작업 세트” 또는 도움말 페이지를 참조하십시오.
$ man taskset

6.3.4. numactl을 사용하여 NUMA 유사성 관리

관리자는 numactl 을 사용하여 지정된 스케줄링 또는 메모리 배치 정책으로 프로세스를 실행할 수 있습니다. numactl 은 공유 메모리 세그먼트 또는 파일에 대한 영구 정책을 설정하고 프로세스의 프로세서 선호도 및 메모리 선호도를 설정할 수도 있습니다.
NUMA 토폴로지가 있는 시스템에서는 프로세서와 메모리 은행 사이의 거리가 증가함에 따라 프로세서의 메모리 액세스가 느려집니다. 따라서 가능한 가장 가까운 메모리 뱅크에서 메모리를 할당하도록 성능에 민감한 애플리케이션을 구성하는 것이 중요합니다. 동일한 NUMA 노드에 있는 메모리 및 CPU를 사용하는 것이 가장 좋습니다.
성능에 민감한 다중 스레드 애플리케이션은 특정 프로세서가 아닌 특정 NUMA 노드에서 실행되도록 구성할 수 있습니다. 이것이 적합한지 여부는 시스템 및 애플리케이션의 요구 사항에 따라 달라집니다. 여러 애플리케이션 스레드가 동일한 캐시된 데이터에 액세스하는 경우 동일한 프로세서에서 실행되도록 해당 스레드를 구성하는 것이 적합할 수 있습니다. 그러나 동일한 프로세서에서 서로 다른 데이터에 액세스하고 캐시하는 여러 스레드가 이전 스레드에서 액세스하는 캐시된 데이터를 제거할 수 있습니다. 즉, 각 스레드가 캐시를 '허용"하고 메모리에서 데이터를 가져와서 캐시에서 교체하는 실행 시간을 삭제합니다. A.6절. “perf” 에 설명된 대로 perf 툴을 사용하여 과도한 수의 캐시 누락을 확인할 수 있습니다.
numactl 은 프로세서 및 메모리 선호도를 관리하는 데 도움이 되는 다양한 옵션을 제공합니다. 자세한 내용은 A.11절. “numastat” 또는 도움말 페이지를 참조하십시오.
$ man numactl
참고
numactl 패키지에는 libnuma 라이브러리가 포함되어 있습니다. 이 라이브러리는 커널에서 지원하는 NUMA 정책에 간단한 프로그래밍 인터페이스를 제공하며 numactl 애플리케이션보다 세분화된 튜닝에 사용할 수 있습니다. 자세한 내용은 도움말 페이지를 참조하십시오.
$ man numa

6.3.5. numad를 사용한 자동 NUMA 선호도 관리

numad 는 자동 NUMA 선호도 관리 데몬입니다. NUMA 리소스 할당 및 관리를 동적으로 개선하기 위해 시스템 내에서 NUMA 토폴로지 및 리소스 사용량을 모니터링합니다.
또한 numad 는 다양한 작업 관리 시스템에서 쿼리하여 프로세스에 대한 CPU 및 메모리 리소스의 초기 바인딩에 대한 지원을 제공할 수 있는 사전 배치 조언 서비스도 제공합니다. 이 사전 배치 조언은 numad가 실행 가능 여부 또는 서비스로 실행되는지 여부에 관계없이 사용할 수 있습니다.
numad 를 사용하는 방법에 대한 자세한 내용은 A.13절. “numad” 또는 도움말 페이지를 참조하십시오.
$ man numad

6.3.6. 스케줄링 정책 튜닝

Linux 스케줄러는 스레드가 실행되는 위치와 기간을 결정하는 여러 스케줄링 정책을 구현합니다. 스케줄링 정책에는 일반적인 정책과 실시간 정책의 두 가지 주요 범주가 있습니다. 일반 스레드는 일반 우선 순위의 작업에 사용됩니다. 실시간 정책은 중단 없이 완료해야 하는 시간에 민감한 작업에 사용됩니다.
실시간 스레드는 시간 분할의 영향을 받지 않습니다. 즉, 차단, 종료, 수집 출력 또는 더 높은 우선 순위 스레드에 의해 미리 시도될 때까지 실행됩니다. 가장 낮은 우선 순위의 실시간 스레드는 일반 정책이 있는 스레드보다 먼저 예약됩니다.

6.3.6.1. 스케줄링 정책

6.3.6.1.1. Cryostat_FIFO를 사용한 정적 우선 순위 스케줄링
Cryostat_FIFO (정정 우선 순위 스케줄링이라고도 함)는 각 스레드에 고정된 우선 순위를 정의하는 실시간 정책입니다. 관리자는 이 정책을 통해 이벤트 응답 시간을 개선하고 대기 시간을 줄일 수 있으며 장기간 실행되지 않는 시간에 민감한 작업에 권장됩니다.
Cryostat _FIFO 를 사용 중인 경우 스케줄러는 모든 all Cryostat _FIFO 스레드 목록을 우선 순위순으로 검색하고 실행할 준비가 된 가장 높은 우선 순위 스레드를 예약합니다. priority 수준은 1에서 99까지의 모든 정수일 수 있으며 99는 가장 높은 우선 순위로 취급됩니다. Red Hat은 대기 시간 문제를 식별할 때만 적은 수에서 시작하여 우선 순위를 높이는 것이 좋습니다.
주의
실시간 스레드는 시간 분할에 종속되지 않으므로 Red Hat은 우선 순위를 99로 설정하는 것을 권장하지 않습니다. 그러면 프로세스가 마이그레이션 및 워치독 스레드와 동일한 우선 순위 수준에 배치됩니다. 스레드가 컴퓨팅 루프에 들어가면 이러한 스레드가 차단되면 실행할 수 없습니다. 단일 프로세서가 있는 시스템은 결국 이 상황에서 중단됩니다.
관리자는 실시간 애플리케이션 프로그래머가 프로세서를 단조하는 실시간 작업을 시작하는 것을 방지하기 위해 Cryostat _FIFO 대역폭을 제한할 수 있습니다.
/proc/sys/kernel/sched_rt_period_us
이 매개 변수는 프로세서 대역폭의 100 %로 간주되는 마이크로초 단위로 기간을 정의합니다. 기본값은 1000000 Cryostats 또는 1초입니다.
/proc/sys/kernel/sched_rt_runtime_us
이 매개 변수는 실시간 스레드를 실행하는 데 사용되는 마이크로초 단위로 기간을 정의합니다. 기본값은 950000 Cryostats 또는 0.95초입니다.
6.3.6.1.2. round Robin Priority Scheduling with Cryostat_RR
Cryostat_RR 은 round-robin variant of Cryo stat_FIFO 입니다. 이 정책은 여러 스레드가 동일한 우선 순위 수준에서 실행되어야 하는 경우에 유용합니다.
Cryo stat_FIFO마찬가지로 Cryostat_RR 은 각 스레드에 대한 고정된 우선 순위를 정의하는 실시간 정책입니다. 스케줄러는 모든 Cryostat _RR 스레드 목록을 우선 순위순으로 스캔하고 실행할 준비가 된 가장 높은 우선 순위 스레드를 예약합니다. 그러나 Cryo stat_FIFO 와 달리 우선 순위가 동일한 스레드는 특정 시간 슬라이스 내에서 라운드 로빈 스타일을 예약합니다.
sched_rr_timeslice_ms 커널 매개변수(/proc/sys/kernel/sched_rr_timeslice_ms)를 사용하여 이 시간 슬라이스의 값을 밀리초 단위로 설정할 수 있습니다. 가장 낮은 값은 1밀리초입니다.
6.3.6.1.3. normal Scheduling with Cryostat_OTHER
Cryostat_OTHER 는 Red Hat Enterprise Linux 7의 기본 스케줄링 정책입니다. 이 정책은 CFS(Completely Fair Scheduler)를 사용하여 이 정책과 함께 예약된 모든 스레드에 대한 공정하게 프로세서 액세스를 허용합니다. 이 정책은 시간이 지남에 따라 스레드를 더 효율적으로 예약할 수 있으므로 많은 스레드 또는 데이터 처리량이 우선 순위입니다.
이 정책이 사용 중인 경우 스케줄러는 각 프로세스 스레드의 nice 값에 따라 부분적으로 동적 우선순위 목록을 생성합니다. 관리자는 프로세스의 niceness 값을 변경할 수 있지만 스케줄러의 동적 우선순위 목록을 직접 변경할 수 없습니다.
프로세스 nice 값 변경에 대한 자세한 내용은 Red Hat Enterprise Linux 7 시스템 관리자 가이드를 참조하십시오.

6.3.6.2. CPU 격리

isolcpus boot 매개변수를 사용하여 스케줄러에서 하나 이상의 CPU를 분리할 수 있습니다. 이렇게 하면 스케줄러에서 이 CPU의 사용자 공간 스레드를 예약할 수 없습니다.
CPU가 분리되면 CPU 선호도 시스템 호출 또는 numactl 명령을 사용하여 격리된 CPU에 프로세스를 수동으로 할당해야 합니다.
시스템의 세 번째 및 여섯 번째 CPU를 8번째 CPU로 분리하려면 커널 명령줄에 다음을 추가합니다.
isolcpus=2,5-7
Tuna 툴을 사용하여 CPU를 격리할 수도 있습니다. Tuna 는 부팅 시뿐만 아니라 언제든지 CPU를 격리할 수 있습니다. 그러나 이 격리 방법은 isolcpus 매개변수와 크게 다르며 현재 isolcpus 와 관련된 성능 향상을 달성하지 못합니다. 이 툴에 대한 자세한 내용은 6.3.8절. “Tuna를 사용하여 CPU, Thread 및 Interrupt Affinity 구성” 을 참조하십시오.

6.3.7. AMD64 및 Intel 64에서 Interrupt Affinity 설정

인터럽트 요청에는 인터럽트 요청을 처리할 프로세서를 정의하는 smp_affinity 속성 smp_affinity가 있습니다. 애플리케이션 성능을 개선하기 위해 동일한 프로세서 또는 동일한 코어의 프로세서에 인터럽트 선호도 및 프로세스 선호도를 할당합니다. 이를 통해 지정된 인터럽트 및 애플리케이션 스레드가 캐시 라인을 공유할 수 있습니다.
중요
이 섹션에서는 AMD64 및 Intel 64 아키텍처만 다룹니다. 인터럽트 선호도 구성은 다른 아키텍처에서 크게 다릅니다.

절차 6.1. 자동으로 인터럽트 밸런싱

  • BIOS가 NUMA 토폴로지를 내보내는 경우 irqbalance 서비스는 하드웨어 요청 서비스에 로컬인 노드에서 인터럽트 요청을 자동으로 제공할 수 있습니다.
    irqbalance 구성에 대한 자세한 내용은 A.1절. “irqbalance” 을 참조하십시오.

절차 6.2. Interrupts 수동 밸런싱

  1. 구성할 인터럽트 요청에 해당하는 장치를 확인합니다.
    Red Hat Enterprise Linux 7.5부터 시스템은 특정 장치와 해당 드라이버에 대한 최적의 인터럽트 선호도를 자동으로 구성합니다. 더 이상 선호도를 수동으로 구성할 수 없습니다. 이는 다음 장치에 적용됩니다.
    • be2iscsi 드라이버를 사용하는 장치
    • NVMe PCI 장치
  2. 플랫폼의 하드웨어 사양을 찾습니다. 시스템의 칩셋이 인터럽트 배포를 지원하는지 확인합니다.
    • 이 경우 다음 단계에 설명된 대로 인터럽트 전달을 구성할 수 있습니다.
      또한 칩셋이 인터럽트의 균형을 조정하는 데 사용하는 알고리즘을 확인합니다. 일부 BIOS에는 인터럽트 전달을 구성할 수 있는 옵션이 있습니다.
    • 그렇지 않은 경우, 칩셋은 항상 모든 인터럽트를 단일 정적 CPU로 라우팅합니다. 사용 중인 CPU를 구성할 수 없습니다.
  3. 시스템에서 사용 중인 Advanced Programmable Interrupt Controller (APIC) 모드를 확인합니다.
    물리적이 아닌 플랫 모드(flat)만 인터럽트를 여러 CPU에 분산할 수 있습니다. 이 모드는 CPU가 최대 8개인 시스템에만 사용할 수 있습니다.
    $ journalctl --dmesg | grep APIC
    명령 출력에서 다음을 수행합니다.
    • 시스템이 flat 이외의 모드를 사용하는 경우 APIC 라우팅 설정과 유사한 행을 물리적 플랫 으로 볼 수 있습니다.
    • 이러한 메시지가 표시되지 않으면 시스템은 플랫 모드를 사용합니다.
    시스템에서 x2apic 모드를 사용하는 경우 부트로더 구성에서 nox2apic 옵션을 커널 명령줄에 추가하여 비활성화할 수 있습니다.
  4. smp_affinity mask를 계산합니다.
    smp_affinity 값은 시스템의 모든 프로세서를 나타내는 16진수 비트 마스크로 저장됩니다. 각 비트는 다른 CPU를 구성합니다. 최소 유효 비트는 CPU 0입니다.
    마스크의 기본값은 f 이며, 이는 인터럽트 요청이 시스템의 모든 프로세서에서 처리될 수 있음을 의미합니다. 이 값을 1 로 설정하면 프로세서 0만 인터럽트를 처리할 수 있습니다.

    절차 6.3. 영업 및 지원

    1. 바이너리에서 인터럽트를 처리할 CPU에 1 값을 사용합니다.
      예를 들어 CPU 0 및 CPU 7로 인터럽트를 처리하려면 0000000010000001 을 바이너리 코드로 사용합니다.

      표 6.1. CPU용 바이너리 비트

      CPU1514131211109876543210
      바이너리0000000010000001
    2. 바이너리 코드를 16진수로 변환합니다.
      예를 들어 Python을 사용하여 바이너리 코드를 변환하려면 다음을 수행합니다.
      >>> hex(int('0000000010000001', 2))
      
      '0x81'
      
    32개 이상의 프로세서가 있는 시스템에서는 개별 32비트 그룹에 대해 smp_affinity 값을 분리해야 합니다. 예를 들어 64 프로세서 시스템의 처음 32 프로세서만 인터럽트 요청을 서비스하려면 0xffffffffffffff 0000 을 사용합니다.
  5. smp_affinity mask를 설정합니다.
    특정 인터럽트 요청에 대한 인터럽트 선호도 값은 연결된 /proc/irq/irq_number/smp_affinity 파일에 저장됩니다.
    계산된 마스크를 연결된 파일에 씁니다.
    # echo mask > /proc/irq/irq_number/smp_affinity

추가 리소스

  • 인터럽트를 지원하는 시스템에서 인터럽트 요청의 smp_affinity 속성을 수정하면 하드웨어를 설정하여 특정 프로세서와의 인터럽트를 서비스하는 결정이 커널의 개입 없이 하드웨어 수준에서 이루어집니다.
    인터럽트 운영에 대한 자세한 내용은 9장. 네트워킹 을 참조하십시오.

6.3.8. Tuna를 사용하여 CPU, Thread 및 Interrupt Affinity 구성

Tuna 는 실행 중인 프로세스를 튜닝하는 도구이며 CPU, 스레드 및 인터럽트 선호도를 제어할 수 있으며 제어할 수 있는 각 엔터티 유형에 대한 여러 작업도 제공합니다. Tuna 에 대한 자세한 내용은 4장. tuna 을 참조하십시오.