요약
- "새로 만든 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로 맞춰야 한다.
관련 노트
- Fargate는 물리 CPU 세대를 고를 수 없어 같은 태스크 정의라도 성능이 1.5~2배 갈린다
- 처리 속도가 제각각인 서버에는 round robin 대신 least outstanding requests를 쓴다
- ECS Exec SSM Agent는 readonlyRootFilesystem에서 동작하지 않는다
- 변수 하나만 바꾼 카나리를 같은 타깃그룹에 동시 투입하면 부하 교란 없이 회귀 원인을 격리한다
참고
- https://scalefactory.com/blog/2021/05/12/what-powers-ecs-fargate/
- https://github.com/torvalds/linux/blob/master/arch/arm64/include/asm/cputype.h
- https://docs.aws.amazon.com/whitepapers/latest/aws-graviton-performance-testing/other-considerations.html
- https://aws.amazon.com/blogs/aws/announcing-aws-graviton2-support-for-aws-fargate-get-up-to-40-better-price-performance-for-your-serverless-containers
- https://chipsandcheese.com/p/arms-neoverse-v2-in-awss-graviton-4