SRE: Analisis Kinerja. Metode konfigurasi menggunakan server web sederhana di Go

Analisis dan penyesuaian kinerja adalah alat yang ampuh untuk memverifikasi kepatuhan kinerja bagi klien.

Analisis kinerja dapat digunakan untuk memeriksa kemacetan dalam suatu program dengan menerapkan pendekatan ilmiah untuk menguji eksperimen penyetelan. Artikel ini menjelaskan pendekatan umum terhadap analisis dan penyesuaian kinerja, menggunakan server web Go sebagai contoh.

Go sangat bagus di sini karena memiliki alat pembuatan profil pprof di perpustakaan standar.

SRE: Analisis Kinerja. Metode konfigurasi menggunakan server web sederhana di Go

strategi

Mari kita buat daftar ringkasan untuk analisis struktural kita. Kami akan mencoba menggunakan beberapa data untuk mengambil keputusan daripada membuat perubahan berdasarkan intuisi atau dugaan. Untuk melakukan ini kita akan melakukan ini:

  • Kami menentukan batas optimasi (persyaratan);
  • Kami menghitung beban transaksi untuk sistem;
  • Kami melakukan pengujian (membuat data);
  • Kami mengamati;
  • Kami menganalisis - apakah semua persyaratan terpenuhi?
  • Kami menyusunnya secara ilmiah, membuat hipotesis;
  • Kami melakukan percobaan untuk menguji hipotesis ini.

SRE: Analisis Kinerja. Metode konfigurasi menggunakan server web sederhana di Go

Arsitektur Server HTTP Sederhana

Untuk artikel ini kita akan menggunakan server HTTP kecil di Golang. Semua kode dari artikel ini dapat ditemukan di sini.

Aplikasi yang dianalisis adalah server HTTP yang melakukan polling Postgresql untuk setiap permintaan. Selain itu, ada Prometheus, node_exporter dan Grafana untuk mengumpulkan dan menampilkan metrik aplikasi dan sistem.

SRE: Analisis Kinerja. Metode konfigurasi menggunakan server web sederhana di Go

Untuk menyederhanakan, kami menganggap bahwa untuk penskalaan horizontal (dan menyederhanakan penghitungan) setiap layanan dan database disebarkan bersama:

SRE: Analisis Kinerja. Metode konfigurasi menggunakan server web sederhana di Go

Mendefinisikan tujuan

Pada langkah ini, kami memutuskan tujuannya. Apa yang ingin kita analisis? Bagaimana kita tahu kapan waktunya untuk mengakhiri? Pada artikel ini, kita akan membayangkan bahwa kita memiliki klien dan layanan kita akan memproses 10 permintaan per detik.

Π’ Buku SRE Google Metode seleksi dan pemodelan dibahas secara rinci. Mari lakukan hal yang sama dan buat model:

  • Latensi: 99% permintaan harus diselesaikan dalam waktu kurang dari 60 md;
  • Biaya: Layanan harus menggunakan jumlah uang minimum yang menurut kami memungkinkan. Untuk melakukan hal ini, kami memaksimalkan throughput;
  • Perencanaan kapasitas: Memerlukan pemahaman dan dokumentasi berapa banyak instance aplikasi yang perlu dijalankan, termasuk fungsionalitas penskalaan secara keseluruhan, dan berapa banyak instance yang diperlukan untuk memenuhi persyaratan pemuatan dan penyediaan awal redundansi n+1.

Latensi mungkin memerlukan optimasi selain analisis, namun throughput jelas perlu dianalisis. Saat menggunakan proses SRE SLO, permintaan penundaan datang dari pelanggan atau bisnis yang diwakili oleh pemilik produk. Dan layanan kami akan memenuhi kewajiban ini sejak awal tanpa pengaturan apa pun!

Menyiapkan lingkungan pengujian

Dengan bantuan lingkungan pengujian, kami akan dapat menempatkan beban terukur pada sistem kami. Untuk analisis, data kinerja layanan web akan dihasilkan.

Beban transaksi

