13.6. 가상 머신 CPU 성능 최적화

호스트 시스템의 물리적 CPU와 마찬가지로 vCPU는 VM(가상 머신) 성능에 매우 중요합니다. 따라서 vCPU 최적화는 VM의 리소스 효율성에 상당한 영향을 미칠 수 있습니다. vCPU를 최적화하려면 다음을 수행합니다.

  1. VM에 할당되는 호스트 CPU 수를 조정합니다. CLI 또는 웹 콘솔 을 사용하여 이 작업을 수행할 수 있습니다.
  2. vCPU 모델이 호스트의 CPU 모델에 맞게 조정되었는지 확인합니다. 예를 들어, 호스트의 CPU 모델을 사용하도록 testguest1 VM을 설정하려면 다음을 수행합니다.

    # virt-xml testguest1 --edit --cpu host-model
  3. 커널 동일한 페이지 병합(KSM)을 관리합니다.
  4. 호스트 시스템에서 NUMA(Non-Uniform Memory Access)를 사용하는 경우 해당 VM에 대해 NUMA를 구성할 수도 있습니다. 이렇게 하면 호스트의 CPU 및 메모리 프로세스가 VM의 CPU 및 메모리 프로세스에 최대한 밀접하게 매핑됩니다. 실제로 NUMA 튜닝은 vCPU에 할당된 시스템 메모리에 보다 간소화된 액세스를 제공하여 vCPU 처리 효율성을 향상시킬 수 있습니다.

    자세한 내용은 가상 머신의 NUMA 구성Sample vCPU 성능 튜닝 시나리오를 참조하십시오.

13.6.1. 명령줄 인터페이스를 사용하여 가상 CPU 추가 및 제거

VM(가상 머신)의 CPU 성능을 늘리거나 최적화하기 위해 VM에 할당된 가상 CPU(vCPU)를 추가하거나 제거할 수 있습니다.

실행 중인 VM에서 수행할 때 이 작업을 vCPU 핫 플러그링 및 핫 플러그 연결이라고도 합니다. 그러나 RHEL 9에서는 vCPU 핫 언플러그가 지원되지 않으며 Red Hat은 사용하지 않는 것이 좋습니다.

사전 요구 사항

  • 선택 사항: 대상 VM에서 vCPU의 현재 상태를 확인합니다. 예를 들어 testguest VM에 vCPU 수를 표시하려면 다음을 수행합니다.

    # virsh vcpucount testguest
    maximum      config         4
    maximum      live           2
    current      config         2
    current      live           1

    이 출력은 현재 testguest 가 1 vCPU를 사용하고 있으며 VM 성능을 높이기 위해 1개의 vCPu를 핫 플러그로 연결할 수 있음을 나타냅니다. 그러나 재부팅 후 testguest 의 수는 2로 변경되며 두 개의 vCPU를 핫 플러그로 변경할 수 있습니다.

절차

  1. VM에 연결할 수 있는 최대 vCPU 수를 조정하여 VM의 다음 부팅에 적용됩니다.

    예를 들어 testguest VM의 최대 vCPU 수를 8로 늘리려면 다음을 수행합니다.

    # virsh setvcpus testguest 8 --maximum --config

    CPU 토폴로지, 호스트 하드웨어, 하이퍼바이저 및 기타 요인에 의해 최대값이 제한될 수 있습니다.

  2. VM에 연결된 현재 vCPU 수를 이전 단계에서 구성한 최대값까지 조정합니다. 예를 들어 다음과 같습니다.

    • 실행 중인 testguest VM에 연결된 vCPU 수를 4로 늘리려면 다음을 수행합니다.

      # virsh setvcpus testguest 4 --live

      이렇게 하면 VM의 다음 부팅이 될 때까지 VM의 성능 및 호스트 로드 공간이 testguest 의 성능 및 호스트 로드가 증가합니다.

    • testguest VM에 연결된 vCPU 수를 1로 영구적으로 줄입니다.

      # virsh setvcpus testguest 1 --config

      이렇게 하면 VM의 다음 부팅 후 VM의 성능 및 호스트 로드 풋프린트가 감소됩니다. 하지만 필요한 경우 추가 vCPU를 VM에 핫 플러그하여 일시적으로 성능을 향상시킬 수 있습니다.

