Ketika beberapa aplikasi berjalan pada node yang sama, konflik sumber daya CPU dan seringnya context switching dapat menyebabkan jitter kinerja pada aplikasi sensitif. Penjadwalan yang sadar topologi CPU mengikat proses aplikasi secara eksklusif ke core CPU tertentu (CPU pinning), sehingga mengurangi ketidakpastian kinerja akibat perpindahan core dan akses memori lintas node NUMA.
Cara kerja
Secara default, Kubernetes mengandalkan Completely Fair Scheduler (CFS) kernel untuk menyeimbangkan beban CPU. Penjadwal ini mendistribusikan beban ke seluruh core dengan mengalokasikan time slice CPU secara adil. Namun, pendekatan ini dapat menyebabkan jitter kinerja pada aplikasi sensitif karena mengabaikan topologi fisik CPU.
CPU Manager Kubernetes (dengan kebijakan static) dapat mengikat Pod ke core CPU eksklusif, tetapi memiliki keterbatasan berikut:
Kurangnya kesadaran penjadwal: kube-scheduler native hanya membuat keputusan di tingkat node dan tidak memahami topologi CPU seluruh kluster, sehingga tidak mampu menemukan tata letak core fisik optimal untuk suatu Pod secara global.
Kurangnya kesadaran topologi: Saat mengalokasikan core pada suatu node, kebijakan
statictidak mempertimbangkan arsitektur NUMA, yang dapat menyebabkan akses memori lintas node NUMA dan menimbulkan latensi tambahan.Kurangnya fleksibilitas: Kebijakan ini mensyaratkan kelas QoS Pod adalah
<a href="https://kubernetes.io/docs/concepts/workloads/pods/pod-qos/#guaranteed" id="5b2a90624cgtc">Guaranteed</a>, sehingga tidak dapat diterapkan pada Pod<a href="https://kubernetes.io/docs/concepts/workloads/pods/pod-qos/#burstable" id="174c05a5978cf">Burstable</a>atau<a href="https://kubernetes.io/docs/concepts/workloads/pods/pod-qos/#burstable" id="6cada2573fokq">BestEffort</a>.
Untuk mengatasi keterbatasan tersebut, ACK menyediakan penjadwalan yang sadar topologi CPU yang ditingkatkan berdasarkan Scheduling Framework baru. Fitur ini dicapai melalui kolaborasi antara kube-scheduler ACK dan ack-koordinator.
Pelaporan topologi node: Komponen ack-koordinator mendeteksi topologi CPU fisik lokal—seperti socket, node NUMA, dan cache—secara real-time, lalu melaporkan informasi tersebut ke pusat penjadwalan.
Penjadwalan yang sadar topologi global: kube-scheduler menggunakan informasi topologi global untuk memilih node optimal bagi suatu Pod dari seluruh kluster serta merancang skema alokasi core. Sebagai contoh, saat memilih node optimal, penjadwal secara default mencari core dengan jumlah aplikasi terikat paling sedikit. Skema alokasi ini kemudian ditulis ke anotasi Pod sebagai bagian dari hasil penjadwalan.
Pinning core lokal: Setelah Pod dijadwalkan ke node target, ack-koordinator membaca anotasi Pod dan memodifikasi file
cpuset.cpusdalam Cgroup Pod yang sesuai untuk mengikat Pod ke core fisik.
Skenario
Aplikasi sensitif terhadap kinerja: Aplikasi yang sangat sensitif terhadap latensi context switching CPU, seperti perdagangan frekuensi tinggi dan pemrosesan data real-time.
Aplikasi sensitif terhadap NUMA: Aplikasi yang ditempatkan pada server multi-core dan multi-socket, seperti Elastic Bare Metal Instances (Intel dan AMD). Kinerjanya sangat dipengaruhi oleh latensi akses memori dan perlu menghindari akses memori lintas node NUMA.
Kebutuhan daya komputasi deterministik: Aplikasi yang memerlukan daya komputasi stabil dan dapat diprediksi, seperti tugas komputasi ilmiah dan analitik data besar.
Adaptasi aplikasi lama: Aplikasi yang belum diadaptasi untuk lingkungan cloud-native. Misalnya, suatu aplikasi mungkin menetapkan jumlah thread berdasarkan jumlah core fisik seluruh mesin, bukan spesifikasi kontainer, sehingga menyebabkan kinerja buruk.
Jangan aktifkan fitur ini dalam skenario berikut:
Lingkungan overcommitment CPU: Sifat eksklusif resource dari core pinning tidak kompatibel dengan model berbagi sumber daya overcommitment. Hal ini dapat menyebabkan pemborosan resource dan mengganggu logika penjadwalan overcommitment.
Aplikasi tujuan umum atau intensif-I/O: Sebagian besar aplikasi, seperti layanan web dan middleware, tidak sensitif terhadap perpindahan core CPU dan tidak memerlukan fitur ini.
Persiapan
Anda memiliki kluster ACK yang dikelola edisi Pro. Kebijakan CPU (
cpuManagerPolicy) untuk kelompok node diatur kenone. Untuk informasi lebih lanjut tentang cara mengatur nilaicpuManagerPolicy, lihat Sesuaikan konfigurasi kubelet untuk kelompok node.ack-koordinator telah diinstal, dan versi komponennya 0.2.0 atau lebih baru.
Langkah 1: Terapkan aplikasi contoh
Dokumen ini menggunakan aplikasi Nginx sebagai contoh untuk menunjukkan cara mengaktifkan penjadwalan yang sadar topologi CPU dan mencapai CPU pinning.
Buat file
nginx-app.yaml.Terapkan aplikasi.
kubectl apply -f nginx-app.yamlLogin ke node tempat Pod berada untuk mendapatkan UID Pod dan ID kontainer.
Dapatkan nama Pod.
Jalankan perintahkubectl get pods -n <your-namespace>untuk melihat nama Pod, misalnyanginx-deployment-6f5899*****.Dapatkan UID Pod.
# Ganti <your-pod-name> dengan nama Pod sebenarnya kubectl get pod <your-pod-name> -n default -o jsonpath='{.metadata.uid}{"\n"}'Output yang diharapkan:
uid: a78a02b5-c87f-4e74-9ddd-254c163*****Dapatkan ID kontainer.
# Ganti <your-pod-name> dengan nama Pod sebenarnya kubectl describe pod <your-pod-name> -n defaultDalam output, temukan bidang
Containers, cariContainer ID, lalu hapus awalan seperticontainerd://.Output yang diharapkan:
Containers: nginx: Container ID: containerd://b8b88a70096aabb0aea197dd2aba78d15bcbe9145198ef46a0474b31*****
Periksa versi cgroup node.
stat -fc %T /sys/fs/cgroup/Jika output-nya
cgroup_root, sistem menggunakan cgroup v1.Jika output-nya
cgroup2fs, sistem menggunakan cgroup v2.
Jalankan perintah verifikasi yang sesuai berdasarkan versi cgroup untuk memeriksa status CPU pinning.
Dalam path cgroup, ganti tanda hubung (
-) pada UID Pod dengan garis bawah (_). Misalnya, jika UID Pod aslinya adalaha78a02b5-c87f-4e74-9ddd-254c163*****, format yang digunakan dalam path adalaha78a02b5_c87f_4e74_9ddd_254c163*****.cgroup v1:
# Ganti <POD_UID> dan <CONTAINER_ID> dengan nilai sebenarnya cat /sys/fs/cgroup/cpuset/kubepods.slice/kubepods-pod<POD_UID>.slice/cri-containerd-<CONTAINER_ID>.scope/cpuset.cpuscgroup v2:
# Ganti <POD_UID> dan <CONTAINER_ID> dengan nilai sebenarnya cat /sys/fs/cgroup/kubepods.slice/kubepods-pod<POD_UID>.slice/cri-containerd-<CONTAINER_ID>.scope/cpuset.cpus.effective
Output yang diharapkan berupa rentang, yang berarti kontainer dapat menggunakan semua core pada node dan belum dipasangkan (not pinned).
0-31
Langkah 2: Aktifkan penjadwalan yang sadar topologi CPU
Anda dapat mengaktifkan penjadwalan yang sadar topologi CPU dengan menambahkan anotasi ke Pod.
Kebijakan pinning umum: Kebijakan umum yang mengikuti prinsip pinning 1:1. Kebijakan ini mengikat jumlah core yang ditentukan oleh
resources.limits.cpuke Pod dan memprioritaskan core CPU dalam satu node NUMA yang sama untuk memastikan kinerja akses memori optimal.Kebijakan pinning otomatis: Kebijakan yang dioptimalkan untuk perangkat keras tertentu. Kebijakan ini memprioritaskan pengikatan kluster core fisik lengkap (seperti CCX/CCD pada CPU AMD) untuk memaksimalkan lokalitas CPU dan meningkatkan konkurensi. Disarankan untuk jenis mesin AMD berskala besar tertentu (32 core atau lebih).
Saat mengaktifkan penjadwalan yang sadar topologi CPU, jangan langsung menentukan nodeName pada Pod. kube-scheduler tidak berpartisipasi dalam proses penjadwalan untuk Pod semacam itu. Gunakan bidang seperti nodeSelector untuk mengonfigurasi kebijakan afinitas guna menentukan node untuk penjadwalan.
Kebijakan pinning umum
Konfigurasi:
Tambahkan anotasi
cpuset-scheduler: "true"dalam file YAML.Untuk Pod: Tambahkan anotasi ke bidang
metadata.annotations.Untuk workload (seperti deployment): Tambahkan anotasi ke bidang
spec.template.metadata.annotations.
Dalam bidang
Containers, konfigurasikan nilairesources.limits.cpu(harus berupa bilangan bulat) untuk menentukan cakupan pinning CPU.
Contoh konfigurasi:
apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment namespace: default labels: app: nginx spec: replicas: 1 selector: matchLabels: app: nginx template: metadata: annotations: # Atur ke true untuk mengaktifkan penjadwalan yang sadar topologi CPU cpuset-scheduler: "true" labels: app: nginx spec: containers: - name: nginx image: alibaba-cloud-linux-3-registry.cn-hangzhou.cr.aliyuncs.com/alinux3/nginx_optimized:20240221-1.20.1-2.3.0 ports: - containerPort: 80 command: - "sleep" - "infinity" resources: requests: cpu: 4 memory: 8Gi limits: # Setel nilai CPU. Harus berupa bilangan bulat cpu: 4 memory: 8GiVerifikasi:
Anda dapat memeriksanya dengan dua cara.
Periksa file Cgroup node
Setelah Pod berjalan, login kembali ke nodenya dan periksa status CPU pinning.
Ganti tanda hubung (
-) pada UID Pod dengan garis bawah (_).cgroup v1:
# Ganti <POD_UID> dan <CONTAINER_ID> dengan nilai sebenarnya cat /sys/fs/cgroup/cpuset/kubepods.slice/kubepods-pod<POD_UID>.slice/cri-containerd-<CONTAINER_ID>.scope/cpuset.cpuscgroup v2:
# Ganti <POD_UID> dan <CONTAINER_ID> dengan nilai sebenarnya cat /sys/fs/cgroup/kubepods.slice/kubepods-pod<POD_UID>.slice/cri-containerd-<CONTAINER_ID>.scope/cpuset.cpus.effective
Output yang diharapkan berupa kumpulan ID core yang sesuai dengan pengaturan
limits.cpu: 4. Hal ini menunjukkan bahwa pinning berhasil.0-3Periksa anotasi Pod
Setelah Pod dijadwalkan ke node target, ack-koordinator membaca anotasi Pod dan memodifikasi file
cpuset.cpusdalam Cgroup Pod yang sesuai untuk mengikat Pod ke core fisik.Periksa informasi
cpusetPod.# Ganti <your-pod-name> dengan nama Pod sebenarnya kubectl get pod <your-pod-name> -n default -o yaml | grep "cpuset:"Output yang diharapkan:
cpuset: '{"nginx":{"0":{"elems":{"0":{},"1":{},"2":{},"3":{}}}}}'Output:
"nginx":{...}: Berisi konfigurasi untuk kontainer bernamanginx."0":{...}: Kunci terluar"0"merepresentasikan ID node Non-Uniform Memory Access (NUMA). Dalam contoh ini, semua core yang terikat berada pada NUMA Node 0 yang sama. Konfigurasi ini mencegah degradasi kinerja akibat akses memori lintas-NUMA."elems":{"0":{},"1":{},"2":{},"3":{}}: Kunci-kunci tersebut merepresentasikan ID core CPU fisik tempat kontainer dipasangkan. Dalam contoh ini, kontainer dipasangkan ke core 0, 1, 2, dan 3, yang sesuai dengan pengaturanlimits.cpu: 4.
Kebijakan pinning otomatis
Konfigurasi:
Tambahkan dua anotasi:
cpuset-scheduler: "true"dancpu-policy: "static-burst".Untuk Pod: Tambahkan anotasi ke bidang
metadata.annotations.Untuk workload (seperti deployment): Tambahkan anotasi ke bidang
spec.template.metadata.annotations.
Dalam bidang
Containers, konfigurasikan nilairesources.limits.cpu(harus berupa bilangan bulat) untuk menentukan cakupan pinning CPU.
Contoh konfigurasi:
apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment namespace: default labels: app: nginx spec: replicas: 1 selector: matchLabels: app: nginx template: metadata: annotations: # Atur ke true untuk mengaktifkan penjadwalan yang sadar topologi CPU cpuset-scheduler: "true" # Atur ke static-burst untuk mengaktifkan pinning otomatis dan kebijakan afinitas NUMA cpu-policy: "static-burst" labels: app: nginx spec: containers: - name: nginx image: alibaba-cloud-linux-3-registry.cn-hangzhou.cr.aliyuncs.com/alinux3/nginx_optimized:20240221-1.20.1-2.3.0 ports: - containerPort: 80 command: - "sleep" - "infinity" resources: requests: cpu: 4 memory: 8Gi limits: # Setel nilai CPU. Harus berupa bilangan bulat cpu: 4 memory: 8GiVerifikasi:
Kebijakan pinning otomatis menganalisis topologi CPU dan penggunaan resource node secara real-time. Jumlah core yang dipasangkan mungkin lebih besar daripada jumlah core yang secara eksplisit Anda minta untuk Pod. Anda dapat memverifikasi status pinning dengan dua cara berikut.
Periksa file Cgroup node
Setelah Pod berjalan, login kembali ke nodenya dan periksa status CPU pinning.
Ganti tanda hubung (
-) pada UID Pod dengan garis bawah (_).cgroup v1:
# Ganti <POD_UID> dan <CONTAINER_ID> dengan nilai sebenarnya cat /sys/fs/cgroup/cpuset/kubepods.slice/kubepods-pod<POD_UID>.slice/cri-containerd-<CONTAINER_ID>.scope/cpuset.cpuscgroup v2:
# Ganti <POD_UID> dan <CONTAINER_ID> dengan nilai sebenarnya cat /sys/fs/cgroup/kubepods.slice/kubepods-pod<POD_UID>.slice/cri-containerd-<CONTAINER_ID>.scope/cpuset.cpus.effective
Output yang diharapkan berupa kumpulan ID core spesifik. Hal ini menunjukkan bahwa pinning berhasil.
0-7Periksa anotasi Pod
Setelah Pod dijadwalkan ke node target, ack-koordinator membaca anotasi Pod dan memodifikasi file
cpuset.cpusdalam Cgroup Pod yang sesuai untuk mengikat Pod ke core fisik.Periksa informasi
cpusetPod.# Ganti <your-pod-name> dengan nama Pod sebenarnya kubectl get pod <your-pod-name> -n default -o yaml | grep "cpuset:"Output yang diharapkan:
cpuset: '{"nginx":{"0":{"elems":{"0":{},"1":{},"2":{},"3":{},"4":{},"5":{},"6":{},"7":{}}}}}'Penjelasan output:
"nginx":{...}: Konfigurasi untuk kontainer bernamanginx."0":{...}: Kunci terluar"0"merepresentasikan ID node NUMA. Dalam contoh ini, semua core yang terikat berada pada NUMA Node 0 yang sama. Hal ini menghindari kehilangan kinerja akibat akses memori lintas node NUMA."elems":{"0":{},"1":{},"2":{},"3":{},"4":{},"5":{},"6":{},"7":{}}: Kunci-kunci tersebut merepresentasikan ID core CPU fisik yang dipasangkan. Dalam contoh ini, kontainer dipasangkan ke core 0 hingga 7.
Operasi terkait
Nonaktifkan penjadwalan yang sadar topologi CPU (lepaskan pinning core CPU)
Edit file YAML aplikasi. Hapus anotasi
cpuset-scheduler: "true"dancpu-policy: "static-burst"(jika ada) dari bidangspec.template.metadata.annotations.Terapkan file YAML yang telah dimodifikasi selama jam sepi. Perubahan akan berlaku setelah Pod direstart.
Setelah Anda melepaskan pinning core CPU, proses Pod tidak lagi terikat ke core fisik tertentu dan dapat berpindah di antara semua core CPU yang tersedia pada node. Hal ini dapat berdampak sebagai berikut:
Penggunaan CPU mungkin sedikit meningkat akibat context switching lintas core.
Untuk aplikasi komputasi-intensif, jitter kinerja akibat konflik resource CPU dapat muncul kembali karena core tidak lagi eksklusif.
Ketika proses beberapa Pod berbeban tinggi dijadwalkan ke core yang sama, hal ini dapat menyebabkan lonjakan beban tiba-tiba pada core tersebut, yang mungkin memicu pembatasan kecepatan CPU kontainer.
Rekomendasi untuk lingkungan produksi
Observabilitas: Sebelum dan sesudah mengaktifkan pinning core, integrasikan dengan Layanan Terkelola untuk Prometheus Alibaba Cloud. Pantau secara ketat metrik kinerja aplikasi utama (seperti waktu respons (RT) dan QPS) serta metrik node seperti penggunaan CPU dan pembatasan kecepatan CPU untuk mengamati perubahan kinerja akibat pinning core.
Penerapan bertahap: Untuk aplikasi dengan beberapa replika, gunakan rilis canary atau pembaruan bertahap untuk secara bertahap mengaktifkan atau menonaktifkan kebijakan pinning. Hal ini membantu mengendalikan risiko yang terkait dengan perubahan tersebut.
Penagihan
Komponen ack-koordinator gratis untuk diinstal dan digunakan. Namun, biaya tambahan mungkin timbul dalam skenario berikut:
ack-koordinator merupakan komponen yang dikelola sendiri dan mengonsumsi resource node pekerja setelah instalasi. Anda dapat mengonfigurasi permintaan resource untuk setiap modul saat menginstal komponen.
Secara default, ack-koordinator mengekspos metrik pemantauan untuk fitur seperti profiling resource dan penjadwalan detail halus dalam format Prometheus. Jika Anda memilih opsi Enable Prometheus Monitoring for ACK-Koordinator saat mengonfigurasi komponen dan menggunakan layanan Prometheus Alibaba Cloud, metrik ini dianggap sebagai metrik kustom dan dikenai biaya. Biaya tersebut bergantung pada faktor seperti ukuran kluster dan jumlah aplikasi. Sebelum mengaktifkan fitur ini, bacalah dengan cermat dokumentasi Penagihan instans Prometheus untuk Prometheus Alibaba Cloud guna memahami kuota gratis dan kebijakan penagihan untuk metrik kustom. Anda dapat memantau dan mengelola penggunaan resource dengan menanyakan data penggunaan.
Referensi
ACK mendukung penjadwalan yang sadar topologi GPU, yang dapat memilih kombinasi GPU optimal pada suatu node untuk kecepatan pelatihan terbaik.
Anda dapat mengukur resource yang dialokasikan namun tidak digunakan dalam suatu kluster dan menyediakannya untuk job prioritas rendah. Hal ini mencapai overcommitment resource dinamis.