SRE: Analisis Prestasi. Kaedah konfigurasi menggunakan pelayan web ringkas dalam Go

Analisis Prestasi dan Penalaan ialah alat yang berkuasa untuk mengesahkan pematuhan prestasi untuk pelanggan.

Analisis prestasi boleh digunakan untuk mengenal pasti kesesakan dalam program, menggunakan pendekatan saintifik untuk mengesahkan eksperimen penalaan. Artikel ini mentakrifkan pendekatan umum untuk analisis dan penalaan prestasi, menggunakan pelayan web Go sebagai contoh.

Go amat sesuai di sini kerana ia mempunyai alat pemprofilan. pprof dalam perpustakaan standard.

SRE: Analisis Prestasi. Kaedah konfigurasi menggunakan pelayan web ringkas dalam Go

strategi

Mari buat senarai ringkasan untuk analisis struktur kami. Kami akan cuba menggunakan beberapa data untuk membuat keputusan dan bukannya membuat perubahan berdasarkan gerak hati atau tekaan. Untuk melakukan ini, kami akan melakukan perkara berikut:

  • Kami mentakrifkan sempadan pengoptimuman (keperluan);
  • Kami mengira beban transaksi untuk sistem;
  • Kami menjalankan ujian (buat data);
  • Kami sedang memerhati;
  • Kami menganalisis - adakah semua keperluan dipenuhi?
  • Kami menetapkannya secara saintifik dan membuat hipotesis;
  • Kami menjalankan eksperimen untuk menguji hipotesis ini.

SRE: Analisis Prestasi. Kaedah konfigurasi menggunakan pelayan web ringkas dalam Go

Seni Bina Pelayan HTTP Mudah

Untuk artikel ini kami akan menggunakan pelayan HTTP kecil di Golang. Semua kod daripada artikel ini boleh didapati di sini.

Aplikasi yang dianalisis ialah pelayan HTTP yang menanyakan PostgreSQL untuk setiap permintaan. Selain itu, Prometheus, node_exporter, dan Grafana digunakan untuk mengumpul dan memaparkan metrik aplikasi dan sistem.

SRE: Analisis Prestasi. Kaedah konfigurasi menggunakan pelayan web ringkas dalam Go

Untuk kesederhanaan, kami menganggap bahawa untuk penskalaan mendatar (dan untuk memudahkan pengiraan), setiap perkhidmatan dan pangkalan data digunakan bersama:

SRE: Analisis Prestasi. Kaedah konfigurasi menggunakan pelayan web ringkas dalam Go

Menentukan matlamat

Dalam langkah ini, kami menentukan matlamat kami. Apa yang kita cuba analisis? Bagaimana kita tahu bila masa untuk berhenti? Dalam artikel ini, kami akan menganggap kami mempunyai pelanggan dan perkhidmatan kami akan memproses 10,000 permintaan sesaat.

В Buku Google SRE Kaedah pemilihan dan pemodelan telah dibincangkan secara terperinci. Mari kita lakukan perkara yang sama dan bina model:

  • Latensi: 99% permintaan harus diselesaikan dalam masa kurang daripada 60ms;
  • Kos: Perkhidmatan harus menggunakan jumlah minimum wang yang kami anggap munasabah mungkin. Untuk mencapai matlamat ini, kami memaksimumkan daya pengeluaran;
  • Perancangan kapasiti: Memahami dan mendokumentasikan bilangan contoh aplikasi yang perlu dijalankan, termasuk fungsi penskalaan keseluruhan, serta bilangan kejadian yang diperlukan untuk memenuhi keperluan beban awal dan peruntukan lebihan n+1.

Kependaman mungkin memerlukan pengoptimuman sebagai tambahan kepada analisis, tetapi daya pengeluaran pastinya perlu dianalisis. Apabila menggunakan proses SRE SLO, keperluan kependaman datang daripada pelanggan dan/atau perniagaan, yang diwakili oleh pemilik produk. Dan perkhidmatan kami akan memenuhi komitmen ini dari awal, tanpa sebarang penyesuaian!