검증

  • VM의 현재 vCPU 상태가 변경 사항을 반영하는지 확인합니다.

    # virsh vcpucount testguest
    maximum      config         8
    maximum      live           4
    current      config         1
    current      live           4

13.6.2. 웹 콘솔을 사용하여 가상 CPU 관리

RHEL 9 웹 콘솔을 사용하면 웹 콘솔이 연결된 VM(가상 머신)에서 사용하는 가상 CPU를 검토하고 구성할 수 있습니다.

사전 요구 사항

절차

  1. 가상 머신 인터페이스에서 정보를 확인할 VM을 클릭합니다.

    선택한 VM 및 콘솔 섹션에 대한 기본 정보가 포함된 개요 섹션이 있는 새 페이지가 열리고 VM의 그래픽 인터페이스에 액세스합니다.

  2. 개요 창에서 vCPU 수 옆에 있는 편집 을 클릭합니다.

    vCPU 세부 정보 대화 상자가 나타납니다.

    VM CPU 세부 정보 대화 상자를 표시하는 이미지입니다.
  1. 선택한 VM의 가상 CPU를 구성합니다.

    • vCPU 수 - 현재 사용 중인 vCPU 수입니다.

      참고

      vCPU 수는 vCPU 최대값보다 클 수 없습니다.

    • vCPU 최대 - VM에 대해 구성할 수 있는 가상 CPU의 최대 수입니다. 이 값이 vCPU 개수보다 높으면 추가 vCPU 를 VM에 연결할 수 있습니다.
    • sockets - VM에 노출하는 소켓 수입니다.
    • 코어당 코어 수 - VM에 노출하는 각 소켓의 코어 수입니다.
    • 코어당 스레드 수 - VM에 노출될 각 코어의 스레드 수입니다.

      소켓,소켓당 코어 수 및 코어 옵션당 스레드 는 VM의 CPU 토폴로지를 조정합니다. 이는 vCPU 성능에 유용할 수 있으며 게스트 OS에서 특정 소프트웨어의 기능에 영향을 미칠 수 있습니다. 배포에 다른 설정이 필요하지 않은 경우 기본값을 유지합니다.

  2. 적용을 클릭합니다.

    VM의 가상 CPU가 구성됩니다.

    참고

    가상 CPU 설정 변경 사항은 VM을 재시작한 후에만 적용됩니다.

13.6.3. 가상 머신에서 NUMA 구성

다음 방법을 사용하여 RHEL 9 호스트에서 가상 머신(VM)의 NUMA(Non-Uniform Memory Access) 설정을 구성할 수 있습니다.

사전 요구 사항

  • 호스트는 NUMA 호환 시스템입니다. 대소문자를 감지하려면 virsh nodeinfo 명령을 사용하여 NUMA 셀 을 확인합니다.

    # virsh nodeinfo
    CPU model:           x86_64
    CPU(s):              48
    CPU frequency:       1200 MHz
    CPU socket(s):       1
    Core(s) per socket:  12
    Thread(s) per core:  2
    NUMA cell(s):        2
    Memory size:         67012964 KiB

    행 값이 2 이상인 경우 호스트는 NUMA와 호환됩니다.

절차

쉽게 사용할 수 있도록 자동화된 유틸리티 및 서비스를 사용하여 VM의 NUMA 구성을 설정할 수 있습니다. 그러나 수동 NUMA 설정은 성능이 크게 향상될 가능성이 높습니다.

자동 방법

  • VM의 NUMA 정책을 Preferred 로 설정합니다. 예를 들어 testguest5 VM에 대해 이렇게 하려면 다음을 수행합니다.

    # virt-xml testguest5 --edit --vcpus placement=auto
    # virt-xml testguest5 --edit --numatune mode=preferred
  • 호스트에서 자동 NUMA 분산을 활성화합니다.

    # echo 1 > /proc/sys/kernel/numa_balancing
  • numad 명령을 사용하여 VM CPU를 메모리 리소스와 자동으로 조정합니다.

    # numad

