Kubernetes 1.23 이상 또는 OCP 4.10 이상을 사용하는 Cluster에서 Pod를 구동하다보면,
Pod Status가 SMTAlignmentError 에러 상태가 되면서 구동하지 못하는 경우를 만난다.
CPU Pinning을 위해 아래처럼 Pod Spec을 설정한 경우에 볼 수 있는 에러이다.
아래 YAML 예시에서 cpu 개수를 5개 설정한 것이 문제를 발생시킨다. (홀수로 설명하는 것이 문제)
kind: Pod
metadata:
name: myapp
spec:
... 중간 생략 ...
containers:
resources:
limits:
cpu: 5 ## 이렇게 홀수인 정수를 설정한 것이 에러를 발생시킴.
... 중간 생략 ...
관련 자료를 찾아보니, 아래 문서가 가장 설명을 잘 해주고 있다.
위 문서의 요지는 이렇다.
X86_64 CPU는 아래 그림처럼 1개의 물리 Core가 2개의 논리 CPU(Thread)로 구성되어 있고, 이 2개의 논리 CPU(Thread)가 1개의 L2 Cache를 공유하기 때문에 만약 홀수 개로 CPU를 Pinning(즉, Isolation)하면, L2 Cache의 Hit Ratio가 확 떨어지기 때문에 Core의 처리 속도가 겁나게 떨어진다는 것이다.
즉, L2 Cache 1개를 두고 LCore-0과 LCore-1이 치고 박고 시끄럽게 싸우는 꼴~~~ X86_64 CPU 구조에는 늘상 발생하는 현상으로써, "noisy neighbors"라고 표현한다.
쉽게 이해하기 위해 일상 생활과 비유해본다면,
2명의 사람이 한 집에 살면서 요리를 하는데
주방이 1개라서 홍길동은 된장찌개(Job-A)를 만들어 먹고 싶고, 이순신은 김밥(Job-B)을 만들어 먹고 싶다면
홍길동이 된장찌개 요리를 마무리하고 주방(L2 Cache)를 비워줘야, 이순신이 그 주방(L2 Cache)에서 김밥을 만들 수 있는 것과 같다.
여기서 핵심은 "주방(L2 Cache)를 비워줘야" 한다에 있다.
Local Thread가 서로 다른 일을 할 경우, L2 Cache에 담을 내용이 서로 다르기 때문에 L2 Cache 메모리에 있는 데이터를 재사용할 수 없고(즉, Hit Ratio가 떨어지고) 실제 L2 Cache는 Cache 로써의 역할을 못하게 된다.
L2 Cache의 내용 싹~~~ 갈아 엎어버리고 다른 CPU Core가 해야 할 일과 관련된 데이터를 복사해야 하니까~~~
이렇기 때문에 비슷한 Job(프로그램, 또는 Process)에 대해서 L2 Cache를 같이 사용하도록 2개씩 쌍으로 할당하는 것이 최고의 성능을 낼 수 있다.
그럴 일은 없겠지만, 만약 논리 쓰레드 3개가 1개의 L2 Cache를 공유하는 CPU 제품이 있다면 3개씩 쌍으로 할당해야 최고의 성능을 낼 수 있다. (이것은 그냥 가정이다)
내 생각에는 처음부터 Intel x86 CPU가 Hyper Threading 구조가 아니였다면, 즉 Logical Core가 L2 Cache Memory를 공유하지 않는 구조였다면 CPU Pinning 설정할 때 짝수로 설정해야 하는 제약도 없었을 것 같다.
##
## Cluter Network 설정 정보 보기
##
$ kubectl get network.config/cluster -o jsonpath='{.status}{"\n"}'
{"clusterNetwork":[{"cidr":"10.128.0.0/14","hostPrefix":23}],"clusterNetworkMTU":1450,"networkType":"OpenShiftSDN","serviceNetwork":["172.30.0.0/16"]}
##
## CNI Network Type 설정 정보 보기
##
$ oc get network.config/cluster -o jsonpath='{.status.networkType}{"\n"}'
OpenShiftSDN
$
아래 Script는 Kuberentes Node의 IP Address를 얻어와서, 이 IP Address로 Node에 SSH 접속하여 'shutdown' 명령을 수행하는 예제이다.
#!/bin/bash
for ip in $(oc get nodes -o jsonpath='{.items[*].status.addresses[?(@.type=="InternalIP")].address}')
do
echo "reboot node $ip"
ssh -o StrictHostKeyChecking=no core@$ip sudo shutdown -r -t 3
done