Menyediakan persekitaran ujian

Menggunakan persekitaran ujian, kami boleh menggunakan beban terukur pada sistem kami. Data prestasi perkhidmatan web akan dijana untuk analisis.

Beban transaksi

Persekitaran ini menggunakan seperti tumbuh-tumbuhan untuk membuat kadar permintaan HTTP tersuai sehingga 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

Pemerhatian

Semasa pelaksanaan, beban kerja transaksi akan digunakan. Selain metrik aplikasi (bilangan permintaan, kependaman respons) dan metrik sistem pengendalian (memori, CPU, IOPS), pemprofilan aplikasi akan dijalankan untuk memahami tempat masalah berlaku dan cara masa CPU digunakan.

Pemprofilan

Pemprofilan ialah sejenis ukuran yang membolehkan anda melihat di mana masa CPU dibelanjakan semasa aplikasi sedang berjalan. Ia membolehkan anda menentukan dengan tepat di mana dan berapa banyak masa CPU dibelanjakan:

SRE: Analisis Prestasi. Kaedah konfigurasi menggunakan pelayan web ringkas dalam Go

Data ini boleh digunakan semasa analisis untuk mendapatkan cerapan tentang masa CPU yang terbuang dan kerja yang tidak perlu. Go (pprof) boleh menjana profil dan menggambarkannya sebagai graf nyala menggunakan set alat standard. Saya akan membincangkan penggunaannya dan panduan persediaan kemudian dalam artikel.

Pelaksanaan, pemerhatian, analisis.

Mari kita jalankan percubaan. Kami akan menjalankan, memerhati dan menganalisis sehingga kami berpuas hati dengan prestasi. Kami akan memilih beban rendah sewenang-wenangnya untuk digunakan untuk mendapatkan pemerhatian awal. Pada setiap langkah seterusnya, kami akan meningkatkan beban dengan faktor penskalaan yang dipilih dengan beberapa varians. Setiap ujian beban akan dilakukan dengan bilangan permintaan yang diselaraskan: make load-test LOAD_TEST_RATE=X.

50 permintaan sesaat

SRE: Analisis Prestasi. Kaedah konfigurasi menggunakan pelayan web ringkas dalam Go

Beri perhatian kepada dua graf teratas. Graf kiri atas menunjukkan bahawa aplikasi kami memproses 50 permintaan sesaat (mengikut pengiraannya), dan graf kanan atas menunjukkan tempoh setiap permintaan. Kedua-dua parameter membantu kami memantau dan menganalisis sama ada kami berada dalam had prestasi kami. Garis merah pada graf Latensi Permintaan HTTP menunjukkan SLO 60ms. Garis menunjukkan bahawa kami berada jauh di bawah masa tindak balas maksimum kami.

Mari kita lihat dari segi kos:

10000 permintaan sesaat / 50 permintaan setiap pelayan = 200 pelayan + 1

Kami masih boleh menambah baik angka ini.

500 permintaan sesaat

Perkara yang lebih menarik mula berlaku apabila beban mencapai 500 permintaan sesaat:

SRE: Analisis Prestasi. Kaedah konfigurasi menggunakan pelayan web ringkas dalam Go

Sekali lagi, graf kiri atas menunjukkan bahawa aplikasi sedang mendaftarkan beban biasa. Jika ini tidak berlaku, terdapat masalah dengan pelayan menjalankan aplikasi. Graf kependaman respons, yang terletak di bahagian atas sebelah kanan, menunjukkan bahawa 500 permintaan sesaat menghasilkan kependaman respons 25-40ms. Persentil ke-99 masih selesa dalam 60ms SLO yang dipilih di atas.

Dari segi kos:

10000 permintaan sesaat / 500 permintaan setiap pelayan = 20 pelayan + 1

Masih ada ruang untuk penambahbaikan.

1000 permintaan sesaat

SRE: Analisis Prestasi. Kaedah konfigurasi menggunakan pelayan web ringkas dalam Go

