Kami baru-baru ini mengalihkan lingkungan produksi kami ke Kubernetes. Saya ingin menegakkan batas CPU pada wadah. Saya mendapatkan metrik CPU yang saling bertentangan yang tidak cocok bersama. Inilah pengaturan saya:
- Agen DataDog berjalan sebagai
Daemonset
- Aplikasi yang ada berjalan tanpa Batas CPU
- Kontainer yang dimaksud adalah aplikasi Ruby multi-threaded
- Dua metrik:
kubernetes.cpu.usage.{avg,max}
dandocker.cpu.usage
c4.xlarge
node cluster (4 vCPUs atau 4000m dalam istilah Kubernetes)
kubernetes.cpu.usage.max
melaporkan ~ 600m untuk kontainer yang dimaksud. docker.cpu.usage
laporan ~ 60%. Maka batas CPU 1000m akan lebih dari cukup kapasitas dalam operasi normal.
Saya menetapkan batas ke 1000m. Kemudian docker.container.throttles
naik secara signifikan sementara kubernetes.cpu.usage.max
dan docker.cpu.usage
tetap sama. Sistem semua jatuh ke lututnya selama ini. Ini tidak masuk akal bagi saya.
Saya meneliti statistik Docker. Tampaknya docker stats
(dan API yang mendasarinya) menormalkan beban menurut inti CPU. Jadi dalam kasus saya, docker.cpu.usage
60% (4000m * 0,60) hingga 2400m dalam istilah Kubernetes. Namun ini tidak berkorelasi dengan angka Kubernetes apa pun. Saya melakukan percobaan lain untuk menguji hipotesis saya bahwa angka Kubernetes salah. Saya menetapkan batas ke 2600m (untuk beberapa ruang kepala tambahan). Ini tidak menghasilkan throttle. Namun Kubernetes mengamati penggunaan CPU tidak berubah. Ini membuat saya bingung.
Jadi pertanyaan saya adalah:
- Apakah ini terasa seperti bug di Kubernetes (atau sesuatu di stack?)
- Apakah pemahaman saya benar?
Pertanyaan tindak lanjut saya berkaitan dengan cara menentukan dengan benar CPU untuk aplikasi Ruby. Satu wadah menggunakan Puma. Ini adalah server web multi-utas dengan jumlah utas yang dapat dikonfigurasi. Permintaan HTTP ditangani oleh salah satu utas. Aplikasi kedua adalah server hemat menggunakan server berulir. Setiap koneksi TCP yang masuk ditangani oleh utasnya sendiri. Utas keluar saat koneksi ditutup. Ruby sebagai GIL (Global Interpreter Lock) sehingga hanya satu utas yang dapat mengeksekusi kode Ruby sekaligus. Itu memungkinkan beberapa thread menjalankan IO dan hal-hal seperti itu.
Saya pikir pendekatan terbaik adalah membatasi jumlah utas yang berjalan di setiap aplikasi dan mendekati batas CPU Kubernet berdasarkan jumlah utas. Prosesnya tidak forking sehingga total penggunaan CPU lebih sulit diprediksi.
Pertanyaannya di sini adalah: bagaimana cara memprediksi penggunaan dan batasan CPU dengan benar untuk aplikasi ini?