1. Genel Bakış
İstemci uygulaması ve ön uç web geliştiricileri, kodlarının performansını artırmak için genellikle Android Studio CPU Profiler veya Chrome'da bulunan profil çıkarma araçları gibi araçları kullanır. Ancak eşdeğer teknikler, arka uç hizmetlerinde çalışanlar tarafından o kadar kolay erişilebilir ve benimsenmemiş olanlardır. Cloud Profiler, kodlarının Google Cloud Platform'da veya başka bir yerde çalıştırılmasından bağımsız olarak bu özellikleri hizmet geliştiricilere sunar.
Bu araç, üretim uygulamalarınızdan CPU kullanımı ve bellek ayırma bilgilerini toplar. Bu bilgileri uygulamanın kaynak koduyla ilişkilendirir, bu sayede uygulamanın en çok kaynağı tüketen kısımlarını belirlemenize yardımcı olur ve kodun performans özelliklerini aydınlatır. Aracın kullandığı toplama tekniklerinin düşük ek yükü, aracı üretim ortamlarında sürekli kullanıma uygun hale getirir.
Bu codelab'de, aracın sunabileceği uygulama performansı hakkında bilgi edinecek ve Go programı için Cloud Profiler'ı nasıl ayarlayacağınızı öğreneceksiniz.
Neler öğreneceksiniz?
- Cloud Profiler ile profil oluşturmak için Go programı yapılandırma.
- Cloud Profiler ile performans verilerini toplama, görüntüleme ve analiz etme.
Gerekenler
- Bir Google Cloud Platform projesi
- Chrome veya Firefox gibi bir tarayıcı
- Vim, EMAC veya Nano gibi standart Linux metin düzenleyicileri hakkında bilgi
Bu eğiticiden nasıl yararlanacaksınız?
Google Cloud Platform deneyiminizi nasıl değerlendirirsiniz?
2. Kurulum ve Gereksinimler
Kendi hızınızda ortam kurulumu
- Cloud Console'da oturum açıp yeni bir proje oluşturun veya mevcut bir projeyi yeniden kullanın. Gmail veya Google Workspace hesabınız yoksa hesap oluşturmanız gerekir.
Tüm Google Cloud projelerinde benzersiz bir ad olan proje kimliğini unutmayın (yukarıdaki ad zaten alınmış ve size uygun olmayacaktır!). Bu kod laboratuvarın ilerleyen bölümlerinde PROJECT_ID
olarak adlandırılacaktır.
- Sonraki adımda, Google Cloud kaynaklarını kullanmak için Cloud Console'da faturalandırmayı etkinleştirmeniz gerekir.
Bu codelab'i çalıştırmanın maliyeti, yüksek değildir. "Temizleme" bölümündeki talimatları izlediğinizden emin olun. bölümünde, bu eğiticinin dışında faturalandırmayla karşılaşmamanız için kaynakları nasıl kapatacağınız konusunda tavsiyelerde bulunuyoruz. Yeni Google Cloud kullanıcıları, 300 ABD doları değerindeki ücretsiz denemeden yararlanabilir.
Google Cloud Shell
Google Cloud, dizüstü bilgisayarınızdan uzaktan çalıştırılabilse de bu codelab'de kurulumu kolaylaştırmak için Cloud'da çalışan bir komut satırı ortamı olan Google Cloud Shell'i kullanacağız.
Cloud Shell'i etkinleştirme
- Cloud Console'da, Cloud Shell'i etkinleştir simgesini tıklayın.
Cloud Shell'i daha önce hiç başlatmadıysanız ne olduğunu açıklayan bir ara ekran (ekranın alt kısmında) gösterilir. Bu durumda Devam'ı tıklayın (bunu bir daha görmezsiniz). Tek seferlik ekran şöyle görünür:
Temel hazırlık ve Cloud Shell'e bağlanmak yalnızca birkaç dakika sürer.
Bu sanal makinede, ihtiyacınız olan tüm geliştirme araçları yüklüdür. 5 GB boyutunda kalıcı bir ana dizin sunar ve Google Cloud'da çalışarak ağ performansını ve kimlik doğrulamasını büyük ölçüde iyileştirir. Bu codelab'deki çalışmalarınızın tamamı olmasa bile büyük bir kısmı yalnızca bir tarayıcı veya Chromebook'unuzla yapılabilir.
Cloud Shell'e bağlandıktan sonra kimliğinizin doğrulandığını ve projenin proje kimliğinize ayarlandığını görürsünüz.
- Kimlik doğrulamanızın tamamlandığını onaylamak için Cloud Shell'de aşağıdaki komutu çalıştırın:
gcloud auth list
Komut çıkışı
Credentialed Accounts ACTIVE ACCOUNT * <my_account>@<my_domain.com> To set the active account, run: $ gcloud config set account `ACCOUNT`
- gcloud komutunun projenizi bildiğini onaylamak için Cloud Shell'de aşağıdaki komutu çalıştırın:
gcloud config list project
Komut çıkışı
[core] project = <PROJECT_ID>
Doğru değilse aşağıdaki komutla ayarlayabilirsiniz:
gcloud config set project <PROJECT_ID>
Komut çıkışı
Updated property [core/project].
3. Cloud Profiler'a gidin
Cloud Console'da "Profiler"i tıklayarak Profiler kullanıcı arayüzüne gidin. tıklayın:
Alternatif olarak Profiler kullanıcı arayüzüne gitmek için Cloud Console arama çubuğunu kullanabilirsiniz: "Cloud Profiler" yazmanız yeterlidir tıklayın ve bulunan öğeyi seçin. Her iki durumda da, Profil Aracı kullanıcı arayüzünde "Görüntülenecek veri yok" ifadesini görürsünüz. aşağıdaki gibi bir mesaj görürsünüz. Proje yeni olduğundan henüz hiç profil çıkarma verisi toplanmadı.
Artık profilinizi oluşturabilirsiniz.
4. Karşılaştırmanın profilini çıkarın
GitHub'da bulunan basit bir sentetik Go uygulaması kullanacağız. Hâlâ açık olduğunuz Cloud Shell terminalinde (Profil Aracı kullanıcı arayüzünde "Görüntülenecek veri yok" mesajı hâlâ gösteriliyorsa) aşağıdaki komutu çalıştırın:
$ go get -u github.com/GoogleCloudPlatform/golang-samples/profiler/...
Ardından uygulama dizinine geçin:
$ cd ~/gopath/src/github.com/GoogleCloudPlatform/golang-samples/profiler/hotapp
Dizin "main.go"yu içerir dosyasını seçin:
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)
}
...
}
Profil oluşturma aracısı varsayılan olarak CPU, yığın ve iş parçacığı profillerini toplar. Buradaki kod, karşılıklı dışlama ("çakışma" olarak da bilinir) profillerinin toplanmasını sağlar.
Şimdi, programı çalıştırın:
$ go run main.go
Program çalışırken profil oluşturma aracısı, yapılandırılmış beş türün profillerini düzenli aralıklarla toplar. Toplama zaman içinde rastgele hale getirilir (türlerin her biri için dakikada bir profil ortalama oranıyla). Bu nedenle, toplanan türlerin her birinin alınması üç dakikayı bulabilir. Program, profil oluşturulduğunda bunu size bildirir. Mesajlar, yukarıdaki yapılandırmada DebugLogging
işaretiyle etkinleştirilir; aksi takdirde, aracı sessizce çalışır:
$ 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 ...
Kullanıcı arayüzü, profillerin ilk kez toplanmasından kısa bir süre sonra kendisini günceller. Bu tarihten sonra otomatik olarak güncellenmediğinden, yeni verileri görmek için Profiler kullanıcı arayüzünü manuel olarak yenilemeniz gerekir. Bunu yapmak için zaman aralığı seçicide Şimdi düğmesini iki kez tıklayın:
Kullanıcı arayüzü yenilendikten sonra, şuna benzer bir sayfa görürsünüz:
Profil türü seçici, kullanılabilen beş profil türünü gösterir:
Şimdi her bir profil türünü ve bazı önemli kullanıcı arayüzü özelliklerini inceleyip bazı denemeler yapalım. Bu aşamada artık Cloud Shell terminaline ihtiyacınız yoktur. Bu nedenle CTRL-C tuşlarına basıp "exit" yazarak terminalden çıkabilirsiniz.
5. Profiler Verilerini Analiz Etme
Bazı verileri topladığımıza göre, bunları daha yakından inceleyelim. Üretimde yer alan farklı performans sorunu türlerinin tipik davranışlarını simüle eden bir sentetik uygulama kullanıyoruz (kaynak GitHub'da mevcuttur).
CPU'yu Yoğun Olarak Kullanan Kod
CPU profili türünü seçin. Kullanıcı arayüzü yüklendikten sonra, alev grafiğinde load
işlevine ait dört yaprak bloğunu görürsünüz. Bunlar toplu olarak tüm CPU tüketimini hesaba katar:
Bu işlev, sıkı bir döngü çalıştırarak çok sayıda CPU döngüsü tüketecek şekilde özel olarak yazılmıştır:
main.go
func load() {
for i := 0; i < (1 << 20); i++ {
}
}
İşlev, dört çağrı yoluyla busyloop
() işlevinden dolaylı olarak çağrılır: busyloop
→ {foo1
, foo2
} → {bar
, baz
} → load
. İşlev kutusunun genişliği, belirli bir çağrı yolunun göreli maliyetini gösterir. Bu durumda, dört yolun da maliyeti aynıdır. Gerçek bir programda, performans açısından en önemli arama yollarını optimize etmeye odaklanmak istersiniz. Daha büyük kutulara sahip daha pahalı yolları görsel olarak vurgulayan alev grafiği, bu yolların tanımlanmasını kolaylaştırıyor.
Görüntüyü daha da daraltmak için profil verileri filtresini kullanabilirsiniz. Örneğin, "Grupları göster" "baz" ifadesini belirten filtre girin. load()
hedefine giden dört arama yolundan yalnızca ikisinin gösterildiği aşağıdaki ekran görüntüsüne benzer bir ekran göreceksiniz. Yalnızca şu iki yol, "baz" dizesine sahip bir işlevden geçer unutmayın. Bu tür filtreleme, daha büyük bir programın alt kısmına odaklanmak istediğinizde (örneğin, yalnızca bir kısmına sahip olmanız nedeniyle) yararlıdır.
Yoğun bellek kullanan kod
Şimdi "Yığın" moduna geçin profil türü. Önceki denemelerde oluşturduğunuz filtreleri kaldırdığınızdan emin olun. Şimdi, alloc
tarafından çağrılan allocImpl
öğesinin, uygulamada belleğin ana tüketicisi olarak gösterildiği bir flame grafiği göreceksiniz:
Yangın grafiğinin üzerindeki özet tablosu, uygulamada kullanılan toplam bellek miktarının ortalama ~57,4 MiB olduğunu göstermektedir.Bunların büyük bir kısmı allocImpl
işlevi tarafından ayrılır. Bu işlevin uygulanması göz önünde bulundurulduğunda bu durum şaşırtıcı değildir:
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))
}
}
İşlev bir kez yürütülür, daha küçük parçalara 64 MiB ayırır ve ardından bu parçaların çöp toplanmasını önlemek için işaretçileri genel bir değişkende depolar. Profil oluşturucu tarafından kullanılan bellek miktarının 64 MiB'tan biraz farklı olduğunu unutmayın: Go yığın profil oluşturucu, istatistiksel bir araçtır. Bu nedenle, ölçümler düşük ek yük oluşturur ancak bayt doğru değildir. Böyle bir yaklaşık% 10'luk bir fark gördüğünüzde şaşırmayın.
KS yoğun kod
"Mesaj dizileri"ni seçerseniz ekranda, genişliğin büyük kısmının wait
ve waitImpl
işlevleri tarafından alındığı flame grafiğine geçiş yapılır:
Flame grafiğinin üzerindeki özette, wait
işlevinden çağrı yığınlarını büyüten 100 gorutin olduğunu görebilirsiniz. Bu beklemeleri başlatan kod aşağıdaki gibi göründüğü için, bu tam olarak doğrudur:
main.go
func main() {
...
// Simulate some waiting goroutines.
for i := 0; i < 100; i++ {
go wait()
}
Bu profil türü, programın bekleme sırasında (G/Ç gibi) beklenmedik bir süre harcayıp harcamadığını anlamak için yararlıdır. Bu tür çağrı yığınları, CPU süresinin önemli bir kısmını kullanmadığı için genellikle CPU profil oluşturucu tarafından örneklenmez. "Grupları gizle"yi kullanmayı tercih edebilirsiniz. İş Parçacıkları profillerine sahip filtreler: örneğin, gopark,
çağrısı ile biten tüm yığınları gizlemek için kullanılır. Çünkü bunlar genellikle boşta olan gorutinler olup G/Ç'de bekleyenlere göre daha az ilgi çekicidir.
İleti dizisi profil türü, programda ileti dizilerinin programın başka bir bölümüne ait bir karşılıklı kapatmayı uzun süre boyunca beklediği noktaları belirlemeye de yardımcı olabilir. Ancak aşağıdaki profil türü bunun için daha yararlıdır.
Çarpışma Yoğun Kod
Çakışma profil türü, en "istenen" kilitleyeceğiz. Bu profil türü Go programları için kullanılabilir ancak "MutexProfiling: true
" belirtilerek açıkça etkinleştirilmelidir yazması gerekir. Koleksiyon, belirli bir kilidin, A goroutine tarafından kilidi açıldığında, kilidin kilidinin açılmasını bekleyen başka bir goroutin B'ye kaç kez sahip olduğu kaydedilerek ("İçerikler" metriğinde) çalışır. Engellenen kategorinin kilit açma süresini de ("Gecikme" metriği altında) kaydeder. Bu örnekte, tek bir çekişme yığını vardır ve kilit için toplam bekleme süresi 10,5 saniyeydi:
Bu profili oluşturan kod, karşılıklı dışlamaya karşı savaşan 4 gorutten oluşur:
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. Özet
Bu laboratuvarda, Go programının Cloud Profiler ile kullanılmak üzere nasıl yapılandırılabileceğini öğrendiniz. Ayrıca bu araçla performans verilerini toplamayı, görüntülemeyi ve analiz etmeyi de öğrendiniz. Artık yeni becerinizi Google Cloud Platform'da çalıştırdığınız gerçek hizmetlere uygulayabilirsiniz.
7. Tebrikler!
Cloud Profiler'ı nasıl yapılandırıp kullanacağınızı öğrendiniz.
Daha Fazla Bilgi
- Cloud Profiler: https://cloud.google.com/profiler/
- Cloud Profiler'ın kullandığı Goworkspace/pprof paketi: https://golang.org/pkg/runtime/pprof/
Lisans
Bu çalışma, Creative Commons Attribution 2.0 Genel Amaçlı Lisans ile lisans altına alınmıştır.