수동 방법

  1. 특정 vCPU 스레드를 특정 호스트 CPU 또는 CPU 범위에 고정합니다. 이는 NUMA 이외의 호스트 및 VM에서도 가능하며 안전한 vCPU 성능 향상 방법으로 권장됩니다.

    예를 들어 다음 명령은 vCPU 스레드 0~5를 testguest6 VM의 호스트 CPU 1, 3, 5, 7, 9, 11에 고정합니다.

    # virsh vcpupin testguest6 0 1
    # virsh vcpupin testguest6 1 3
    # virsh vcpupin testguest6 2 5
    # virsh vcpupin testguest6 3 7
    # virsh vcpupin testguest6 4 9
    # virsh vcpupin testguest6 5 11

    그런 다음 이것이 성공했는지 확인할 수 있습니다.

    # virsh vcpupin testguest6
    VCPU   CPU Affinity
    ----------------------
    0      1
    1      3
    2      5
    3      7
    4      9
    5      11
  2. vCPU 스레드를 고정한 후 지정된 VM과 연결된 QEMU 프로세스 스레드를 특정 호스트 CPU 또는 CPU 범위에 고정할 수도 있습니다. 예를 들어 다음 명령은 testguest6 의 QEMU 프로세스 스레드를 CPU 13 및 15에 고정하고 성공적으로 완료되었는지 확인합니다.

    # virsh emulatorpin testguest6 13,15
    # virsh emulatorpin testguest6
    emulator: CPU Affinity
    ----------------------------------
           *: 13,15
  3. 마지막으로 특정 VM에 구체적으로 할당할 호스트 NUMA 노드를 지정할 수도 있습니다. 이를 통해 VM의 vCPU에 의해 호스트 메모리 사용량을 개선할 수 있습니다. 예를 들어 다음 명령은 호스트 NUMA 노드 3을 5로 사용하도록 testguest6 를 설정하고 성공적인지 확인합니다.

    # virsh numatune testguest6 --nodeset 3-5
    # virsh numatune testguest6
참고

최상의 성능 결과를 얻으려면 위에 나열된 수동 튜닝 방법을 모두 사용하는 것이 좋습니다.

추가 리소스

13.6.4. 샘플 vCPU 성능 튜닝 시나리오

가능한 최상의 vCPU 성능을 얻으려면 다음 시나리오에서와 같이 수동 vcpupin,emulatorpinnumatune 설정을 함께 사용하는 것이 좋습니다.

시작 시나리오

  • 호스트에는 다음과 같은 하드웨어 관련 사항이 있습니다.

    • NUMA 노드 2개
    • 각 노드의 CPU 코어 3개
    • 각 코어의 2개 스레드

    이러한 머신의 virsh nodeinfo 출력은 다음과 유사합니다.

    # virsh nodeinfo
    CPU model:           x86_64
    CPU(s):              12
    CPU frequency:       3661 MHz
    CPU socket(s):       2
    Core(s) per socket:  3
    Thread(s) per core:  2
    NUMA cell(s):        2
    Memory size:         31248692 KiB
  • 기존 VM을 8개의 vCPU를 사용하도록 수정하려고 합니다. 즉, 단일 NUMA 노드에 맞지 않습니다.

    따라서 각 NUMA 노드에 4개의 vCPU를 배포하고 vCPU 토폴로지를 호스트 토폴로지와 최대한 가깝게 만들어야 합니다. 즉, 지정된 물리적 CPU의 형제 스레드로 실행되는 vCPU를 동일한 코어의 호스트 스레드에 고정해야 합니다. 자세한 내용은 아래 솔루션을 참조하십시오.