Pelancaran hebat! Apl menunjukkan ia memproses 1000 permintaan sesaat, tetapi had kependaman telah dilanggar oleh SLO. Ini jelas dalam baris p99 dalam graf kanan atas. Walaupun garis p100 jauh lebih tinggi, kependaman sebenar melebihi maksimum 60ms. Mari selami pemprofilan untuk melihat perkara yang sebenarnya dilakukan oleh apl itu.

Pemprofilan

Untuk pemprofilan kami menetapkan beban kepada 1000 permintaan sesaat, kemudian gunakan pprof untuk mengumpul data untuk mengetahui di mana aplikasi menghabiskan masa CPU. Ini boleh dilakukan dengan mengaktifkan titik akhir HTTP. pprof, kemudian simpan hasil di bawah beban menggunakan curl:

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

Hasilnya boleh dipaparkan seperti ini:

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

SRE: Analisis Prestasi. Kaedah konfigurasi menggunakan pelayan web ringkas dalam Go

Graf menunjukkan di mana dan berapa banyak masa CPU yang dibelanjakan oleh apl. Daripada penerangan Brendan Gregg:

Paksi X menunjukkan isian profil tindanan, diisih mengikut abjad (bukan masa). Paksi-Y menunjukkan kedalaman tindanan, mengira dari sifar hingga [atas]. Setiap segi empat tepat mewakili bingkai tindanan. Lebih lebar bingkai, lebih kerap ia muncul dalam tindanan. Bingkai atas dijalankan pada CPU, manakala bingkai bawah adalah elemen kanak-kanak. Warna umumnya tidak mewakili apa-apa, tetapi hanya dipilih secara rawak untuk membezakan bingkai.

Analisis - hipotesis

Untuk penalaan, kami akan menumpukan pada usaha mencari pembaziran masa CPU. Kami akan mencari sumber terbesar perbelanjaan membazir dan membuangnya. Oleh itu, memandangkan pemprofilan mendedahkan dengan tepat di mana aplikasi menghabiskan masa CPUnya, anda mungkin perlu melakukan ini beberapa kali, dan anda juga perlu menukar kod sumber aplikasi, menjalankan semula ujian dan perhatikan bahawa prestasi menghampiri sasaran.

Mengikut cadangan Brendan Gregg, kami akan membaca graf dari atas ke bawah. Setiap baris mewakili bingkai tindanan (panggilan fungsi). Baris pertama ialah titik masuk program, induk kepada semua panggilan lain (dengan kata lain, semua panggilan lain akan mempunyainya dalam timbunan mereka). Baris seterusnya adalah berbeza:

SRE: Analisis Prestasi. Kaedah konfigurasi menggunakan pelayan web ringkas dalam Go

Jika anda menuding pada nama fungsi pada graf, anda akan melihat jumlah masa yang dihabiskan pada timbunan semasa nyahpepijat. Fungsi HTTPServe berada di sana untuk 65% masa, manakala fungsi masa jalan yang lain runtime.mcall, mstart и gc, mengambil masa yang selebihnya. Fakta menarik: 5% daripada jumlah masa dibelanjakan untuk pertanyaan DNS:

SRE: Analisis Prestasi. Kaedah konfigurasi menggunakan pelayan web ringkas dalam Go

Alamat yang dicari oleh program adalah milik Postgresql. klik pada FindByAge:

SRE: Analisis Prestasi. Kaedah konfigurasi menggunakan pelayan web ringkas dalam Go

Menariknya, program ini menunjukkan bahawa terdapat tiga sumber utama kependaman: membuka dan menutup sambungan, permintaan data dan sambungan pangkalan data. Graf menunjukkan bahawa permintaan DNS dan sambungan membuka dan menutup menyumbang kira-kira 13% daripada jumlah masa pelaksanaan.

Hipotesis: Menggunakan semula sambungan dengan kolam harus mengurangkan masa permintaan HTTP tunggal, membolehkan daya pemprosesan yang lebih tinggi dan kependaman yang lebih rendah..

