1. Ringkasan
Meskipun developer aplikasi klien dan web frontend biasanya menggunakan alat seperti CPU Profiler Android Studio atau alat pembuatan profil yang disertakan dalam Chrome untuk meningkatkan performa kode mereka, teknik yang setara belum dapat diakses atau diadopsi dengan baik oleh mereka yang bekerja di layanan backend. Cloud Profiler menghadirkan kemampuan yang sama ini kepada developer layanan, terlepas dari apakah kode mereka berjalan di Google Cloud Platform atau di tempat lain.

Alat ini mengumpulkan informasi penggunaan CPU dan alokasi memori dari aplikasi produksi Anda. Cloud Profiler mengatribusikan informasi tersebut ke kode sumber aplikasi, membantu Anda mengidentifikasi bagian aplikasi yang paling banyak menggunakan resource, dan menunjukkan karakteristik performa kode tersebut. Overhead rendah dari teknik pengumpulan yang digunakan oleh alat ini membuatnya cocok untuk penggunaan berkelanjutan di lingkungan produksi.
Dalam codelab ini, Anda akan mempelajari cara menyiapkan Cloud Profiler untuk program Go dan akan memahami jenis insight tentang performa aplikasi yang dapat ditampilkan oleh alat ini.
Yang akan Anda pelajari
- Cara mengonfigurasi program Go untuk pembuatan profil dengan Cloud Profiler.
- Cara mengumpulkan, melihat, dan menganalisis data performa dengan Cloud Profiler.
Yang Anda butuhkan
- Project Google Cloud Platform
- Browser, seperti Chrome atau Firefox
- Pemahaman tentang editor teks Linux standar seperti Vim, EMACs, atau Nano
Bagaimana Anda akan menggunakan tutorial ini?
Bagaimana penilaian Anda terhadap pengalaman menggunakan Google Cloud Platform?
2. Penyiapan dan Persyaratan
Penyiapan lingkungan mandiri
- Login ke Cloud Console lalu buat project baru atau gunakan kembali project yang sudah ada. Jika belum memiliki akun Gmail atau Google Workspace, Anda harus membuatnya.



Ingat project ID, nama unik di semua project Google Cloud (maaf, nama di atas telah digunakan dan tidak akan berfungsi untuk Anda!) Project ID tersebut selanjutnya akan dirujuk di codelab ini sebagai PROJECT_ID.
- Selanjutnya, Anda harus mengaktifkan penagihan di Cloud Console untuk menggunakan resource Google Cloud.
Menjalankan operasi dalam codelab ini seharusnya tidak memerlukan banyak biaya, bahkan mungkin tidak sama sekali. Pastikan untuk mengikuti petunjuk yang ada di bagian "Membersihkan" yang memberi tahu Anda cara menonaktifkan resource sehingga tidak menimbulkan penagihan di luar tutorial ini. Pengguna baru Google Cloud memenuhi syarat untuk mengikuti program Uji Coba Gratis senilai$300 USD.
Google Cloud Shell
Meskipun Google Cloud dapat dioperasikan dari jarak jauh menggunakan laptop Anda, untuk menyederhanakan penyiapan dalam codelab ini, kita akan menggunakan Google Cloud Shell, lingkungan command line yang berjalan di Cloud.
Mengaktifkan Cloud Shell
- Dari Cloud Console, klik Aktifkan Cloud Shell
.

Jika belum pernah memulai Cloud Shell, Anda akan melihat layar perantara (di paruh bawah) yang menjelaskan apa itu Cloud Shell. Jika demikian, klik Continue (dan Anda tidak akan pernah melihatnya lagi). Berikut tampilan layar sekali-tampil tersebut:

Perlu waktu beberapa saat untuk menyediakan dan terhubung ke Cloud Shell.

