본문 바로가기
컴퓨터과학

NUMA 아키텍처와 운영체제 최적화

by 코드그래피 2025. 1. 24.
반응형

NUMA(Non-Uniform Memory Access) 아키텍처와 운영체제 최적화는 현대 고성능 컴퓨팅 시스템에서 중요한 주제입니다. NUMA 아키텍처는 다중 프로세서 시스템에서 메모리 접근 성능을 최적화하기 위해 설계되었습니다. 이 글에서는 NUMA 아키텍처의 개념, 그와 관련된 운영체제 최적화 기법, 그리고 NUMA 시스템에서 성능을 극대화하는 방법을 다루겠습니다.

 

1. NUMA 아키텍처란?

 

1.1 NUMA의 기본 개념

 

NUMA(Non-Uniform Memory Access) 아키텍처는 멀티프로세서 시스템에서 각 프로세서가 자신만의 지역 메모리를 갖는 구조를 의미합니다. NUMA에서는 각 프로세서가 자신의 메모리 영역에 접근할 때 빠르게 처리할 수 있으며, 다른 프로세서의 메모리에 접근할 경우 성능이 저하됩니다. 이는 다중 프로세서 시스템에서 메모리 접근 속도가 균등하지 않음을 뜻합니다. NUMA 아키텍처는 SMP(Symmetric Multiprocessing) 시스템의 한계를 극복하기 위해 설계되었습니다.

 

1.2 NUMA 아키텍처의 구성 요소

 

  • 노드(Node): NUMA 시스템은 하나 이상의 프로세서와 메모리를 포함하는 노드로 구성됩니다. 각 노드는 자체적인 메모리 영역을 가집니다.
  • 프로세서: 각 노드는 최소한 하나의 프로세서를 포함하며, 여러 프로세서가 메모리를 공유합니다.
  • 메모리: 각 노드는 고유한 메모리 공간을 가지고 있으며, 다른 노드의 메모리로의 접근은 상대적으로 느립니다.

1.3 NUMA와 UMA의 차이점

 

NUMA는 비균일 메모리 접근을 지원하며, 각 프로세서가 메모리에 다르게 접근하는 반면, UMA(Uniform Memory Access) 시스템은 모든 프로세서가 메모리에 동일한 속도로 접근할 수 있는 시스템입니다. NUMA는 대규모 멀티프로세서 시스템에서 성능을 최적화하는 데 사용되며, 각 프로세서가 자신에게 가까운 메모리 영역을 빠르게 접근할 수 있게 합니다.

 

2. NUMA 아키텍처에서의 문제점

 

NUMA 시스템은 메모리 접근 속도의 비균등성으로 인해 성능 저하를 초래할 수 있습니다. 이 문제를 해결하기 위해서는 메모리 지역성을 고려한 설계와 최적화가 필요합니다. 주요 문제점은 다음과 같습니다:

  • 원거리 메모리 접근: 프로세서가 다른 프로세서의 메모리에 접근할 때, 해당 접근 속도가 매우 느려질 수 있습니다. 이는 성능에 큰 영향을 미칠 수 있습니다.
  • 스케줄링 문제: 각 프로세서가 메모리를 독립적으로 관리할 수 있기 때문에, 운영체제는 적절히 프로세서와 메모리의 위치를 맞추는 작업을 해야 합니다.

 

3. 운영체제 최적화 기법

 

3.1 메모리 할당 최적화

 

운영체제는 NUMA 시스템에서 프로세스가 최적의 성능을 낼 수 있도록 메모리 할당을 신중하게 관리해야 합니다. 메모리 할당 최적화 기법은 다음과 같습니다:

  • 프로세서 친화적 메모리 할당: 각 프로세서가 자신의 메모리 영역에 접근하도록 할당하는 방식입니다. 이를 통해 원거리 메모리 접근을 최소화하고, 성능을 최적화할 수 있습니다.
  • 메모리 분배: 프로세스가 실행될 때, 가능한 한 해당 프로세서가 위치한 노드의 메모리를 사용하도록 하여 성능 저하를 방지합니다.

 

3.2 CPU 스케줄링 최적화

NUMA(Non-Uniform Memory Access) 아키텍처와 운영체제 최적화는 현대 고성능 컴퓨팅 시스템에서 중요한 주제입니다. NUMA 아키텍처는 다중 프로세서 시스템에서 메모리 접근 성능을 최적화하기 위해 설계되었습니다. 이 글에서는 NUMA 아키텍처의 개념, 그와 관련된 운영체제 최적화 기법, 그리고 NUMA 시스템에서 성능을 극대화하는 방법을 다루겠습니다.

 