Lingkungan ini menggunakan hidup seperti tumbuh-tumbuhan untuk membuat tingkat permintaan HTTP khusus hingga dihentikan:

$ make load-test LOAD_TEST_RATE=50
echo "POST http://localhost:8080" | vegeta attack -body tests/fixtures/age_no_match.json -rate=50 -duration=0 | tee results.bin | vegeta report

Pengamatan

Beban transaksional akan diterapkan saat runtime. Selain metrik aplikasi (jumlah permintaan, latensi respons) dan sistem operasi (memori, CPU, IOPS), pembuatan profil aplikasi akan dijalankan untuk memahami di mana masalahnya dan bagaimana waktu CPU digunakan.

Profil

Pembuatan profil adalah jenis pengukuran yang memungkinkan Anda melihat ke mana perginya waktu CPU saat aplikasi sedang berjalan. Ini memungkinkan Anda menentukan dengan tepat di mana dan berapa banyak waktu prosesor yang dihabiskan:

SRE: Analisis Kinerja. Metode konfigurasi menggunakan server web sederhana di Go

Data ini dapat digunakan selama analisis untuk mendapatkan wawasan tentang waktu CPU yang terbuang dan pekerjaan yang tidak perlu dilakukan. Go (pprof) dapat membuat profil dan memvisualisasikannya sebagai grafik api menggunakan seperangkat alat standar. Saya akan membicarakan panduan penggunaan dan pengaturannya nanti di artikel.

Eksekusi, observasi, analisis.

Mari kita melakukan percobaan. Kami akan melakukan, mengamati, dan menganalisis hingga kami puas dengan kinerjanya. Mari kita pilih nilai beban rendah secara sembarang untuk diterapkan guna memperoleh hasil pengamatan pertama. Pada setiap langkah selanjutnya kami akan menambah beban dengan faktor skala tertentu, dipilih dengan beberapa variasi. Setiap pengujian beban yang dijalankan dilakukan dengan jumlah permintaan yang disesuaikan: make load-test LOAD_TEST_RATE=X.

50 permintaan per detik

SRE: Analisis Kinerja. Metode konfigurasi menggunakan server web sederhana di Go

Perhatikan dua grafik teratas. Kiri atas menunjukkan bahwa aplikasi kita memproses 50 permintaan per detik (menurutnya) dan kanan atas menunjukkan durasi setiap permintaan. Kedua parameter tersebut membantu kami melihat dan menganalisis apakah kami berada dalam batas kinerja kami atau tidak. Garis merah pada grafik Latensi Permintaan HTTP menunjukkan SLO pada 60ms. Garis tersebut menunjukkan bahwa waktu respons kami jauh di bawah maksimum.

Mari kita lihat dari sisi biaya:

10000 permintaan per detik / 50 permintaan per server = 200 server + 1

Angka ini masih bisa kita tingkatkan.

500 permintaan per detik

Hal-hal menarik lainnya mulai terjadi ketika beban mencapai 500 permintaan per detik:

SRE: Analisis Kinerja. Metode konfigurasi menggunakan server web sederhana di Go

Sekali lagi, di grafik kiri atas Anda dapat melihat bahwa aplikasi mencatat beban normal. Jika tidak, berarti ada masalah pada server tempat aplikasi dijalankan. Grafik latensi respons terletak di kanan atas, menunjukkan bahwa 500 permintaan per detik menghasilkan penundaan respons sebesar 25-40 md. Persentil ke-99 masih cocok dengan SLO 60 md yang dipilih di atas.

Dari segi biaya:

10000 permintaan per detik / 500 permintaan per server = 20 server + 1

Semuanya masih bisa ditingkatkan.

1000 permintaan per detik

SRE: Analisis Kinerja. Metode konfigurasi menggunakan server web sederhana di Go

Peluncuran yang bagus! Aplikasi menunjukkan bahwa ia memproses 1000 permintaan per detik, namun batas latensi dilanggar oleh SLO. Hal ini terlihat pada baris p99 pada grafik kanan atas. Meskipun garis p100 jauh lebih tinggi, penundaan sebenarnya lebih tinggi dari batas maksimum 60 ms. Mari selami pembuatan profil untuk mencari tahu apa yang sebenarnya dilakukan aplikasi tersebut.

