SQL Server 2005부터 H/W NUMA를 본격적으로 지원하고 있습니다.
NUMA란 Non-Uniform Memory Access으로 간단하게 특정 CPU 그룹 단위로
전용 메모리 공간을 가지는 것을 말합니다.
기존 SMP환경에서는 다수의 CPU가 동일한 메모리를 바라보게 되어
메모리 엑세스 경합이라는 문제가 발생하여 이러한 문제를 극복하고자 NUMA 아키텍쳐가
소개되었습니다.
기존 x86, x64 프로세스에서는 AMD의 옵테론 정도만 H/W NUMA를 지원하고 있었으나,
요즘 INTEL에서 발표된 네할렘 CPU도 메모리 컨트롤러가 CPU 내부로 들어가면서
CPU 당 NUMA 노드 하나씩 설정 할 수 있게 되었습니다.
그렇다면 SQL Server에서 NUMA를 사용하는 것이 기존 SMP환경보다 더 좋을까요?
여러 CPU가 하나의 메모리를 바라보지 않아도 되고, NUMA 노드별로 Lazy Write 프로세스가
독립적으로 생겨 성능상 이점을 줄 수 있습니다. 하지만 NUMA 또한 단점이 있습니다.
CPU 노드별로 NUMA 노드가 생기는 경우를 예로 들어보면
내가 어떠한 쿼리를 수행하기 위해서 필요한 데이터가 로컬 메모리에 있을 수도 있고,
리모트 메모리에 있을 수도 있습니다. 만약 모든 데이터가 로컬 메모리에 존재한다면
특별한 추가적인 작업 없이 데이터를 엑세스 할 수 있을 것이니다. 하지만 리모트에
데이터가 있다면 추가적인 오버헤드가 발생하게 됩니다. 하지만 일반적으로 메모리가 워낙 빨라
로컬 메모리에서 읽든, 리모트에서 읽든 사용자는 체감하기는 쉽지 않습니다.
그럼 과연 NUMA를 사용하는 SQL Server환경에서 리모트 메모리 엑세스와 로컬 메모리 엑세스가
눈에 보이는 성능 차이가 발생할지 또 어느정도 차이가 발생할지 살펴보겠습니다.
테스트는 두 가지로 샘플 테이블을 만들고 테이블을 쭉 읽는 SCAN 작업과 넌 클러스터 인덱스에서
데이터 페이지를 Lookup하도록 하여 테스트 하였습니다. 노드별 시간을 측정하기 위해 우선 NUMA
노드별로 데이터를 올리기 위해 TCP/IP 포트와 NUMA노드를 매핑하여 테스트 하였습니다.
1000번 포트로 연결하면 0번 NUMA 노드로, 2000번 포트로 연결하면 1번 NUMA 노드만을
사용하도록 세팅하였습니다. 모든 데이터 페이지를 비운 후 1000번 포트로 접근하여, 0번 노드의
Freepage에 데이터 페이지를 채운 후 두 개의 쿼리를 각각 5번씩 수행하였습니다.
처음으로 살펴볼 것은 lookup이 발생하는 쿼리 입니다.
SET STATISTICS TIME은 ms 단위이기에 두 경우가 비슷하게 나오는 경향이 있어 DMV를 통해
응답시간을 비교했습니다.
아래 표에서 볼 부분은 avg_Elapsed_Time(ms) 입니다.
로컬 메모리 엑세스와 리모트 메모리 엑세스의 평균 수행시간이 12ms정도 차이가 나는 것을 볼 수 statement_text ExecutionCount avg_Elapsed_Time(ms) max_Elapsed_Time(ms) avg_Worker_Time(ms) avg_logical_reads 로컬(0번 노드) SELECT @COL = COL2 FROM test..tbl WITH(NOLOCK,index=2) OPTION(MAXDOP 1) 5 391.406 404.296 391.406 106541 리모트(1번 노드) SELECT @COL = COL2 FROM test..tbl WITH(NOLOCK,index=2) OPTION(MAXDOP 1) 5 403.906 413.085 403.906 106541
있습니다.
두 번째로 살펴볼 것은 SCAN하는 쿼리입니다.
로컬 메모리 엑세스와 리모트 메모리 엑세스의 평균 수행시간이 4ms정도 차이가 나는 것을 볼 수
있습니다.
statement_text |
ExecutionCount |
avg_Elapsed_Time(ms) |
max_Elapsed_Time(ms) |
avg_Worker_Time(ms) |
avg_logical_reads | |
로컬(0번 노드) |
SELECT @COL = COL2 FROM test..tbl WITH(NOLOCK) OPTION(MAXDOP 1) |
5 |
293.554 |
303.71 |
293.554 |
100031 |
리모트(1번 노드) |
SELECT @COL = COL2 FROM test..tbl WITH(NOLOCK) OPTION(MAXDOP 1) |
5 |
297.851 |
304.687 |
297.851 |
100031 |
이러한 결과를 볼 때 분명 리모트 메모리 엑세스는 분명 로컬 메모리 엑세스 보다 느린 것을 볼 수
있습니다. 그렇다면 이러한 문제를 해결 할 수 있는 방법은 없을까? 아니 보다 효율적으로 사용할 수
있는 방법은 없을까에 대한 고민은 다음에 정리하도록 하겠습니다.
송 혁, SQL Server MVP
sqler.com // sqlleader.com
hyoksong.tistory.com