1. NUMA 아키텍처란?

 

1.1 NUMA의 기본 개념

 

NUMA(Non-Uniform Memory Access) 아키텍처는 멀티프로세서 시스템에서 각 프로세서가 자신만의 지역 메모리를 갖는 구조를 의미합니다. NUMA에서는 각 프로세서가 자신의 메모리 영역에 접근할 때 빠르게 처리할 수 있으며, 다른 프로세서의 메모리에 접근할 경우 성능이 저하됩니다. 이는 다중 프로세서 시스템에서 메모리 접근 속도가 균등하지 않음을 뜻합니다. NUMA 아키텍처는 SMP(Symmetric Multiprocessing) 시스템의 한계를 극복하기 위해 설계되었습니다.

 

1.2 NUMA 아키텍처의 구성 요소

  • 노드(Node): NUMA 시스템은 하나 이상의 프로세서와 메모리를 포함하는 노드로 구성됩니다. 각 노드는 자체적인 메모리 영역을 가집니다.
  • 프로세서: 각 노드는 최소한 하나의 프로세서를 포함하며, 여러 프로세서가 메모리를 공유합니다.
  • 메모리: 각 노드는 고유한 메모리 공간을 가지고 있으며, 다른 노드의 메모리로의 접근은 상대적으로 느립니다.

 

1.3 NUMA와 UMA의 차이점

 

NUMA는 비균일 메모리 접근을 지원하며, 각 프로세서가 메모리에 다르게 접근하는 반면, UMA(Uniform Memory Access) 시스템은 모든 프로세서가 메모리에 동일한 속도로 접근할 수 있는 시스템입니다. NUMA는 대규모 멀티프로세서 시스템에서 성능을 최적화하는 데 사용되며, 각 프로세서가 자신에게 가까운 메모리 영역을 빠르게 접근할 수 있게 합니다.

 

2. NUMA 아키텍처에서의 문제점

 

NUMA 시스템은 메모리 접근 속도의 비균등성으로 인해 성능 저하를 초래할 수 있습니다. 이 문제를 해결하기 위해서는 메모리 지역성을 고려한 설계와 최적화가 필요합니다. 주요 문제점은 다음과 같습니다:

  • 원거리 메모리 접근: 프로세서가 다른 프로세서의 메모리에 접근할 때, 해당 접근 속도가 매우 느려질 수 있습니다. 이는 성능에 큰 영향을 미칠 수 있습니다.
  • 스케줄링 문제: 각 프로세서가 메모리를 독립적으로 관리할 수 있기 때문에, 운영체제는 적절히 프로세서와 메모리의 위치를 맞추는 작업을 해야 합니다.

 

3. 운영체제 최적화 기법

 

3.1 메모리 할당 최적화

 

운영체제는 NUMA 시스템에서 프로세스가 최적의 성능을 낼 수 있도록 메모리 할당을 신중하게 관리해야 합니다. 메모리 할당 최적화 기법은 다음과 같습니다:

  • 프로세서 친화적 메모리 할당: 각 프로세서가 자신의 메모리 영역에 접근하도록 할당하는 방식입니다. 이를 통해 원거리 메모리 접근을 최소화하고, 성능을 최적화할 수 있습니다.
  • 메모리 분배: 프로세스가 실행될 때, 가능한 한 해당 프로세서가 위치한 노드의 메모리를 사용하도록 하여 성능 저하를 방지합니다.

 

3.2 CPU 스케줄링 최적화

 

3.3 NUMA 성능 모니터링 및 튜닝

 

NUMA 시스템에서 성능을 최적화하기 위해서는 성능 모니터링 도구를 사용하여 시스템의 상태를 파악하고, 이를 기반으로 튜닝을 진행해야 합니다. 주요 튜닝 방법은 다음과 같습니다:

  • CPU와 메모리 간의 거리를 모니터링: 각 프로세서와 메모리 노드 간의 성능 차이를 모니터링하고, 이를 바탕으로 자원 배치를 조정합니다.
  • 캐시 친화적 메모리 사용: 캐시가 중요한 역할을 하는 NUMA 시스템에서는 프로세서와 메모리 간의 데이터 전송을 최소화하여 캐시 효율성을 극대화합니다.

 

4. NUMA에서의 운영체제 예시

 

4.1 리눅스

 

