Artikel ini menjelaskan bagaimana tim pengembangan menggunakan metrik untuk menemukan penyempitan dan meningkatkan performa sistem terdistribusi. Artikel ini didasarkan pada pengujian beban aktual yang dilakukan untuk aplikasi sampel. Aplikasi ini berasal dari Garis Besar Azure Kubernetes Service (AKS) untuk layanan mikro, bersama dengan proyek uji beban Visual Studio yang digunakan untuk menghasilkan hasilnya.
Artikel ini adalah bagian dari seri. Baca bagian pertama di sini.
Skenario: Panggil beberapa layanan backend untuk mengambil informasi lalu mengagregasi hasilnya.
Skenario ini melibatkan aplikasi pengiriman drone. Klien dapat meminta REST API untuk mendapatkan informasi faktur terbaru mereka. Faktur mencakup ringkasan pengiriman, paket, dan total pemanfaatan drone pelanggan. Aplikasi ini menggunakan arsitektur layanan mikro yang berjalan di AKS, dan informasi yang diperlukan untuk faktur tersebar di beberapa layanan mikro.
Daripada klien memanggil setiap layanan secara langsung, aplikasi menerapkan pola Agregasi Gateway . Dengan menggunakan pola ini, klien membuat satu permintaan ke layanan gateway. Gateway pada gilirannya memanggil layanan backend secara paralel, lalu menggabungkan hasilnya menjadi satu payload respons.
Uji 1: Performa garis besar
Untuk membangun garis besar, tim pengembangan dimulai dengan pengujian beban langkah, meningkatkan beban dari satu pengguna yang disimulasikan hingga 40 pengguna, selama total durasi 8 menit. Bagan berikut, yang diambil dari Visual Studio, memperlihatkan hasilnya. Garis ungu menunjukkan beban pengguna, dan garis oranye menunjukkan throughput (permintaan rata-rata per detik).
Garis merah di sepanjang bagian bawah bagan menunjukkan bahwa tidak ada kesalahan yang dikembalikan ke klien, yang menggembirakan. Namun, throughput rata-rata memuncak sekitar setengah jalan melalui pengujian, dan kemudian turun untuk sisanya, bahkan saat beban terus meningkat. Itu menunjukkan back end tidak dapat mengikuti. Pola yang terlihat di sini adalah umum ketika sistem mulai mencapai batas sumber daya - setelah mencapai maksimum, throughput benar-benar turun secara signifikan. Ketidakcocokan sumber daya, kesalahan sementara, atau peningkatan tingkat pengecualian semuanya dapat berkontribusi pada pola ini.
Mari kita gali data pemantauan untuk mempelajari apa yang terjadi di dalam sistem. Bagan berikutnya diambil dari Application Insights. Ini menunjukkan durasi rata-rata panggilan HTTP dari gateway ke layanan backend.
Bagan ini menunjukkan bahwa satu operasi khususnya, GetDroneUtilization
, membutuhkan waktu rata-rata jauh lebih lama — berdasarkan urutan besarnya. Gateway melakukan panggilan ini secara paralel, sehingga operasi paling lambat menentukan berapa lama waktu yang diperlukan untuk menyelesaikan seluruh permintaan.
Jelas langkah berikutnya adalah menggali GetDroneUtilization
operasi dan mencari hambatan apa pun. Salah satu kemungkinan adalah kelelahan sumber daya. Mungkin layanan backend khusus ini kehabisan CPU atau memori. Untuk kluster AKS, informasi ini tersedia di portal Azure melalui fitur wawasan kontainer Azure Monitor. Grafik berikut menunjukkan pemanfaatan sumber daya di tingkat kluster:
Dalam cuplikan layar ini, nilai rata-rata dan maksimum ditampilkan. Penting untuk melihat lebih dari sekadar rata-rata, karena rata-rata dapat menyembunyikan lonjakan dalam data. Di sini, rata-rata pemanfaatan CPU tetap di bawah 50%, tetapi ada beberapa lonjakan hingga 80%. Itu mendekati kapasitas tetapi masih dalam toleransi. Sesuatu yang lain menyebabkan penyempitan.
Bagan berikutnya mengungkapkan pelaku sebenarnya. Bagan ini menunjukkan kode respons HTTP dari database backend layanan Pengiriman, yang dalam hal ini adalah Azure Cosmos DB. Garis biru mewakili kode keberhasilan (HTTP 2xx), sementara garis hijau mewakili kesalahan HTTP 429. Kode pengembalian HTTP 429 berarti bahwa Azure Cosmos DB untuk sementara membatasi permintaan, karena pemanggil mengonsumsi lebih banyak unit sumber daya (RU) daripada yang disediakan.
Untuk mendapatkan wawasan lebih lanjut, tim pengembangan menggunakan Application Insights untuk melihat telemetri end-to-end untuk sampel permintaan yang representatif. Berikut adalah satu instans:
Tampilan ini menunjukkan panggilan yang terkait dengan satu permintaan klien, bersama dengan informasi waktu dan kode respons. Panggilan tingkat atas berasal dari gateway ke layanan backend. Panggilan ke GetDroneUtilization
diperluas untuk menampilkan panggilan ke dependensi eksternal — dalam hal ini, ke Azure Cosmos DB. Panggilan berwarna merah mengembalikan kesalahan HTTP 429.
Perhatikan kesenjangan besar antara kesalahan HTTP 429 dan panggilan berikutnya. Ketika pustaka klien Azure Cosmos DB menerima kesalahan HTTP 429, pustaka klien secara otomatis mundur dan menunggu untuk mencoba kembali operasi. Apa yang ditunjukkan oleh tampilan ini adalah bahwa selama 672 md operasi ini berlangsung, sebagian besar waktu tersebut dihabiskan untuk menunggu untuk mencoba kembali Azure Cosmos DB.
Berikut grafik lain yang menarik untuk analisis ini. Ini menunjukkan konsumsi RU per partisi fisik versus RU yang disediakan per partisi fisik:
Untuk memahami grafik ini, Anda perlu memahami bagaimana Azure Cosmos DB mengelola partisi. Koleksi di Azure Cosmos DB dapat memiliki kunci partisi. Setiap nilai kunci yang mungkin mendefinisikan partisi logis data dalam koleksi. Azure Cosmos DB mendistribusikan partisi logis ini di satu atau beberapa partisi fisik . Manajemen partisi fisik ditangani secara otomatis oleh Azure Cosmos DB. Saat Anda menyimpan lebih banyak data, Azure Cosmos DB mungkin memindahkan partisi logis ke partisi fisik baru, untuk menyebarkan beban di seluruh partisi fisik.
Untuk pengujian beban ini, koleksi Azure Cosmos DB disediakan dengan 900 RU. Bagan menunjukkan 100 RU per partisi fisik, yang menyiratkan total sembilan partisi fisik. Meskipun Azure Cosmos DB secara otomatis menangani pemecahan partisi fisik, mengetahui jumlah partisi dapat memberikan wawasan tentang performa. Tim pengembangan akan menggunakan informasi ini nanti, karena mereka terus mengoptimalkan. Di mana garis biru melintasi garis horizontal ungu, konsumsi RU telah melebihi RU yang disediakan. Itulah titik di mana Azure Cosmos DB akan mulai membatasi panggilan.
Pengujian 2: Meningkatkan unit sumber daya
Untuk pengujian beban kedua, tim meluaskan skala koleksi Azure Cosmos DB dari 900 RU ke 2500 RU. Throughput meningkat dari 19 permintaan/detik menjadi 23 permintaan/detik, dan latensi rata-rata turun dari 669 ms menjadi 569 ms.
Metrik | Tes 1 | Tes 2 |
---|---|---|
Throughput (req/detik) | 19 | 23 |
Latensi rata-rata (ms) | 669 | 569 |
Permintaan berhasil | 9,8 K | 11 K |
Ini bukan keuntungan besar, tetapi melihat grafik dari waktu ke waktu menunjukkan gambar yang lebih lengkap:
Sedangkan tes sebelumnya menunjukkan lonjakan awal diikuti dengan penurunan tajam, pengujian ini menunjukkan throughput yang lebih konsisten. Namun, throughput maksimum tidak jauh lebih tinggi.
Semua permintaan ke Azure Cosmos DB mengembalikan status 2xx, dan kesalahan HTTP 429 hilang:
Grafik konsumsi RU versus RU yang disediakan menunjukkan ada banyak ruang utama. Ada sekitar 275 RU per partisi fisik, dan uji beban memuncak pada sekitar 100 RU yang dikonsumsi per detik.
Metrik menarik lainnya adalah jumlah panggilan ke Azure Cosmos DB per operasi yang berhasil:
Metrik | Tes 1 | Tes 2 |
---|---|---|
Panggilan per operasi | 11 | 9 |
Dengan asumsi tidak ada kesalahan, jumlah panggilan harus cocok dengan rencana kueri aktual. Dalam hal ini, operasi melibatkan kueri lintas partisi yang mencapai kesembilan partisi fisik. Nilai yang lebih tinggi dalam uji beban pertama mencerminkan jumlah panggilan yang mengembalikan kesalahan 429.
Metrik ini dihitung dengan menjalankan kueri Analitik Log kustom:
let start=datetime("2020-06-18T20:59:00.000Z");
let end=datetime("2020-07-24T21:10:00.000Z");
let operationNameToEval="GET DroneDeliveries/GetDroneUtilization";
let dependencyType="Azure DocumentDB";
let dataset=requests
| where timestamp > start and timestamp < end
| where success == true
| where name == operationNameToEval;
dataset
| project reqOk=itemCount
| summarize
SuccessRequests=sum(reqOk),
TotalNumberOfDepCalls=(toscalar(dependencies
| where timestamp > start and timestamp < end
| where type == dependencyType
| summarize sum(itemCount)))
| project
OperationName=operationNameToEval,
DependencyName=dependencyType,
SuccessRequests,
AverageNumberOfDepCallsPerOperation=(TotalNumberOfDepCalls/SuccessRequests)
Untuk meringkas, pengujian beban kedua menunjukkan peningkatan. Namun, GetDroneUtilization
operasi ini masih membutuhkan waktu sekitar urutan besarnya lebih lama dari operasi paling lambat berikutnya. Melihat transaksi end-to-end membantu menjelaskan alasannya:
Seperti disebutkan sebelumnya, GetDroneUtilization
operasi ini melibatkan kueri lintas partisi ke Azure Cosmos DB. Ini berarti klien Azure Cosmos DB harus mengolah kueri ke setiap partisi fisik dan mengumpulkan hasilnya. Seperti yang ditunjukkan oleh tampilan transaksi end-to-end, kueri ini sedang dilakukan secara serial. Operasi ini memakan waktu selama jumlah semua kueri - dan masalah ini hanya akan menjadi lebih buruk karena ukuran data tumbuh dan lebih banyak partisi fisik ditambahkan.
Uji 3: Kueri paralel
Berdasarkan hasil sebelumnya, cara yang jelas untuk mengurangi latensi adalah dengan mengeluarkan kueri secara paralel. SDK klien Azure Cosmos DB memiliki pengaturan yang mengontrol tingkat paralelisme maksimum.
Nilai | Deskripsi |
---|---|
0 | Tidak ada paralelisme (default) |
> 0 | Jumlah maksimum panggilan paralel |
-1 | SDK klien memilih tingkat paralelisme yang optimal |
Untuk pengujian beban ketiga, pengaturan ini diubah dari 0 menjadi -1. Tabel berikut ini meringkas hasilnya:
Metrik | Tes 1 | Tes 2 | Uji 3 |
---|---|---|---|
Throughput (req/detik) | 19 | 23 | 42 |
Latensi rata-rata (ms) | 669 | 569 | 215 |
Permintaan berhasil | 9,8 K | 11 K | 20 K |
Permintaan dibatasi | 2,72 K | 0 | 0 |
Dari grafik uji beban, tidak hanya throughput keseluruhan yang jauh lebih tinggi (garis oranye), tetapi throughput juga mengimbangi beban (garis ungu).
Kita dapat memverifikasi bahwa klien Azure Cosmos DB membuat kueri secara paralel dengan melihat tampilan transaksi end-to-end:
Menariknya, efek samping dari peningkatan throughput adalah bahwa jumlah RU yang dikonsumsi per detik juga meningkat. Meskipun Azure Cosmos DB tidak membatasi permintaan apa pun selama pengujian ini, konsumsinya mendekati batas RU yang disediakan:
Grafik ini mungkin merupakan sinyal untuk meluaskan skala database lebih lanjut. Namun, ternyata kita dapat mengoptimalkan kueri sebagai gantinya.
Langkah 4: Optimalkan kueri
Pengujian beban sebelumnya menunjukkan performa yang lebih baik dalam hal latensi dan throughput. Latensi permintaan rata-rata berkurang 68% dan throughput meningkat 220%. Namun, kueri lintas partisi menjadi perhatian.
Masalah dengan kueri lintas partisi adalah Anda membayar RU di setiap partisi. Jika kueri hanya dijalankan sesekali — katakanlah, satu jam sekali — itu mungkin tidak masalah. Tetapi setiap kali Anda melihat beban kerja baca-berat yang melibatkan kueri lintas partisi, Anda akan melihat apakah kueri dapat dioptimalkan dengan menyertakan kunci partisi. (Anda mungkin perlu mendesain ulang koleksi untuk menggunakan kunci partisi yang berbeda.)
Berikut adalah kueri untuk skenario khusus ini:
SELECT * FROM c
WHERE c.ownerId = <ownerIdValue> and
c.year = <yearValue> and
c.month = <monthValue>
Kueri ini memilih rekaman yang cocok dengan ID pemilik dan bulan/tahun tertentu. Dalam desain asli, tidak ada properti ini yang merupakan kunci partisi. Itu mengharuskan klien untuk mengolah kueri ke setiap partisi fisik dan mengumpulkan hasilnya. Untuk meningkatkan performa kueri, tim pengembangan mengubah desain sehingga ID pemilik adalah kunci partisi untuk koleksi. Dengan begitu, kueri dapat menargetkan partisi fisik tertentu. (Azure Cosmos DB menangani ini secara otomatis; Anda tidak perlu mengelola pemetaan antara nilai kunci partisi dan partisi fisik.)
Setelah mengalihkan koleksi ke kunci partisi baru, ada peningkatan dramatis dalam konsumsi RU, yang diterjemahkan langsung ke biaya yang lebih rendah.
Metrik | Tes 1 | Tes 2 | Uji 3 | Uji 4 |
---|---|---|---|---|
RU per operasi | 29 | 29 | 29 | 3.4 |
Panggilan per operasi | 11 | 9 | 10 | 1 |
Tampilan transaksi end-to-end menunjukkan bahwa seperti yang diprediksi, kueri hanya membaca satu partisi fisik:
Uji beban menunjukkan peningkatan throughput dan latensi:
Metrik | Tes 1 | Tes 2 | Uji 3 | Uji 4 |
---|---|---|---|---|
Throughput (req/detik) | 19 | 23 | 42 | 59 |
Latensi rata-rata (ms) | 669 | 569 | 215 | 176 |
Permintaan berhasil | 9,8 K | 11 K | 20 K | 29 K |
Permintaan dibatasi | 2,72 K | 0 | 0 | 0 |
Konsekuensi dari peningkatan performa adalah bahwa pemanfaatan CPU simpul menjadi sangat tinggi:
Menjeda akhir uji beban, CPU rata-rata mencapai sekitar 90%, dan CPU maksimum mencapai 100%. Metrik ini menunjukkan bahwa CPU adalah hambatan berikutnya dalam sistem. Jika throughput yang lebih tinggi diperlukan, langkah berikutnya mungkin menskalakan layanan Pengiriman ke lebih banyak instans.
Ringkasan
Untuk skenario ini, penyempitan berikut diidentifikasi:
- Permintaan pembatasan Azure Cosmos DB karena RU tidak mencukupkan yang disediakan.
- Latensi tinggi disebabkan oleh kueri beberapa partisi database secara serial.
- Kueri lintas partisi yang tidak efisien, karena kueri tidak menyertakan kunci partisi.
Selain itu, pemanfaatan CPU diidentifikasi sebagai penyempitan potensial pada skala yang lebih tinggi. Untuk mendiagnosis masalah ini, tim pengembangan melihat:
- Latensi dan throughput dari uji beban.
- Kesalahan Azure Cosmos DB dan konsumsi RU.
- Tampilan transaksi end-to-end di Application Insight.
- Pemanfaatan CPU dan memori dalam wawasan kontainer Azure Monitor.
Langkah berikutnya
Ulas antipola performa