Menyediakan aplikasi - percubaan

Kami sedang mengemas kini kod sumber dan cuba mengalih keluar sambungan PostgreSQL untuk setiap pertanyaan. Pilihan pertama ialah menggunakan kolam sambungan di peringkat permohonan. Dalam eksperimen ini, kami mari kita setelkan penyatuan sambungan menggunakan pemacu sql untuk pergi:

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

if err != nil {
   return nil, err
}

Pelaksanaan, pemerhatian, analisis

Selepas memulakan semula ujian dengan 1000 permintaan sesaat, jelas bahawa kependaman p99 telah kembali normal dengan SLO 60ms!

Berapa kosnya?

10000 permintaan sesaat / 1000 permintaan setiap pelayan = 10 pelayan + 1

Mari jadikan ia lebih baik!

2000 permintaan sesaat

SRE: Analisis Prestasi. Kaedah konfigurasi menggunakan pelayan web ringkas dalam Go

Menggandakan beban menunjukkan perkara yang sama, graf kiri atas menunjukkan bahawa aplikasi berjaya memproses 2000 permintaan sesaat, p100 lebih rendah daripada 60ms, p99 memenuhi SLO.

Dari segi kos:

10000 permintaan sesaat / 2000 permintaan setiap pelayan = 5 pelayan + 1

3000 permintaan sesaat

SRE: Analisis Prestasi. Kaedah konfigurasi menggunakan pelayan web ringkas dalam Go

Di sini, aplikasi boleh memproses 3000 permintaan dengan kependaman p99 kurang daripada 60 ms. SLO tidak dilanggar, dan kos ditetapkan seperti berikut:

10000 permintaan sesaat / 3000 permintaan setiap pelayan = 4 pelayan + 1 (pengarang membulatkan, lebih kurang penterjemah)

Mari cuba satu lagi pusingan analisis.

Analisis - hipotesis

Kami mengumpul dan memaparkan hasil penyahpepijatan aplikasi pada 3000 permintaan sesaat:

SRE: Analisis Prestasi. Kaedah konfigurasi menggunakan pelayan web ringkas dalam Go

6% daripada masa masih digunakan untuk mewujudkan sambungan. Menyediakan kumpulan telah meningkatkan prestasi, tetapi masih jelas bahawa aplikasi itu terus membuat sambungan baharu ke pangkalan data.

Hipotesis: Sambungan, walaupun terdapat kolam, masih digugurkan dan dibersihkan, jadi aplikasi perlu mewujudkannya semula. Menetapkan bilangan sambungan yang belum selesai kepada saiz kolam akan membantu dengan kependaman dengan meminimumkan masa yang diluangkan oleh aplikasi untuk mewujudkan sambungan..

Menyediakan aplikasi - percubaan

Mari cuba pasang MaxIdleConns sama dengan saiz kolam (juga diterangkan di sini):

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

Pelaksanaan, pemerhatian, analisis

3000 permintaan sesaat

SRE: Analisis Prestasi. Kaedah konfigurasi menggunakan pelayan web ringkas dalam Go

p99 kurang daripada 60ms dengan p100 yang jauh lebih rendah!

SRE: Analisis Prestasi. Kaedah konfigurasi menggunakan pelayan web ringkas dalam Go

Semakan graf nyalaan menunjukkan bahawa sambungan tidak lagi kelihatan! Mari kita lihat lebih dekat. pg(*conn).query — kami juga tidak perasan sambungan diwujudkan di sini.

SRE: Analisis Prestasi. Kaedah konfigurasi menggunakan pelayan web ringkas dalam Go

Kesimpulan

Analisis prestasi adalah penting untuk memahami sama ada jangkaan pelanggan dan keperluan bukan fungsi dipenuhi. Membandingkan pemerhatian dengan jangkaan pelanggan boleh membantu menentukan apa yang boleh diterima dan apa yang tidak. Go menyediakan alatan berkuasa terbina dalam pustaka standard yang menjadikan analisis ini mudah dan boleh diakses.

Sumber: www.habr.com