리눅스는 NUMA 아키텍처를 잘 지원하는 운영체제 중 하나입니다. 리눅스에서는 numactrl, numactrl -H 등 명령어를 사용하여 NUMA 관련 설정을 최적화할 수 있습니다. 또한, 리눅스는 NUMA-aware 스케줄링과 메모리 할당 방식을 지원하여 멀티코어 시스템에서 성능을 최적화하는 데 유용합니다.

 

4.2 윈도우

 

윈도우는 NUMA 시스템을 지원하지만, 리눅스만큼 세밀한 조정은 제공하지 않습니다. 다만, 윈도우의 경우 NumaNodePolicy를 사용하여 NUMA 관련 최적화를 수행할 수 있습니다. 이는 프로세서가 자신에게 할당된 메모리 영역에 접근하도록 유도하여 성능을 개선하는 방법입니다.


NUMA-aware 메모리 할당 예제

 

문제 설정

 

NUMA 시스템에서는 각 프로세서가 자신만의 메모리 영역을 가집니다. 이를 고려하여 프로세스가 데이터를 처리할 때, 자신에게 가까운 메모리 영역을 사용할 수 있도록 해야 성능을 최적화할 수 있습니다. 이 예제에서는 리눅스에서 numactrl 명령어와 NUMA 친화적인 메모리 할당 방법을 사용하여 데이터를 할당하는 방법을 설명합니다.

 

코드 예제 (리눅스)

 

리눅스에서는 numactrl을 통해 NUMA 아키텍처를 제어할 수 있습니다. 또한, 프로그래밍적으로는 libnuma를 사용하여 NUMA-aware 메모리 할당을 할 수 있습니다.

 

numactrl을 통한 NUMA 설정

# NUMA 시스템에서 프로세서와 메모리 노드를 지정하여 실행
numactrl --physcpubind=0 --membind=0 ./your_program

이 명령은 your_program을 프로세서 0과 메모리 노드 0에서 실행하도록 설정합니다. 이렇게 하면, 해당 프로세스는 자신에게 가까운 메모리 노드를 사용하여 성능을 최적화합니다.

 

libnuma를 통한 NUMA-aware 메모리 할당

#include <numa.h>
#include <stdio.h>

int main() {
    if (numa_available() == -1) {
        printf("NUMA is not available on this system\n");
        return 1;
    }

    // NUMA node 0에 메모리 할당
    struct numa_mem *mem = numa_alloc_onnode(1024 * 1024, 0); // 1MB 메모리 할당
    if (mem == NULL) {
        printf("Memory allocation failed on NUMA node 0\n");
        return 1;
    }

    // 메모리 접근 및 사용
    // 예: 메모리에 데이터 쓰기
    for (int i = 0; i < 1024 * 1024; i++) {
        mem[i] = i;
    }

    // NUMA 메모리 해제
    numa_free(mem, 1024 * 1024);

    return 0;
}

 

위 코드에서는 numa_alloc_onnode를 사용하여 NUMA 노드 0에 메모리를 할당하고, 해당 메모리에 데이터를 쓰고 해제하는 예제를 보여줍니다. 이 방식은 NUMA 아키텍처에서 메모리의 물리적 위치를 제어하며, 프로세스가 가장 가까운 메모리에서 데이터를 처리하도록 돕습니다.

 

NUMA-aware CPU 스케줄링

 

NUMA 시스템에서 CPU 스케줄링은 매우 중요한 최적화 포인트입니다. CPU와 메모리 노드 간의 거리를 최소화하는 방식으로 프로세스를 스케줄링해야 합니다. 이를 통해 원거리 메모리 접근을 최소화하고 성능을 극대화할 수 있습니다.

 

코드 예제 (리눅스에서 CPU 바인딩)

 

리눅스에서는 taskset 명령어를 사용하여 프로세스를 특정 CPU에 바인딩할 수 있습니다. 이를 통해 NUMA 시스템에서 CPU와 메모리의 효율적인 매핑을 할 수 있습니다.

# CPU 0에서 실행하도록 프로세스 바인딩
taskset -c 0 ./your_program

NUMA-aware 스케줄링 코드

 

libnuma를 사용하여 NUMA-aware 스케줄링을 직접 구현할 수 있습니다. 이 예제에서는 프로세서와 메모리 노드를 고려하여 프로세스의 스케줄링을 최적화하는 방법을 설명합니다.

#include <numa.h>
#include <sched.h>
#include <stdio.h>
#include <stdlib.h>

