Cloud Profiler ile üretim performansını analiz etme

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.

95c034c70c9cac22.png

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?

Yalnızca okuma Okuyun ve alıştırmaları tamamlayın

Google Cloud Platform deneyiminizi nasıl değerlendirirsiniz?

Acemi Orta Yeterli

2. Kurulum ve Gereksinimler

Kendi hızınızda ortam kurulumu

  1. 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.

96a9c957bc475304.png

b9a10ebdf5b5a448.png

a1e3c01a38fa61c2.png

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.

  1. 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

  1. Cloud Console'da, Cloud Shell'i etkinleştir 4292cbf4971c9786.png simgesini tıklayın.

bce75f34b2c53987.png

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:

70f315d7b402b476.png

Temel hazırlık ve Cloud Shell'e bağlanmak yalnızca birkaç dakika sürer.

fbe3a0674c982259.png

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.

  1. 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`
  1. 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:

37ad0df7ddb2ad17.png

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ı.

d275a5f61ed31fb2.png

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:

650051097b651b91.png

Kullanıcı arayüzü yenilendikten sonra, şuna benzer bir sayfa görürsünüz:

47a763d4dc78b6e8.png

Profil türü seçici, kullanılabilen beş profil türünü gösterir:

b5d7b4b5051687c9.png

Ş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:

fae661c9fe6c58df.png

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.

eb1d97491782b03f.png

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:

f6311c8c841d04c4.png

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:

ebd57fdff01dede9.png

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:

83f00dca4a0f768e.png

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

Lisans

Bu çalışma, Creative Commons Attribution 2.0 Genel Amaçlı Lisans ile lisans altına alınmıştır.