해결책

  1. 호스트 토폴로지에 대한 정보를 가져옵니다.

    # virsh capabilities

    출력에는 다음과 유사한 섹션이 포함되어야 합니다.

    <topology>
      <cells num="2">
        <cell id="0">
          <memory unit="KiB">15624346</memory>
          <pages unit="KiB" size="4">3906086</pages>
          <pages unit="KiB" size="2048">0</pages>
          <pages unit="KiB" size="1048576">0</pages>
          <distances>
            <sibling id="0" value="10" />
            <sibling id="1" value="21" />
          </distances>
          <cpus num="6">
            <cpu id="0" socket_id="0" core_id="0" siblings="0,3" />
            <cpu id="1" socket_id="0" core_id="1" siblings="1,4" />
            <cpu id="2" socket_id="0" core_id="2" siblings="2,5" />
            <cpu id="3" socket_id="0" core_id="0" siblings="0,3" />
            <cpu id="4" socket_id="0" core_id="1" siblings="1,4" />
            <cpu id="5" socket_id="0" core_id="2" siblings="2,5" />
          </cpus>
        </cell>
        <cell id="1">
          <memory unit="KiB">15624346</memory>
          <pages unit="KiB" size="4">3906086</pages>
          <pages unit="KiB" size="2048">0</pages>
          <pages unit="KiB" size="1048576">0</pages>
          <distances>
            <sibling id="0" value="21" />
            <sibling id="1" value="10" />
          </distances>
          <cpus num="6">
            <cpu id="6" socket_id="1" core_id="3" siblings="6,9" />
            <cpu id="7" socket_id="1" core_id="4" siblings="7,10" />
            <cpu id="8" socket_id="1" core_id="5" siblings="8,11" />
            <cpu id="9" socket_id="1" core_id="3" siblings="6,9" />
            <cpu id="10" socket_id="1" core_id="4" siblings="7,10" />
            <cpu id="11" socket_id="1" core_id="5" siblings="8,11" />
          </cpus>
        </cell>
      </cells>
    </topology>
  2. 선택 사항: 해당 툴 및 유틸리티를 사용하여 VM의 성능을 테스트합니다.
  3. 호스트에서 1GiB 대규모 페이지를 설정하고 마운트합니다.

    1. 호스트의 커널 명령줄에 다음 행을 추가합니다.

      default_hugepagesz=1G hugepagesz=1G
    2. 다음 콘텐츠를 사용하여 /etc/systemd/system/hugetlb-gigantic-pages.service 파일을 만듭니다.

      [Unit]
      Description=HugeTLB Gigantic Pages Reservation
      DefaultDependencies=no
      Before=dev-hugepages.mount
      ConditionPathExists=/sys/devices/system/node
      ConditionKernelCommandLine=hugepagesz=1G
      
      [Service]
      Type=oneshot
      RemainAfterExit=yes
      ExecStart=/etc/systemd/hugetlb-reserve-pages.sh
      
      [Install]
      WantedBy=sysinit.target
    3. 다음 콘텐츠를 사용하여 /etc/systemd/hugetlb-reserve-pages.sh 파일을 만듭니다.

      #!/bin/sh
      
      nodes_path=/sys/devices/system/node/
      if [ ! -d $nodes_path ]; then
      	echo "ERROR: $nodes_path does not exist"
      	exit 1
      fi
      
      reserve_pages()
      {
      	echo $1 > $nodes_path/$2/hugepages/hugepages-1048576kB/nr_hugepages
      }
      
      reserve_pages 4 node1
      reserve_pages 4 node2

      이렇게 하면 node1 에서 4GiB 대규모 페이지를 예약하고 node2 에서 4GiB 대규모 페이지를 예약합니다.

    4. 이전 단계에서 생성한 스크립트를 실행 파일로 만듭니다.

      # chmod +x /etc/systemd/hugetlb-reserve-pages.sh
    5. 부팅 시 대규모 페이지 예약을 활성화합니다.

      # systemctl enable hugetlb-gigantic-pages
  4. 이 예제에서는 super-VM 예제에서 최적화하려는 VM의 XML 구성을 편집하려면 virsh edit 명령을 사용합니다.

    # virsh edit super-vm
  5. VM의 XML 구성을 다음과 같이 조정합니다.

    1. 8개의 정적 vCPU를 사용하도록 VM을 설정합니다. < vcpu/> 요소를 사용하여 이 작업을 수행합니다.
    2. 각 vCPU 스레드를 토폴로지에서 미러링하는 해당 호스트 CPU 스레드에 고정합니다. 이렇게 하려면 < cpu tune> 섹션의 <vcpu pin/ > 요소를 사용합니다.

      위의 virsh capabilities 유틸리티에서와 같이 호스트 CPU 스레드는 해당 코어에서 순차적으로 정렬되지 않습니다. 또한 vCPU 스레드는 동일한 NUMA 노드에서 사용 가능한 최고 호스트 코어 세트에 고정되어야 합니다. 테이블 그림은 아래의 샘플 토폴로지 섹션을 참조하십시오.

      1단계와 b 단계를 위한 XML 구성은 다음과 같습니다.

      <cputune>
        <vcpupin vcpu='0' cpuset='1'/>
        <vcpupin vcpu='1' cpuset='4'/>
        <vcpupin vcpu='2' cpuset='2'/>
        <vcpupin vcpu='3' cpuset='5'/>
        <vcpupin vcpu='4' cpuset='7'/>
        <vcpupin vcpu='5' cpuset='10'/>
        <vcpupin vcpu='6' cpuset='8'/>
        <vcpupin vcpu='7' cpuset='11'/>
        <emulatorpin cpuset='6,9'/>
      </cputune>
    3. 1GiB 대규모 페이지를 사용하도록 VM을 설정합니다.

      <memoryBacking>
        <hugepages>
          <page size='1' unit='GiB'/>
        </hugepages>
      </memoryBacking>
    4. 호스트의 해당 NUMA 노드의 메모리를 사용하도록 VM의 NUMA 노드를 구성합니다. 이렇게 하려면 < numatune /> 섹션의 <memnode / > 요소를 사용합니다.

      <numatune>
        <memory mode="preferred" nodeset="1"/>
        <memnode cellid="0" mode="strict" nodeset="0"/>
        <memnode cellid="1" mode="strict" nodeset="1"/>
      </numatune>
    5. CPU 모드가 host-passthrough 로 설정되어 있고 CPU가 passthrough 모드에서 캐시를 사용하는지 확인합니다.

      <cpu mode="host-passthrough">
        <topology sockets="2" cores="2" threads="2"/>
        <cache mode="passthrough"/>