int main() {
    if (numa_available() == -1) {
        printf("NUMA is not available on this system\n");
        return 1;
    }

    // 프로세서 0에 바인딩
    cpu_set_t cpuset;
    CPU_ZERO(&cpuset);
    CPU_SET(0, &cpuset);
    
    if (sched_setaffinity(0, sizeof(cpu_set_t), &cpuset) == -1) {
        perror("sched_setaffinity failed");
        return 1;
    }

    // NUMA 노드 0에 메모리 할당
    struct numa_mem *mem = numa_alloc_onnode(1024 * 1024, 0); // 1MB 메모리 할당
    if (mem == NULL) {
        printf("Memory allocation failed on NUMA node 0\n");
        return 1;
    }

    // CPU와 메모리 할당이 일치하는지 확인
    printf("Assigned memory and CPU are on NUMA node 0\n");

    // 메모리 해제
    numa_free(mem, 1024 * 1024);

    return 0;
}

위 코드에서는 sched_setaffinity 함수를 사용하여 프로세서를 NUMA 노드 0에 바인딩하고, 그 후 해당 노드에 메모리를 할당하여 NUMA-aware 메모리 할당과 CPU 스케줄링을 수행합니다.

 

NUMA 시스템에서 성능 최적화

 

NUMA 성능 모니터링 도구

 

NUMA 시스템에서 성능을 모니터링하는 것이 중요합니다. 다음은 NUMA 시스템에서 성능을 모니터링할 수 있는 몇 가지 도구입니다:

  • numactrl: NUMA 관련 정보를 제공하며, NUMA-aware 작업을 할 수 있는 명령어입니다.
  • numastat: NUMA 관련 통계 정보를 제공하여 메모리의 분배 상태 및 활용도를 파악할 수 있습니다.
  • hwloc: 시스템의 NUMA 아키텍처를 시각화하여 CPU, 메모리, I/O의 물리적 배치를 확인할 수 있는 도구입니다.

 

성능 최적화 기법

  • 프로세서와 메모리 간의 일관성 유지: 프로세서가 사용하는 메모리와 CPU를 최대한 가까운 노드에 배치해야 성능 저하를 방지할 수 있습니다.
  • 메모리 지역성 최적화: 프로세스가 자주 사용하는 데이터를 지역적으로 할당하여 메모리 접근 시간을 최소화해야 합니다.
  • 메모리 병목 현상 해결: 여러 프로세스가 동시에 메모리에 접근할 경우 병목 현상이 발생할 수 있습니다. 이를 해결하기 위해서는 프로세스를 적절히 배치하고, 메모리 할당을 최적화해야 합니다.

실생활 적용 사례

슈퍼컴퓨터

 

NUMA 시스템은 슈퍼컴퓨터에서 성능을 최적화하는 데 중요한 역할을 합니다. 슈퍼컴퓨터는 수많은 프로세서와 메모리 노드를 사용하므로, NUMA-aware 스케줄링과 메모리 할당을 통해 성능을 극대화할 수 있습니다.

 

대규모 데이터베이스 시스템

 

대규모 데이터베이스 시스템에서는 수많은 쿼리와 작업을 동시에 처리해야 하므로, NUMA 시스템을 최적화하여 성능을 높일 수 있습니다. 각 쿼리는 자신에게 가까운 메모리 영역에서 작업을 처리하도록 할당되며, 이는 데이터베이스 성능을 크게 향상시킵니다.

 

고성능 계산 플랫폼

 

고성능 계산을 요구하는 분야에서는 NUMA 시스템을 통해 병렬 처리와 메모리 접근 성능을 최적화할 수 있습니다. NUMA-aware 스케줄링을 통해 여러 계산 작업을 효율적으로 처리하고, 병목 현상을 최소화할 수 있습니다.

 

5. 결론

 

NUMA 아키텍처는 멀티프로세서 시스템에서 중요한 역할을 하며, 이를 효율적으로 활용하기 위해서는 운영체제 차원의 최적화가 필수적입니다. 메모리 할당 최적화, CPU 스케줄링 최적화, 그리고 성능 모니터링과 튜닝을 통해 NUMA 시스템의 성능을 극대화할 수 있습니다. NUMA-aware 스케줄링 및 메모리 할당 방식은 NUMA 시스템에서 성능을 높이고, 시스템이 원활하게 동작할 수 있도록 돕습니다.

이 글에서는 NUMA 아키텍처와 관련된 운영체제 최적화 기법을 다루었으며, 이를 통해 NUMA 시스템에서 발생할 수 있는 성능 문제를 해결할 수 있는 방법들을 제시했습니다.

반응형