Profil

Untuk pembuatan profil, kami mengatur beban menjadi 1000 permintaan per detik, lalu menggunakannya pprof untuk menangkap data untuk mengetahui di mana aplikasi menghabiskan waktu CPU. Hal ini dapat dilakukan dengan mengaktifkan titik akhir HTTP pprof, lalu, saat dimuat, simpan hasilnya menggunakan curl:

$ curl http://localhost:8080/debug/pprof/profile?seconds=29 > cpu.1000_reqs_sec_no_optimizations.prof

Hasilnya dapat ditampilkan seperti ini:

$ go tool pprof -http=:12345 cpu.1000_reqs_sec_no_optimizations.prof

SRE: Analisis Kinerja. Metode konfigurasi menggunakan server web sederhana di Go

Grafik menunjukkan di mana dan berapa banyak aplikasi menghabiskan waktu CPU. Dari uraian dari Brendan Gregg:

Sumbu X adalah populasi profil tumpukan, diurutkan berdasarkan abjad (ini bukan waktu), sumbu Y menunjukkan kedalaman tumpukan, dihitung dari nol di [atas]. Setiap persegi panjang adalah bingkai tumpukan. Semakin lebar bingkainya, semakin sering ia berada di tumpukan. Yang di atas berjalan di CPU, dan yang di bawah adalah elemen turunannya. Warna biasanya tidak berarti apa-apa, tetapi dipilih secara acak untuk membedakan bingkai.

Analisis - hipotesis

Untuk penyetelan, kami akan fokus mencoba menemukan waktu CPU yang terbuang. Kami akan mencari sumber terbesar dari pengeluaran tidak berguna dan menghapusnya. Mengingat bahwa pembuatan profil mengungkapkan dengan sangat akurat di mana tepatnya aplikasi menghabiskan waktu prosesornya, Anda mungkin harus melakukannya beberapa kali, dan Anda juga perlu mengubah kode sumber aplikasi, menjalankan kembali pengujian, dan melihat apakah kinerja mendekati target.

Mengikuti rekomendasi Brendan Gregg, kita akan membaca grafik dari atas ke bawah. Setiap baris menampilkan bingkai tumpukan (panggilan fungsi). Baris pertama adalah titik masuk ke dalam program, induk dari semua panggilan lainnya (dengan kata lain, semua panggilan lain akan memilikinya di tumpukannya). Baris selanjutnya sudah berbeda:

SRE: Analisis Kinerja. Metode konfigurasi menggunakan server web sederhana di Go

Jika Anda mengarahkan kursor ke nama fungsi pada grafik, total waktu fungsi tersebut berada di tumpukan selama debugging akan ditampilkan. Fungsi HTTPServe ada di sana 65% sepanjang waktu, fungsi runtime lainnya runtime.mcall, mstart ΠΈ gc, menyita sisa waktunya. Fakta menarik: 5% dari total waktu dihabiskan untuk kueri DNS:

SRE: Analisis Kinerja. Metode konfigurasi menggunakan server web sederhana di Go

Alamat yang dicari program adalah milik Postgresql. Klik FindByAge:

SRE: Analisis Kinerja. Metode konfigurasi menggunakan server web sederhana di Go

Menariknya, program ini menunjukkan bahwa, pada prinsipnya, ada tiga sumber utama yang menambah penundaan: membuka dan menutup koneksi, meminta data, dan menghubungkan ke database. Grafik menunjukkan bahwa permintaan DNS, pembukaan dan penutupan koneksi memakan waktu sekitar 13% dari total waktu eksekusi.

Hipotesa: Menggunakan kembali koneksi menggunakan pooling akan mengurangi waktu satu permintaan HTTP, memungkinkan throughput yang lebih tinggi dan latensi yang lebih rendah.

Menyiapkan aplikasi - percobaan