검증

  1. VM의 결과 XML 구성에 다음과 유사한 섹션이 포함되어 있는지 확인합니다.

    [...]
      <memoryBacking>
        <hugepages>
          <page size='1' unit='GiB'/>
        </hugepages>
      </memoryBacking>
      <vcpu placement='static'>8</vcpu>
      <cputune>
        <vcpupin vcpu='0' cpuset='1'/>
        <vcpupin vcpu='1' cpuset='4'/>
        <vcpupin vcpu='2' cpuset='2'/>
        <vcpupin vcpu='3' cpuset='5'/>
        <vcpupin vcpu='4' cpuset='7'/>
        <vcpupin vcpu='5' cpuset='10'/>
        <vcpupin vcpu='6' cpuset='8'/>
        <vcpupin vcpu='7' cpuset='11'/>
        <emulatorpin cpuset='6,9'/>
      </cputune>
      <numatune>
        <memory mode="preferred" nodeset="1"/>
        <memnode cellid="0" mode="strict" nodeset="0"/>
        <memnode cellid="1" mode="strict" nodeset="1"/>
      </numatune>
      <cpu mode="host-passthrough">
        <topology sockets="2" cores="2" threads="2"/>
        <cache mode="passthrough"/>
        <numa>
          <cell id="0" cpus="0-3" memory="2" unit="GiB">
            <distances>
              <sibling id="0" value="10"/>
              <sibling id="1" value="21"/>
            </distances>
          </cell>
          <cell id="1" cpus="4-7" memory="2" unit="GiB">
            <distances>
              <sibling id="0" value="21"/>
              <sibling id="1" value="10"/>
            </distances>
          </cell>
        </numa>
      </cpu>
    </domain>
  2. 선택 사항: 해당 툴 및 유틸리티를 사용하여 VM의 성능을 테스트하여 VM 최적화의 영향을 평가합니다.