Virtual machine ini dimuat dengan semua alat pengembangan yang Anda perlukan. Layanan ini menawarkan direktori beranda tetap sebesar 5 GB dan beroperasi di Google Cloud, sehingga sangat meningkatkan performa dan autentikasi jaringan. Sebagian besar pekerjaan Anda dalam codelab ini dapat dilakukan hanya dengan browser atau Chromebook.
Setelah terhubung ke Cloud Shell, Anda akan melihat bahwa Anda sudah diautentikasi dan project sudah ditetapkan ke project ID Anda.
- Jalankan perintah berikut di Cloud Shell untuk mengonfirmasi bahwa Anda telah diautentikasi:
gcloud auth list
Output perintah
Credentialed Accounts
ACTIVE ACCOUNT
* <my_account>@<my_domain.com>
To set the active account, run:
$ gcloud config set account `ACCOUNT`
- Jalankan perintah berikut di Cloud Shell untuk mengonfirmasi bahwa perintah gcloud mengetahui project Anda:
gcloud config list project
Output perintah
[core] project = <PROJECT_ID>
Jika tidak, Anda dapat menyetelnya dengan perintah ini:
gcloud config set project <PROJECT_ID>
Output perintah
Updated property [core/project].
3. Buka Cloud Profiler
Di Konsol Cloud, buka UI Profiler dengan mengklik "Profiler" di menu navigasi sebelah kiri:

Atau, Anda dapat menggunakan kotak penelusuran Konsol Cloud untuk membuka UI Profiler: cukup ketik "Cloud Profiler" dan pilih item yang ditemukan. Anda akan melihat UI Profiler dengan pesan "Tidak ada data untuk ditampilkan" seperti di bawah. Project ini baru, sehingga belum mengumpulkan data pembuatan profil.

Sekarang saatnya memprofilkan sesuatu.
4. Membuat Profil Tolok Ukur
Kita akan menggunakan aplikasi Go sintetis sederhana yang tersedia di GitHub. Di terminal Cloud Shell yang masih Anda buka (dan saat pesan "Tidak ada data untuk ditampilkan" masih ditampilkan di UI Profiler), jalankan perintah berikut:
$ go get -u github.com/GoogleCloudPlatform/golang-samples/profiler/...
Kemudian, beralih ke direktori aplikasi:
$ cd ~/gopath/src/github.com/GoogleCloudPlatform/golang-samples/profiler/hotapp
Direktori ini berisi file "main.go", yang merupakan aplikasi sintetis dengan agen pembuatan profil yang diaktifkan:
main.go
...
import (
...
"cloud.google.com/go/profiler"
)
...
func main() {
err := profiler.Start(profiler.Config{
Service: "hotapp-service",
DebugLogging: true,
MutexProfiling: true,
})
if err != nil {
log.Fatalf("failed to start the profiler: %v", err)
}
...
}
Agen pembuatan profil mengumpulkan profil CPU, heap, dan thread secara default. Kode di sini memungkinkan pengumpulan profil mutex (juga dikenal sebagai "persaingan").
Sekarang, jalankan program:
$ go run main.go
Saat program berjalan, agen pembuatan profil akan mengumpulkan profil dari lima jenis yang dikonfigurasi secara berkala. Pengumpulan data diacak dari waktu ke waktu (dengan kecepatan rata-rata satu profil per menit untuk setiap jenis), sehingga mungkin diperlukan waktu hingga tiga menit untuk mengumpulkan setiap jenis. Program akan memberi tahu Anda saat membuat profil. Pesan diaktifkan oleh tanda DebugLogging dalam konfigurasi di atas; jika tidak, agen akan berjalan tanpa pemberitahuan:
$ go run main.go 2018/03/28 15:10:24 profiler has started 2018/03/28 15:10:57 successfully created profile THREADS 2018/03/28 15:10:57 start uploading profile 2018/03/28 15:11:19 successfully created profile CONTENTION 2018/03/28 15:11:30 start uploading profile 2018/03/28 15:11:40 successfully created profile CPU 2018/03/28 15:11:51 start uploading profile 2018/03/28 15:11:53 successfully created profile CONTENTION 2018/03/28 15:12:03 start uploading profile 2018/03/28 15:12:04 successfully created profile HEAP 2018/03/28 15:12:04 start uploading profile 2018/03/28 15:12:04 successfully created profile THREADS 2018/03/28 15:12:04 start uploading profile 2018/03/28 15:12:25 successfully created profile HEAP 2018/03/28 15:12:25 start uploading profile 2018/03/28 15:12:37 successfully created profile CPU ...
UI akan diperbarui sendiri segera setelah profil pertama dikumpulkan. Setelah itu, Profiler tidak akan otomatis diperbarui, jadi untuk melihat data baru, Anda harus memperbarui UI Profiler secara manual. Untuk melakukannya, klik tombol Sekarang di pemilih interval waktu dua kali:

Setelah UI dimuat ulang, Anda akan melihat tampilan seperti ini:

Pemilih jenis profil menampilkan lima jenis profil yang tersedia:

Sekarang, mari kita tinjau setiap jenis profil dan beberapa kemampuan UI penting, lalu lakukan beberapa eksperimen. Pada tahap ini, Anda tidak lagi memerlukan terminal Cloud Shell, sehingga Anda dapat keluar dengan menekan CTRL-C dan mengetik "exit".
5. Menganalisis Data Profiler
Setelah mengumpulkan beberapa data, mari kita lihat lebih dekat. Kami menggunakan aplikasi sintetis (sumbernya tersedia di Github) yang menyimulasikan perilaku yang biasanya terjadi pada berbagai jenis masalah performa dalam produksi.
Kode yang Memerlukan Banyak CPU
Pilih jenis profil CPU. Setelah UI memuatnya, Anda akan melihat empat blok daun untuk fungsi load dalam grafik flame, yang secara kolektif mencakup semua penggunaan CPU:

Fungsi ini ditulis secara khusus untuk menggunakan banyak siklus CPU dengan menjalankan loop yang ketat:
main.go
func load() {
for i := 0; i < (1 << 20); i++ {
}
}
Fungsi ini dipanggil secara tidak langsung dari busyloop() melalui empat jalur panggilan: busyloop → {foo1, foo2} → {bar, baz} → load. Lebar kotak fungsi menunjukkan biaya relatif jalur panggilan tertentu. Dalam hal ini, keempat jalur memiliki biaya yang hampir sama. Dalam program yang sebenarnya, Anda harus berfokus pada pengoptimalan jalur panggilan yang paling penting dalam hal performa. Grafik flame, yang secara visual menekankan jalur yang lebih mahal dengan kotak yang lebih besar, memudahkan identifikasi jalur ini.
Anda dapat menggunakan filter data profil untuk menyaring tampilan lebih lanjut. Misalnya, coba tambahkan filter "Tampilkan stack" yang menentukan "baz" sebagai string filter. Anda akan melihat sesuatu seperti screenshot di bawah, di mana hanya dua dari empat jalur panggilan ke load() yang ditampilkan. Kedua jalur ini adalah satu-satunya jalur yang melewati fungsi dengan string "baz" di namanya. Pemfilteran ini berguna jika Anda ingin berfokus pada subbagian dari program yang lebih besar (misalnya, karena Anda hanya memiliki sebagian program tersebut).

Kode yang Membutuhkan Banyak Memori
Sekarang beralihlah ke jenis profil "Heap". Pastikan untuk menghapus semua filter yang Anda buat dalam eksperimen sebelumnya. Sekarang Anda akan melihat grafik flame dengan allocImpl, yang dipanggil oleh alloc, ditampilkan sebagai konsumen memori utama di aplikasi:

Tabel ringkasan di atas grafik flame menunjukkan bahwa jumlah total memori yang digunakan dalam aplikasi rata-rata ~57,4 MiB, sebagian besar dialokasikan oleh fungsi allocImpl. Hal ini tidak mengejutkan, mengingat penerapan fungsi ini:
main.go
func allocImpl() {
// Allocate 64 MiB in 64 KiB chunks
for i := 0; i < 64*16; i++ {
mem = append(mem, make([]byte, 64*1024))
}
}
Fungsi ini dijalankan sekali, mengalokasikan 64 MiB dalam potongan yang lebih kecil, lalu menyimpan pointer ke potongan tersebut dalam variabel global untuk melindunginya dari pengumpulan sampah. Perhatikan bahwa jumlah memori yang ditampilkan sebagai yang digunakan oleh profiler sedikit berbeda dari 64 MiB: profiler heap Go adalah alat statistik, sehingga pengukuran memiliki overhead rendah, tetapi tidak akurat per byte. Jangan heran jika melihat perbedaan sekitar 10% seperti ini.
Kode yang Intensif IO
Jika Anda memilih "Threads" di pemilih jenis profil, tampilan akan beralih ke grafik flame yang sebagian besar lebarnya digunakan oleh fungsi wait dan waitImpl:

Dalam ringkasan di atas grafik flame, Anda dapat melihat bahwa ada 100 goroutine yang memperbesar stack panggilannya dari fungsi wait. Ini sudah benar, mengingat kode yang memulai penantian ini terlihat seperti ini:
main.go
func main() {
...
// Simulate some waiting goroutines.
for i := 0; i < 100; i++ {
go wait()
}
Jenis profil ini berguna untuk memahami apakah program menghabiskan waktu yang tidak terduga dalam menunggu (seperti I/O). Stack panggilan tersebut biasanya tidak diambil sampelnya oleh profiler CPU, karena tidak menggunakan sebagian besar waktu CPU. Anda sering kali ingin menggunakan filter "Sembunyikan stack" dengan profil Thread - misalnya, untuk menyembunyikan semua stack yang diakhiri dengan panggilan ke gopark, karena sering kali merupakan goroutine tidak aktif dan kurang menarik daripada yang menunggu I/O.
Jenis profil thread juga dapat membantu mengidentifikasi titik dalam program tempat thread menunggu mutex yang dimiliki oleh bagian lain dari program dalam jangka waktu yang lama, tetapi jenis profil berikut lebih berguna untuk hal tersebut.
Kode dengan Persaingan Tinggi
Jenis profil Persaingan mengidentifikasi kunci yang paling "diinginkan" dalam program. Jenis profil ini tersedia untuk program Go, tetapi harus diaktifkan secara eksplisit dengan menentukan "MutexProfiling: true" dalam kode konfigurasi agen. Pengumpulan data ini berfungsi dengan mencatat (di bawah metrik "Contentions") jumlah waktu saat kunci tertentu, saat dibuka oleh goroutine A, membuat goroutine B lain menunggu kunci dibuka. Kode ini juga mencatat (di bawah metrik "Penundaan") waktu tunggu goroutine yang diblokir untuk mendapatkan kunci. Dalam contoh ini, ada satu stack pertentangan dan total waktu tunggu untuk kunci adalah 10,5 detik:

Kode yang menghasilkan profil ini terdiri dari 4 goroutine yang bersaing untuk mendapatkan mutex:
main.go
func contention(d time.Duration) {
contentionImpl(d)
}
func contentionImpl(d time.Duration) {
for {
mu.Lock()
time.Sleep(d)
mu.Unlock()
}
}
...
func main() {
...
for i := 0; i < 4; i++ {
go contention(time.Duration(i) * 50 * time.Millisecond)
}
}
6. Ringkasan
Dalam lab ini, Anda telah mempelajari cara mengonfigurasi program Go untuk digunakan dengan Cloud Profiler. Anda juga mempelajari cara mengumpulkan, melihat, dan menganalisis data performa dengan alat ini. Sekarang Anda dapat menerapkan keterampilan baru Anda ke layanan sebenarnya yang Anda jalankan di Google Cloud Platform.
7. Selamat!
Anda telah mempelajari cara mengonfigurasi dan menggunakan Cloud Profiler.
Pelajari Lebih Lanjut
- Cloud Profiler: https://cloud.google.com/profiler/
- Paket pprof/runtime Go yang digunakan Cloud Profiler: https://golang.org/pkg/runtime/pprof/
Lisensi
Karya ini dilisensikan berdasarkan Lisensi Umum Creative Commons Attribution 2.0.