Zettelkasten

Fargate에서 서브넷을 한 AZ로 묶어도 CPU 세대는 못 고른다

·수정 1회

요약

  • "새로 만든 AZ일수록 새 CPU가 깔려 있으니 서브넷을 그 AZ로 제한해서 최신 칩을 타겟팅하라"는 조언이 널리 퍼져 있는데, ap-northeast-2에서 재보니 안 통한다. AZ를 고정해도 같은 AZ 안에서 세대가 섞여 나온다.
  • AZ×아키텍처당 8개씩 총 64개 태스크를 띄운 결과, x86은 어느 AZ에서도 Cascade Lake와 다른 세대가 섞였다. AZ 수준에서 통계적으로 유의한 차이는 Sapphire Rapids(8488C)가 apne2-az4에서만 나온 것 하나뿐인데, 그것도 8회 중 3회(38%)라 서브넷을 그쪽으로 옮겨도 확정 이득이 아니다.
  • 세대 번호 순서가 곧 속도 순서도 아니다. Skylake(8175M)가 Cascade Lake(8259CL)보다 구세대인데 이 워크로드에선 중앙값 2.92초 대 2.91초로 사실상 같았다. 반면 같은 x86 안에서 Sapphire Rapids는 2.2배 빨랐다.

본문

확인하려던 조언

Fargate는 물리 CPU를 고를 수 없다(Fargate는 물리 CPU 세대를 고를 수 없어 같은 태스크 정의라도 성능이 1.5~2배 갈린다). 그래서 나온 우회책이 AZ 타겟팅이다. 2021년에 17개 리전에서 51.7만 회 벤치마크를 돌린 조사가 "새 AZ일수록 새 CPU를 쓰고, RunTask에 넘기는 서브넷을 그 AZ로 제한하면 명시적으로 타겟팅할 수 있다"고 했고, 이 결론이 이후 여기저기 인용된다. 그 조사에서 ap-northeast-2는 AZ 간 편차가 큰 리전으로 꼽혔다.

측정 방법

busybox 이미지로 1 vCPU / 2GB 태스크를 띄우고 /proc/cpuinfo를 읽었다. 서브넷만 바꾸고 태스크 정의·이미지·크기는 전부 동일하게 뒀다. AZ 4개 × 아키텍처 2개 × 8회 = 64개. 부하 측정은 awk 정수 루프를 태스크마다 3회 돌려 최소값을 썼다.

sh -c 'uname -m; head -c 1500 /proc/cpuinfo;
       for r in 1 2 3; do time awk "BEGIN{s=0;for(i=0;i<5000000;i++)s+=i%7;print s}"; done'

x86_64 결과 (각 n=8)

AZ ID 8259CL (Cascade Lake) 8175M (Skylake) 8488C (Sapphire Rapids)
apne2-az1 7 (88%) 1 (12%) –
apne2-az2 8 (100%) – –
apne2-az3 6 (75%) 2 (25%) –
apne2-az4 5 (62%) – 3 (38%)

벤치 최소시간: 8259CL 2.87초, 8175M 2.82초, 8488C 1.28초.

ARM64 결과 (각 n=8)

AZ ID Neoverse V1 = Graviton3 Neoverse V2 = Graviton4
apne2-az1 2 (25%) 6 (75%)
apne2-az2 2 (25%) 6 (75%)
apne2-az3 2 (25%) 6 (75%)
apne2-az4 4 (50%) 4 (50%)

벤치 최소시간: Graviton3 1.49초, Graviton4 1.31초.

읽는 법

AZ를 고정해도 세대가 안 고정된다. 같은 서브넷에 같은 태스크 정의로 8번 띄우면 8번 다 같은 칩이 나와야 타겟팅이 성립하는데, az2를 뺀 모든 AZ에서 두 종류 이상이 나왔다. 뽑기의 확률 분포가 AZ마다 조금 다를 뿐 뽑기라는 사실 자체는 그대로다.

AZ 수준의 차이가 아예 없지는 않다. Sapphire Rapids(8488C)는 az4에서 8회 중 3회 나왔고 나머지 24회에서는 0회였다. Fisher 정확검정 단측 p = 0.011로, 우연으로 보기는 어렵다. 하지만 그 AZ로 옮겨도 38% 확률이라 "최신 칩을 고른다"가 되지 않는다. 서브넷과 NAT를 새로 만드는 비용까지 감안하면 레버로 쓸 수 없다.

세대 번호와 속도 순서가 어긋난다. 8175M(Skylake, 2017)은 8259CL(Cascade Lake, 2019)보다 두 세대 구형인데 이 벤치에서는 중앙값이 2.92초 대 2.91초로 구분이 안 됐다. 정수 루프라 세대 간 차이가 잘 안 드러나는 워크로드인 탓도 있지만, 같은 조건에서 8488C만 1.28초로 2.2배 빨랐던 걸 보면 "구세대 = 느림"을 일괄 적용할 수는 없다는 뜻이다.

ARM 쪽에서 부수적으로 확인된 것

  • 64회 중 Graviton2(Neoverse N1, MIDR part 0xd0c)는 한 번도 안 나왔다. 전부 Graviton3 아니면 Graviton4였다. "Fargate ARM64는 Graviton2"라는 설명이 아직 돌아다니는데 적어도 이 리전·이 시점 관찰로는 맞지 않는다.
  • ARM은 AZ별 분포 차이가 유의하지 않았다(az4의 Graviton3 비중에 대해 Fisher 단측 p = 0.19).
  • 세대 폭이 좁아서 뽑기의 손실이 작다. 최악의 뽑기인 Graviton3가 1.49초로, x86의 최빈값인 8259CL(2.87초)보다 빠르다.
  • 단 1 vCPU의 의미가 다르다. Graviton은 SMT가 없어 vCPU 하나가 물리 코어 하나에 1:1로 대응하고, x86 인스턴스는 코어당 스레드 2개라 vCPU 하나가 하이퍼스레드 하나다. 위 x86 대 ARM 격차의 상당 부분이 여기서 온다.

MIDR로 ARM 세대 읽기

aarch64의 /proc/cpuinfo에는 model name이 없다. CPU part의 MIDR 값으로 판별한다. 커널 arch/arm64/include/asm/cputype.h 기준:

CPU part 코어 AWS 칩
0xd0c Neoverse N1 Graviton2
0xd40 Neoverse V1 Graviton3
0xd4f Neoverse V2 Graviton4
0xd84 Neoverse V3 –

이 측정의 한계

벤치가 awk 단일 스레드 정수 루프라 메모리 대역폭·SSL·DB IO가 안 잡힌다. 실제 웹 워크로드의 세대 간 격차는 이보다 클 수도 작을 수도 있다. 셀당 표본이 8개고 측정은 2026-08-25 한 번뿐이라, AWS가 배치 정책이나 하드웨어 구성을 바꾸면 분포는 달라진다. AZ 문자(ap-northeast-2a 등)와 AZ ID(apne2-az1 등)의 대응은 계정마다 다르므로 다른 계정에서 재현할 때는 AZ ID로 맞춰야 한다.

관련 노트

참고