토폴로지 샘플

  • 다음 표에서는 vCPU와 해당 CPU가 고정된 호스트 CPU 간 연결을 보여줍니다.

    표 13.2. 호스트 토폴로지

    CPU 스레드

    0

    3

    1

    4

    2

    5

    6

    9

    7

    10

    8

    11

    코어

    0

    1

    2

    3

    4

    5

    소켓

    0

    1

    NUMA 노드

    0

    1

    표 13.3. VM 토폴로지

    vCPU 스레드

    0

    1

    2

    3

    4

    5

    6

    7

    코어

    0

    1

    2

    3

    소켓

    0

    1

    NUMA 노드

    0

    1

    표 13.4. 결합된 호스트 및 VM 토폴로지

    vCPU 스레드

     

    0

    1

    2

    3

     

    4

    5

    6

    7

    호스트 CPU 스레드

    0

    3

    1

    4

    2

    5

    6

    9

    7

    10

    8

    11

    코어

    0

    1

    2

    3

    4

    5

    소켓

    0

    1

    NUMA 노드

    0

    1

    이 시나리오에는 NUMA 노드 2개와 8개의 vCPU가 있습니다. 따라서 4 vCPU 스레드를 각 노드에 고정해야 합니다.

    또한 Red Hat은 호스트 시스템 작업을 위해 각 노드에서 적어도 하나의 CPU 스레드를 사용할 수 있도록 하는 것이 좋습니다.

    이 예제에서 각 NUMA 노드에는 각각 2개의 호스트 CPU 스레드가 있는 코어 3개가 있으므로 노드 0에 대한 세트가 다음과 같이 변환됩니다.

    <vcpupin vcpu='0' cpuset='1'/>
    <vcpupin vcpu='1' cpuset='4'/>
    <vcpupin vcpu='2' cpuset='2'/>
    <vcpupin vcpu='3' cpuset='5'/>

13.6.5. 커널 동일한 페이지 병합 관리

KSM(커널 동일 페이지 병합)은 VM(가상 머신) 간에 동일한 메모리 페이지를 공유하여 메모리 밀도를 향상시킵니다. 그러나 KSM을 활성화하면 CPU 사용률이 증가하며 워크로드에 따라 전체 성능에 부정적인 영향을 미칠 수 있습니다.

요구 사항에 따라 단일 세션에 대해 KSM을 활성화하거나 비활성화할 수 있습니다.

참고

RHEL 9 이상에서는 KSM이 기본적으로 비활성화되어 있습니다.

사전 요구 사항

  • 호스트 시스템에 대한 루트 액세스.

절차

  • KSM을 비활성화합니다.

    • 단일 세션에 대해 KSM을 비활성화하려면 systemctl 유틸리티를 사용하여 ksmksmtuned 서비스를 중지합니다.

      # systemctl stop ksm
      
      # systemctl stop ksmtuned
    • KSM을 영구적으로 비활성화하려면 systemctl 유틸리티를 사용하여 ksmksmtuned 서비스를 비활성화합니다.

      # systemctl disable ksm
      Removed /etc/systemd/system/multi-user.target.wants/ksm.service.
      # systemctl disable ksmtuned
      Removed /etc/systemd/system/multi-user.target.wants/ksmtuned.service.
참고

KSM을 비활성화하기 전에 VM 간에 공유되는 메모리 페이지는 공유로 유지됩니다. 공유를 중지하려면 다음 명령을 사용하여 시스템의 모든 PageKSM 페이지를 삭제합니다.

# echo 2 > /sys/kernel/mm/ksm/run

익명 페이지가 KSM 페이지를 교체한 후 khugepaged 커널 서비스는 VM의 실제 메모리에서 투명한 hugepages를 다시 빌드합니다.

  • KSM을 활성화합니다.
주의

KSM을 활성화하면 CPU 사용률이 증가하고 전체 CPU 성능에 영향을 미칩니다.

  1. ksmtuned 서비스를 설치합니다.

    # dnf install ksmtuned

  2. 서비스를 시작합니다.

    • 단일 세션에 KSM을 활성화하려면 systemctl 유틸리티를 사용하여 ksmksmtuned 서비스를 시작합니다.

      # systemctl start ksm
      # systemctl start ksmtuned
    • KSM을 영구적으로 활성화하려면 systemctl 유틸리티를 사용하여 ksmksmtuned 서비스를 활성화합니다.

      # systemctl enable ksm
      Created symlink /etc/systemd/system/multi-user.target.wants/ksm.service → /usr/lib/systemd/system/ksm.service
      
      # systemctl enable ksmtuned
      Created symlink /etc/systemd/system/multi-user.target.wants/ksmtuned.service → /usr/lib/systemd/system/ksmtuned.service