Kami memperbarui kode sumber, coba hapus koneksi ke Postgresql untuk setiap permintaan. Opsi pertama adalah menggunakan kumpulan koneksi pada tingkat aplikasi. Dalam percobaan ini kami mari kita atur pengumpulan koneksi menggunakan driver sql untuk go:

db, err := sql.Open("postgres", dbConnectionString)
db.SetMaxOpenConns(8)

if err != nil {
   return nil, err
}

Eksekusi, observasi, analisis

Setelah memulai kembali pengujian dengan 1000 permintaan per detik, terlihat jelas bahwa tingkat latensi p99 telah kembali normal dengan SLO 60ms!

Berapa biayanya?

10000 permintaan per detik / 1000 permintaan per server = 10 server + 1

Ayo lakukan dengan lebih baik lagi!

2000 permintaan per detik

SRE: Analisis Kinerja. Metode konfigurasi menggunakan server web sederhana di Go

Menggandakan beban menunjukkan hal yang sama, grafik kiri atas menunjukkan bahwa aplikasi berhasil memproses 2000 permintaan per detik, p100 lebih rendah dari 60ms, p99 memenuhi SLO.

Dari segi biaya:

10000 permintaan per detik / 2000 permintaan per server = 5 server + 1

3000 permintaan per detik

SRE: Analisis Kinerja. Metode konfigurasi menggunakan server web sederhana di Go

Di sini aplikasi dapat memproses 3000 permintaan dengan latensi p99 kurang dari 60ms. SLO tidak dilanggar, dan biayanya diterima sebagai berikut:

10000 permintaan per detik / per 3000 permintaan per server = 4 server + 1 (penulis telah mengumpulkan, kira-kira Penerjemah)

Mari kita coba analisis lainnya.

Analisis - hipotesis

Kami mengumpulkan dan menampilkan hasil debugging aplikasi pada 3000 permintaan per detik:

SRE: Analisis Kinerja. Metode konfigurasi menggunakan server web sederhana di Go

Masih 6% waktunya dihabiskan untuk membangun koneksi. Menyiapkan kumpulan telah meningkatkan kinerja, namun Anda masih dapat melihat bahwa aplikasi terus berupaya membuat koneksi baru ke database.

Hipotesa: Koneksi, meskipun terdapat pool, masih terputus dan dibersihkan, sehingga aplikasi perlu mengatur ulangnya. Menyetel jumlah koneksi yang tertunda ke ukuran kumpulan akan membantu latensi dengan meminimalkan waktu yang dihabiskan aplikasi untuk membuat koneksi.

Menyiapkan aplikasi - percobaan

Mencoba menginstal MaxIdleConns sama dengan ukuran kolam (juga dijelaskan di sini):

db, err := sql.Open("postgres", dbConnectionString)
db.SetMaxOpenConns(8)
db.SetMaxIdleConns(8)
if err != nil {
   return nil, err
}

Eksekusi, observasi, analisis

3000 permintaan per detik

SRE: Analisis Kinerja. Metode konfigurasi menggunakan server web sederhana di Go

p99 kurang dari 60ms dengan p100 jauh lebih sedikit!

SRE: Analisis Kinerja. Metode konfigurasi menggunakan server web sederhana di Go

Memeriksa grafik nyala api menunjukkan bahwa sambungan tidak lagi terlihat! Mari kita periksa lebih detail pg(*conn).query β€” kami juga tidak menyadari adanya koneksi di sini.

SRE: Analisis Kinerja. Metode konfigurasi menggunakan server web sederhana di Go

Kesimpulan

Analisis kinerja sangat penting untuk memahami bahwa harapan pelanggan dan persyaratan non-fungsional terpenuhi. Analisis dengan membandingkan observasi dengan ekspektasi pelanggan dapat membantu menentukan mana yang dapat diterima dan mana yang tidak. Go menyediakan alat canggih yang dibangun ke dalam perpustakaan standar yang membuat analisis menjadi sederhana dan mudah diakses.

Sumber: www.habr.com

Tambah komentar