Go'daki uygulamanızda daha iyi performans elde etmenizi sağlayan araç (1. bölüm: trace)

1. Giriş

505827108874614d.png

Son Güncelleme: 2022-07-15

Uygulamanın gözlemlenebilirliği

Gözlemlenebilirlik ve OpenTelemetry

Gözlemlenebilirlik, bir sistemin özelliğini tanımlamak için kullanılan terimdir. Gözlemlenebilirlik özelliği olan bir sistem, ekiplerin sistemlerinde aktif olarak hata ayıklamasına olanak tanır. Bu bağlamda, gözlemlenebilirliğin üç temel unsuru olan günlükler, metrikler ve izler, sistemin gözlemlenebilirlik kazanması için temel enstrümantasyondur.

OpenTelemetry, gözlemlenebilirlik için gereken telemetri verilerinin (günlükler, metrikler ve izler) enstrümantasyonunu ve dışa aktarılmasını hızlandıran bir dizi spesifikasyon, kitaplık ve aracıdır. OpenTelemetry, CNCF bünyesinde açık standartlı ve topluluk odaklı bir projedir. Projenin ve ekosisteminin sağladığı kitaplıkları kullanarak geliştiriciler, uygulamalarını satıcıdan bağımsız bir şekilde ve birden fazla mimariye karşı kullanabilir.

Ayrıca, gözlemlenebilirlik için üç temel unsura ek olarak sürekli profilleme de bir diğer önemli bileşendir ve sektörde kullanıcı tabanını genişletmektedir. Cloud Profiler, bu özelliği ilk sunanlardan biridir ve uygulama çağrı yığınlarındaki performans metriklerini ayrıntılı olarak incelemek için kolay bir arayüz sağlar.

Bu codelab, serinin 1. bölümüdür ve OpenTelemetry ile Cloud Trace kullanarak mikro hizmetlerde dağıtılmış izleri enstrümante etmeyi kapsar. 2. bölümde Cloud Profiler ile sürekli profilleme ele alınacaktır.

Dağıtılmış İzleme

Günlükler, metrikler ve izler arasında iz, sistemdeki sürecin belirli bir bölümünün gecikmesini bildiren telemetridir. Özellikle mikro hizmetler çağında, dağıtılmış izleme, genel dağıtılmış sistemdeki gecikme sorunlarını bulmak için güçlü bir araçtır.

Dağıtılmış izleri analiz ederken iz verilerinin görselleştirilmesi, genel sistem gecikmelerini bir bakışta anlamanın anahtarıdır. Dağıtılmış izlemede, sisteme giriş noktasına yönelik tek bir isteği işlemek için bir dizi çağrıyı birden fazla aralık içeren bir izleme biçiminde ele alırız.

Span, dağıtılmış bir sistemde yapılan ve başlangıç ile bitiş zamanlarını kaydeden tek bir iş birimini ifade eder. Kapsamlar genellikle birbirleriyle hiyerarşik ilişkilere sahiptir. Aşağıdaki resimde, daha küçük tüm kapsamlar büyük bir /messages kapsamının alt kapsamlarıdır ve sistemdeki iş akışını gösteren tek bir İz'de birleştirilir.

İz

Google Cloud Trace, dağıtılmış izleme arka ucu için seçeneklerden biridir ve Google Cloud'daki diğer ürünlerle iyi entegre edilmiştir.

Ne oluşturacaksınız?

Bu codelab'de, Google Kubernetes Engine kümesinde çalışan "Shakespeare uygulaması" (diğer adıyla Shakesapp) adlı hizmetlerde izleme bilgilerini kullanacaksınız. Shakesapp'in mimarisi aşağıda açıklanmıştır:

44e243182ced442f.png

  • Loadgen, HTTP'de istemciye bir sorgu dizesi gönderir.
  • İstemciler, yük oluşturucudan sunucuya gRPC'de sorguyu geçirir.
  • Sunucu, istemciden gelen sorguyu kabul eder, Google Cloud Storage'dan tüm Shakespeare eserlerini metin biçiminde getirir, sorguyu içeren satırları arar ve eşleşen satırın numarasını istemciye döndürür.

İzleme bilgilerini istek genelinde kullanırsınız. Ardından, sunucuya bir profil aracı aracısı yerleştirip performans sorununu inceleyeceksiniz.

Neler öğreneceksiniz?

  • Go projesinde OpenTelemetry Trace kitaplıklarını kullanmaya başlama
  • Kitaplıkla kapsam oluşturma
  • Kapsam bağlamlarını uygulama bileşenleri arasında kablo üzerinden yayma
  • İz verilerini Cloud Trace'e gönderme
  • Cloud Trace'te izlemeyi analiz etme

Bu codelab'de, mikro hizmetlerinize nasıl izleme araçları ekleyeceğiniz açıklanmaktadır. Bu örneği kolay anlaşılır hale getirmek için yalnızca 3 bileşen (yük oluşturucu, istemci ve sunucu) içerir. Ancak bu codelab'de açıklanan aynı süreci daha karmaşık ve büyük sistemlere de uygulayabilirsiniz.

Gerekenler

  • Go hakkında temel bilgiler
  • Kubernetes hakkında temel bilgiler

2. Kurulum ve Gereksinimler

Yönlendirmesiz ortam kurulumu

Google Hesabınız (Gmail veya Google Apps) yoksa hesap oluşturmanız gerekir. Google Cloud Platform Console'da ( console.cloud.google.com) oturum açın ve yeni bir proje oluşturun.

Önceden oluşturduğunuz bir projeniz varsa konsolun sol üst kısmındaki proje seçimi açılır menüsünü tıklayın:

7a32e5469db69e9.png

ve yeni bir proje oluşturmak için açılan iletişim kutusunda "YENİ PROJE" düğmesini tıklayın:

7136b3ee36ebaf89.png

Henüz bir projeniz yoksa ilk projenizi oluşturmak için aşağıdaki gibi bir iletişim kutusu görürsünüz:

870a3cbd6541ee86.png

Sonraki proje oluşturma iletişim kutusunda yeni projenizin ayrıntılarını girebilirsiniz:

affdc444517ba805.png

Tüm Google Cloud projelerinde benzersiz bir ad olan proje kimliğini unutmayın (Yukarıdaki ad zaten alınmış olduğundan sizin için çalışmayacaktır). Bu codelab'de daha sonra PROJECT_ID olarak adlandırılacaktır.

Ardından, henüz yapmadıysanız Google Cloud kaynaklarını kullanmak için Developers Console'da faturalandırmayı etkinleştirmeniz ve Cloud Trace API'yi etkinleştirmeniz gerekir.

15d0ef27a8fbab27.png

Bu codelab'i tamamlamak size birkaç dolardan fazla maliyet getirmemelidir. Ancak daha fazla kaynak kullanmaya karar verirseniz veya kaynakları çalışır durumda bırakırsanız maliyet artabilir (bu belgenin sonundaki "temizleme" bölümüne bakın). Google Cloud Trace, Google Kubernetes Engine ve Google Artifact Registry'nin fiyatlandırması resmi dokümanlarda belirtilmiştir.

Google Cloud Platform'un yeni kullanıcıları, bu codelab'i tamamen ücretsiz hale getirecek 300 ABD doları değerinde ücretsiz deneme sürümünden yararlanabilir.

Google Cloud Shell Kurulumu

Google Cloud ve Google Cloud Trace, dizüstü bilgisayarınızdan uzaktan çalıştırılabilir. Ancak bu codelab'de, bulutta çalışan bir komut satırı ortamı olan Google Cloud Shell'i kullanacağız.

Bu Debian tabanlı sanal makine, ihtiyaç duyacağınız tüm geliştirme araçlarını içerir. 5 GB boyutunda kalıcı bir ana dizin bulunur ve Google Cloud'da çalışır. Bu sayede ağ performansı ve kimlik doğrulama önemli ölçüde güçlenir. Bu nedenle, bu codelab için ihtiyacınız olan tek şey bir tarayıcıdır (Chromebook'ta da çalışır).

Cloud Shell'i Cloud Console'dan etkinleştirmek için Cloud Shell'i Etkinleştir'i gcLMt5IuEcJJNnMId-Bcz3sxCd0rZn7IzT_r95C8UZeqML68Y1efBG_B0VRp7hc7qiZTLAF-TXD7SsOadxn8uadgHhaLeASnVS3ZHK39eOlKJOgj9SJua_oeGhMxRrbOg3qigddS2A tıklamanız yeterlidir (ortamın sağlanması ve bağlantının kurulması yalnızca birkaç saniye sürer).

JjEuRXGg0AYYIY6QZ8d-66gx_Mtc-_jDE9ijmbXLJSAXFvJt-qUpNtsBsYjNpv2W6BQSrDc1D-ARINNQ-1EkwUhz-iUK-FUCZhJ-NtjvIEx9pIkE-246DomWuCfiGHK78DgoeWkHRw

Screen Shot 2017-06-14 at 10.13.43 PM.png

Cloud Shell'e bağlandıktan sonra kimliğinizin doğrulandığını ve projenin, PROJECT_ID'nize ayarlandığını görürsünüz.

gcloud auth list

Komut çıkışı

Credentialed accounts:
 - <myaccount>@<mydomain>.com (active)
gcloud config list project

Komut çıkışı

[core]
project = <PROJECT_ID>

Herhangi bir nedenle proje ayarlanmamışsa şu komutu verin:

gcloud config set project <PROJECT_ID>

PROJECT_ID cihazınızı mı arıyorsunuz? Kurulum adımlarında hangi kimliği kullandığınızı kontrol edin veya Cloud Console kontrol panelinde arayın:

158fNPfwSxsFqz9YbtJVZes8viTS3d1bV4CVhij3XPxuzVFOtTObnwsphlm6lYGmgdMFwBJtc-FaLrZU7XHAg_ZYoCrgombMRR3h-eolLPcvO351c5iBv506B3ZwghZoiRg6cz23Qw

Cloud Shell, gelecekteki komutları çalıştırırken faydalı olabilecek bazı ortam değişkenlerini de varsayılan olarak ayarlar.

echo $GOOGLE_CLOUD_PROJECT

Komut çıkışı

<PROJECT_ID>

Son olarak, varsayılan alt bölgeyi ve proje yapılandırmasını ayarlayın.

gcloud config set compute/zone us-central1-f

Çeşitli bölgeler arasından seçim yapabilirsiniz. Daha fazla bilgi için Bölgeler ve Alt Bölgeler başlıklı makaleyi inceleyin.

Dil kurulumuna gitme

Bu codelab'de tüm kaynak kodları için Go kullanılır. Cloud Shell'de aşağıdaki komutu çalıştırın ve Go sürümünün 1.17 veya daha yeni olduğunu doğrulayın.

go version

Komut çıkışı

go version go1.18.3 linux/amd64

Google Kubernetes kümesi oluşturma

Bu codelab'de, Google Kubernetes Engine'de (GKE) bir mikro hizmet kümesi çalıştıracaksınız. Bu codelab'in süreci aşağıdaki gibidir:

  1. Temel proje dosyasını Cloud Shell'e indirin.
  2. Mikro hizmetleri container'lara yerleştirme
  3. Google Artifact Registry'ye (GAR) kapsayıcı yükleme
  4. Container'ları GKE'ye dağıtma
  5. İzleme enstrümantasyonu için hizmetlerin kaynak kodunu değiştirme
  6. 2. adıma geçin.

Kubernetes Engine'i etkinleştirme

Öncelikle, Shakesapp'in GKE'de çalıştığı bir Kubernetes kümesi oluşturuyoruz. Bu nedenle GKE'yi etkinleştirmemiz gerekiyor. "Kubernetes Engine" menüsüne gidin ve ETKİNLEŞTİR düğmesine basın.

548cfd95bc6d344d.png

Artık Kubernetes kümesi oluşturmaya hazırsınız.

Kubernetes kümesi oluşturma

Cloud Shell'de Kubernetes kümesi oluşturmak için aşağıdaki komutu çalıştırın. Lütfen bölge değerinin, Artifact Registry deposu oluşturmak için kullanacağınız bölgenin altında olduğunu onaylayın. Depo bölgeniz bölgeyi kapsamıyorsa bölge değerini us-central1-f olarak değiştirin.

gcloud container clusters create otel-trace-codelab2 \
--zone us-central1-f \
--release-channel rapid \
--preemptible \
--enable-autoscaling \
--max-nodes 8 \
--no-enable-ip-alias \
--scopes cloud-platform

Komut çıkışı

Note: Your Pod address range (`--cluster-ipv4-cidr`) can accommodate at most 1008 node(s).
Creating cluster otel-trace-codelab2 in us-central1-f... Cluster is being health-checked (master is healthy)...done.     
Created [https://container.googleapis.com/v1/projects/development-215403/zones/us-central1-f/clusters/otel-trace-codelab2].
To inspect the contents of your cluster, go to: https://console.cloud.google.com/kubernetes/workload_/gcloud/us-central1-f/otel-trace-codelab2?project=development-215403
kubeconfig entry generated for otel-trace-codelab2.
NAME: otel-trace-codelab2
LOCATION: us-central1-f
MASTER_VERSION: 1.23.6-gke.1501
MASTER_IP: 104.154.76.89
MACHINE_TYPE: e2-medium
NODE_VERSION: 1.23.6-gke.1501
NUM_NODES: 3
STATUS: RUNNING

Artifact Registry ve skaffold kurulumu

Artık dağıtıma hazır bir Kubernetes kümemiz var. Ardından, kapsayıcıları göndermek ve dağıtmak için bir kapsayıcı kayıt defteri hazırlıyoruz. Bu adımlar için bir Artifact Registry (GAR) oluşturmamız ve bunu kullanmak üzere Skaffold'u ayarlamamız gerekir.

Artifact Registry kurulumu

"Artifact Registry" menüsüne gidin ve ETKİNLEŞTİR düğmesine basın.

45e384b87f7cf0db.png

Bir süre sonra GAR'ın depo tarayıcısını görürsünüz. "CREATE REPOSITORY" (DEPO OLUŞTUR) düğmesini tıklayın ve deponun adını girin.

d6a70f4cb4ebcbe3.png

Bu codelab'de yeni depoya trace-codelab adını veriyorum. Yapının biçimi "Docker", konum türü ise "Bölge" olmalıdır. Google Compute Engine varsayılan bölgesi için ayarladığınız bölgeye yakın bir bölge seçin. Örneğin, yukarıdaki örnekte "us-central1-f" seçildiğinden burada "us-central1 (Iowa)" seçilir. Ardından "OLUŞTUR" düğmesini tıklayın.

9c2d1ce65258ef70.png

Artık "trace-codelab"i depo tarayıcısında görebilirsiniz.

7a3c1f47346bea15.png

Kayıt defteri yolunu kontrol etmek için daha sonra buraya geri döneceğiz.

Skaffold kurulumu

Skaffold, Kubernetes'te çalışan mikro hizmetler oluştururken kullanışlı bir araçtır. Küçük bir komut grubuyla uygulama kapsayıcılarını oluşturma, gönderme ve dağıtma iş akışını yönetir. Skaffold, varsayılan olarak Docker Registry'yi Container Registry olarak kullandığından, container'ları gönderirken GAR'ı tanıyacak şekilde Skaffold'u yapılandırmanız gerekir.

Cloud Shell'i tekrar açın ve Skaffold'ın yüklü olup olmadığını doğrulayın. (Cloud Shell, skaffold'u ortama varsayılan olarak yükler.) Aşağıdaki komutu çalıştırıp Skaffold sürümünü görün.

skaffold version

Komut çıkışı

v1.38.0

Artık, skaffold'un kullanacağı varsayılan veri deposunu kaydedebilirsiniz. Kayıt yolu almak için Artifact Registry kontrol paneline gidin ve önceki adımda ayarladığınız deponun adını tıklayın.

7a3c1f47346bea15.png

Ardından, sayfanın üst kısmında içerik haritası yollarını görürsünüz. Kayıt defteri yolunu panoya kopyalamak için e157b1359c3edc06.png simgesini tıklayın.

e0f2ae2144880b8b.png

Kopyala düğmesini tıkladığınızda tarayıcının alt kısmında aşağıdaki gibi bir mesaj içeren iletişim kutusu görürsünüz:

"us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab" kopyalandı

Cloud Shell'e geri dönün. skaffold config set default-repo komutunu, kontrol panelinden kopyaladığınız değerle birlikte çalıştırın.

skaffold config set default-repo us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab

Komut çıkışı

set value default-repo to us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab for context gke_stackdriver-sandbox-3438851889_us-central1-b_stackdriver-sandbox

Ayrıca, kayıt defterini Docker yapılandırmasına göre yapılandırmanız gerekir. Aşağıdaki komutu çalıştırın:

gcloud auth configure-docker us-central1-docker.pkg.dev --quiet

Komut çıkışı

{
  "credHelpers": {
    "gcr.io": "gcloud",
    "us.gcr.io": "gcloud",
    "eu.gcr.io": "gcloud",
    "asia.gcr.io": "gcloud",
    "staging-k8s.gcr.io": "gcloud",
    "marketplace.gcr.io": "gcloud",
    "us-central1-docker.pkg.dev": "gcloud"
  }
}
Adding credentials for: us-central1-docker.pkg.dev

Artık GKE'de Kubernetes kapsayıcısı oluşturma işleminin bir sonraki adımına geçebilirsiniz.

Özet

Bu adımda codelab ortamınızı ayarlarsınız:

  • Cloud Shell'i ayarlama
  • Container Registry için bir Artifact Registry deposu oluşturduysanız
  • Container Registry'yi kullanmak için Skaffold'u ayarlama
  • Codelab mikro hizmetlerinin çalıştığı bir Kubernetes kümesi oluşturduysanız

Sıradaki

Sonraki adımda, mikro hizmetlerinizi oluşturup kümeye gönderecek ve dağıtacaksınız.

3. Mikro hizmetleri oluşturma, aktarma ve dağıtma

Codelab materyalini indirin

Önceki adımda, bu codelab için tüm ön koşulları ayarladık. Artık tüm mikro hizmetleri bunların üzerinde çalıştırmaya hazırsınız. Codelab materyali GitHub'da barındırıldığından, aşağıdaki git komutuyla Cloud Shell kabuk ortamına indirin.

cd ~
git clone https://github.com/ymotongpoo/opentelemetry-trace-codelab-go.git
cd opentelemetry-trace-codelab-go

Projenin dizin yapısı aşağıdaki gibidir:

.
├── README.md
├── step0
│   ├── manifests
│   ├── proto
│   ├── skaffold.yaml
│   └── src
├── step1
│   ├── manifests
│   ├── proto
│   ├── skaffold.yaml
│   └── src
├── step2
│   ├── manifests
│   ├── proto
│   ├── skaffold.yaml
│   └── src
├── step3
│   ├── manifests
│   ├── proto
│   ├── skaffold.yaml
│   └── src
├── step4
│   ├── manifests
│   ├── proto
│   ├── skaffold.yaml
│   └── src
├── step5
│   ├── manifests
│   ├── proto
│   ├── skaffold.yaml
│   └── src
└── step6
    ├── manifests
    ├── proto
    ├── skaffold.yaml
    └── src
  • manifests: Kubernetes manifest dosyaları
  • proto: İstemci ile sunucu arasındaki iletişim için proto tanımı
  • src: Her hizmetin kaynak kodunun bulunduğu dizinler
  • skaffold.yaml: Skaffold'un yapılandırma dosyası

Bu codelab'de, step0 klasöründe bulunan kaynak kodu güncelleyeceksiniz. Ayrıca, aşağıdaki adımlardaki yanıtlar için step[1-6] klasörlerindeki kaynak koduna da bakabilirsiniz. (1. bölümde 0. adımdan 4. adıma kadar olanlar, 2. bölümde ise 5. ve 6. adımlar ele alınır)

Skaffold komutunu çalıştırma

Son olarak, tüm içeriği oluşturmaya, aktarmaya ve yeni oluşturduğunuz Kubernetes kümesine dağıtmaya hazırsınız. Bu işlem birden fazla adım içeriyormuş gibi görünse de aslında her şeyi sizin için yapan Skaffold'dur. Bunu aşağıdaki komutla deneyelim:

cd step0
skaffold dev

Komutu çalıştırdığınız anda docker build öğesinin günlük çıkışını görür ve bunların kayıt defterine başarıyla gönderildiğini onaylayabilirsiniz.

Komut çıkışı

...
---> Running in c39b3ea8692b
 ---> 90932a583ab6
Successfully built 90932a583ab6
Successfully tagged us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab/serverservice:step1
The push refers to repository [us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab/serverservice]
cc8f5a05df4a: Preparing
5bf719419ee2: Preparing
2901929ad341: Preparing
88d9943798ba: Preparing
b0fdf826a39a: Preparing
3c9c1e0b1647: Preparing
f3427ce9393d: Preparing
14a1ca976738: Preparing
f3427ce9393d: Waiting
14a1ca976738: Waiting
3c9c1e0b1647: Waiting
b0fdf826a39a: Layer already exists
88d9943798ba: Layer already exists
f3427ce9393d: Layer already exists
3c9c1e0b1647: Layer already exists
14a1ca976738: Layer already exists
2901929ad341: Pushed
5bf719419ee2: Pushed
cc8f5a05df4a: Pushed
step1: digest: sha256:8acdbe3a453001f120fb22c11c4f6d64c2451347732f4f271d746c2e4d193bbe size: 2001

Tüm hizmet kapsayıcıları gönderildikten sonra Kubernetes dağıtımları otomatik olarak başlar.

Komut çıkışı

sha256:b71fce0a96cea08075dc20758ae561cf78c83ff656b04d211ffa00cedb77edf8 size: 1997
Tags used in deployment:
 - serverservice -> us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab/serverservice:step4@sha256:8acdbe3a453001f120fb22c11c4f6d64c2451347732f4f271d746c2e4d193bbe
 - clientservice -> us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab/clientservice:step4@sha256:b71fce0a96cea08075dc20758ae561cf78c83ff656b04d211ffa00cedb77edf8
 - loadgen -> us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab/loadgen:step4@sha256:eea2e5bc8463ecf886f958a86906cab896e9e2e380a0eb143deaeaca40f7888a
Starting deploy...
 - deployment.apps/clientservice created
 - service/clientservice created
 - deployment.apps/loadgen created
 - deployment.apps/serverservice created
 - service/serverservice created

Dağıtımdan sonra, her kapsayıcıda stdout'a gönderilen gerçek uygulama günlüklerini şu şekilde görürsünüz:

Komut çıkışı

[client] 2022/07/14 06:33:15 {"match_count":3040}
[loadgen] 2022/07/14 06:33:15 query 'love': matched 3040
[client] 2022/07/14 06:33:15 {"match_count":3040}
[loadgen] 2022/07/14 06:33:15 query 'love': matched 3040
[client] 2022/07/14 06:33:16 {"match_count":3040}
[loadgen] 2022/07/14 06:33:16 query 'love': matched 3040
[client] 2022/07/14 06:33:19 {"match_count":463}
[loadgen] 2022/07/14 06:33:19 query 'tear': matched 463
[loadgen] 2022/07/14 06:33:20 query 'world': matched 728
[client] 2022/07/14 06:33:20 {"match_count":728}
[client] 2022/07/14 06:33:22 {"match_count":463}
[loadgen] 2022/07/14 06:33:22 query 'tear': matched 463

Bu noktada, sunucudan gelen tüm mesajları görmek istediğinizi unutmayın. Tamam, son olarak hizmetlerin dağıtılmış izlenmesi için uygulamanızı OpenTelemetry ile izlemeye başlamaya hazırsınız.

Hizmeti izlemeye başlamadan önce lütfen Ctrl-C ile kümenizi kapatın.

Komut çıkışı

...
[client] 2022/07/14 06:34:57 {"match_count":1}
[loadgen] 2022/07/14 06:34:57 query 'what's past is prologue': matched 1
^CCleaning up...
 - W0714 06:34:58.464305   28078 gcp.go:120] WARNING: the gcp auth plugin is deprecated in v1.22+, unavailable in v1.25+; use gcloud instead.
 - To learn more, consult https://cloud.google.com/blog/products/containers-kubernetes/kubectl-auth-changes-in-gke
 - deployment.apps "clientservice" deleted
 - service "clientservice" deleted
 - deployment.apps "loadgen" deleted
 - deployment.apps "serverservice" deleted
 - service "serverservice" deleted

Özet

Bu adımda, ortamınızdaki codelab materyalini hazırladınız ve skaffold'un beklendiği gibi çalıştığını onayladınız.

Sıradaki

Bir sonraki adımda, izleme bilgilerini ölçmek için loadgen hizmetinin kaynak kodunu değiştireceksiniz.

4. HTTP için araçlar

İzleme enstrümantasyonu ve yayılımı kavramı

Kaynak kodunu düzenlemeden önce, dağıtılmış izlerin nasıl çalıştığını basit bir şemayla kısaca açıklayayım.

6be42e353b9bfd1d.png

Bu örnekte, izleme ve kapsam bilgilerini Cloud Trace'e aktarmak ve yük oluşturma hizmetinden sunucu hizmetine yapılan istekte izleme bağlamını yaymak için kodu izleme araçlarıyla donatıyoruz.

Cloud Trace'in aynı iz kimliğine sahip tüm aralıkları tek bir izde birleştirebilmesi için uygulamaların İz Kimliği ve Aralık Kimliği gibi Trace meta verilerini göndermesi gerekir. Ayrıca, uygulamanın iz bağlamlarını (üst aralığın iz kimliği ve aralık kimliğinin kombinasyonu) aşağı akış hizmetlerine istek gönderirken yayması gerekir. Böylece, hangi iz bağlamını işlediğinin farkında olabilir.

OpenTelemetry ile yapabilecekleriniz:

  • Benzersiz izleme kimliği ve kapsam kimliği oluşturmak için
  • İzleme kimliğini ve kapsam kimliğini arka uca aktarmak için
  • İzleme bağlamlarını diğer hizmetlere yaymak için
  • izlerin analiz edilmesine yardımcı olan ek meta verileri yerleştirmek için

OpenTelemetry İzlemesindeki Bileşenler

b01f7bb90188db0d.png

OpenTelemetry ile uygulama izi enstrümantasyonu işlemi aşağıdaki gibidir:

  1. Dışa aktarıcı oluşturma
  2. Dışa aktarıcıyı 1'de bağlayan bir TracerProvider oluşturun ve bunu genel olarak ayarlayın.
  3. Yayma yöntemini ayarlamak için TextMapPropagaror'u ayarlayın.
  4. TracerProvider'dan Tracer'ı alma
  5. İzleyiciden Span oluşturma

Şu an için her bileşendeki ayrıntılı özellikleri anlamanız gerekmez. Ancak hatırlamanız gereken en önemli noktalar şunlardır:

  • Buradaki dışa aktarma aracı, TracerProvider'a bağlanabilir.
  • TracerProvider, izleme örnekleme ve dışa aktarma ile ilgili tüm yapılandırmaları içerir.
  • Tüm izler Tracer nesnesinde paketlenir.

Bu bilgileri edindikten sonra kodlama işlemine geçebiliriz.

Instrument first span

Yük oluşturucu hizmeti

Cloud Shell'in sağ üst kısmındaki 776a11bfb2122549.png düğmesine basarak Cloud Shell Düzenleyici'yi açın. Soldaki bölmede bulunan Gezgin'den step0/src/loadgen/main.go simgesini açın ve ana işlevi bulun.

step0/src/loadgen/main.go

func main() {
        ...
        for range t.C {
                log.Printf("simulating client requests, round %d", i)
                if err := run(numWorkers, numConcurrency); err != nil {
                        log.Printf("aborted round with error: %v", err)
                }
                log.Printf("simulated %d requests", numWorkers)
                if numRounds != 0 && i > numRounds {
                        break
                }
                i++
        }
}

Ana işlevde, döngünün run işlevini çağırdığını görürsünüz. Mevcut uygulamada, işlev çağrısının başlangıcını ve bitişini kaydeden 2 günlük satırı bulunur. Şimdi işlev çağrısının gecikmesini izlemek için Span bilgilerini ölçelim.

Öncelikle, önceki bölümde belirtildiği gibi OpenTelemetry'nin tüm yapılandırmalarını ayarlayalım. OpenTelemetry paketlerini aşağıdaki gibi ekleyin:

step0/src/loadgen/main.go

import (
        "context" // step1. add packages
        "encoding/json"
        "fmt"
        "io"
        "log"
        "math/rand"
        "net/http"
        "net/url"
        "time"
        // step1. add packages
        "go.opentelemetry.io/otel"
        "go.opentelemetry.io/otel/attribute"
        stdout "go.opentelemetry.io/otel/exporters/stdout/stdouttrace"
        "go.opentelemetry.io/otel/propagation"
        sdktrace "go.opentelemetry.io/otel/sdk/trace"
        semconv "go.opentelemetry.io/otel/semconv/v1.10.0"
        "go.opentelemetry.io/otel/trace"
        // step1. end add packages
)

Okunabilirliği artırmak için initTracer adlı bir kurulum işlevi oluşturup main işlevinde çağırırız.

step0/src/loadgen/main.go

// step1. add OpenTelemetry initialization function
func initTracer() (*sdktrace.TracerProvider, error) {
        // create a stdout exporter to show collected spans out to stdout.
        exporter, err := stdout.New(stdout.WithPrettyPrint())
        if err != nil {
                return nil, err
        }

        // for the demonstration, we use AlwaysSmaple sampler to take all spans.
        // do not use this option in production.
        tp := sdktrace.NewTracerProvider(
                sdktrace.WithSampler(sdktrace.AlwaysSample()),
                sdktrace.WithBatcher(exporter),
        )
        otel.SetTracerProvider(tp)
        otel.SetTextMapPropagator(propagation.TraceContext{})
        return tp, nil
}

OpenTelemetry'yi ayarlama prosedürünün önceki bölümde açıklandığı gibi olduğunu fark edebilirsiniz. Bu uygulamada, tüm izleme bilgilerini yapılandırılmış bir biçimde stdout'a aktaran bir stdout dışa aktarıcı kullanıyoruz.

Ardından, ana işlevden bu işlevi çağırırsınız. initTracer() numaralı telefonu arayın ve uygulamayı kapattığınızda TracerProvider.Shutdown() numaralı telefonu aradığınızdan emin olun.

step0/src/loadgen/main.go

func main() {
        // step1. setup OpenTelemetry
        tp, err := initTracer()
        if err != nil {
                log.Fatalf("failed to initialize TracerProvider: %v", err)
        }
        defer func() {
                if err := tp.Shutdown(context.Background()); err != nil {
                        log.Fatalf("error shutting down TracerProvider: %v", err)
                }
        }()
        // step1. end setup

        log.Printf("starting worder with %d workers in %d concurrency", numWorkers, numConcurrency)
        log.Printf("number of rounds: %d (0 is inifinite)", numRounds)
        ...

Kurulumu tamamladıktan sonra benzersiz bir izleme kimliği ve aralık kimliği içeren bir aralık oluşturmanız gerekir. OpenTelemetry bu amaçla kullanışlı bir kitaplık sunar. HTTP istemcisine yeni paketler ekleyin.

step0/src/loadgen/main.go

import (
        "context"
        "encoding/json"
        "fmt"
        "io"
        "log"
        "math/rand"
        "net/http"
        "net/http/httptrace" // step1. add packages
        "net/url"
        "time"
        // step1. add packages
        "go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace"
        "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
        // step1. end add packages
        "go.opentelemetry.io/otel"
        "go.opentelemetry.io/otel/attribute"
        stdout "go.opentelemetry.io/otel/exporters/stdout/stdouttrace"
        "go.opentelemetry.io/otel/propagation"
        sdktrace "go.opentelemetry.io/otel/sdk/trace"
        semconv "go.opentelemetry.io/otel/semconv/v1.10.0"
        "go.opentelemetry.io/otel/trace"
)

Yük oluşturucu, runQuery işlevinde net/http ile HTTP'de istemci hizmetini çağırdığından net/http için contrib paketini kullanırız ve httptrace ile otelhttp paketinin uzantısıyla enstrümantasyonu etkinleştiririz.

Öncelikle, HTTP isteklerini izlenen istemci üzerinden çağırmak için bir paket genel değişkeni olan httpClient'ı ekleyin.

step0/src/loadgen/main.go

var httpClient = http.Client{
        Transport: otelhttp.NewTransport(http.DefaultTransport)
}

Ardından, OpenTelemetry'yi ve özel HTTP istemcisinden otomatik olarak oluşturulan aralığı kullanarak özel aralık oluşturmak için runQuery işlevine enstrümantasyon ekleyin. Yapacaklarınız:

  1. otel.Tracer() ile dünyanın dört bir yanındaki TracerProvider cihazlardan İz Alma
  2. Tracer.Start() yöntemiyle kök kapsam oluşturma
  3. Kök kapsamı rastgele bir zamanda sonlandırın (bu örnekte runQuery işlevinin sonu)

step0/src/loadgen/main.go

        reqURL.RawQuery = v.Encode()
        // step1. replace http.Get() with custom client call
        // resp, err := http.Get(reqURL.String())

        // step1. instrument trace
        ctx := context.Background()
        tr := otel.Tracer("loadgen")
        ctx, span := tr.Start(ctx, "query.request", trace.WithAttributes(
                semconv.TelemetrySDKLanguageGo,
                semconv.ServiceNameKey.String("loadgen.runQuery"),
                attribute.Key("query").String(s),
        ))
        defer span.End()
        ctx = httptrace.WithClientTrace(ctx, otelhttptrace.NewClientTrace(ctx))
        req, err := http.NewRequestWithContext(ctx, "GET", reqURL.String(), nil)
        if err != nil {
                return -1, fmt.Errorf("error creating HTTP request object: %v", err)
        }
        resp, err := httpClient.Do(req)
        // step1. end instrumentation
        if err != nil {
                return -1, fmt.Errorf("error sending request to %v: %v", reqURL.String(), err)
        }

Artık yük oluşturma aracında (HTTP istemci uygulaması) enstrümantasyon işlemini tamamladınız. Lütfen go.mod ve go.sum dosyalarınızı go mod komutuyla güncellediğinizden emin olun.

go mod tidy

Enstrüman müşteri hizmetleri

Önceki bölümde, aşağıdaki çizimde kırmızı dikdörtgen içine alınmış kısmı izledik. Yük oluşturucu hizmetinde span bilgilerini enstrümante ettik. Yük oluşturucu hizmetine benzer şekilde, şimdi de istemci hizmetini izlememiz gerekiyor. Yük oluşturucu hizmetinden farklı olarak, istemci hizmetinin HTTP başlığında yük oluşturucu hizmetinden yayılan İzleme Kimliği bilgilerini ayıklaması ve bu kimliği kullanarak aralıklar oluşturması gerekir.

bcaccd06691269f8.png

Cloud Shell Düzenleyici'yi açın ve yük oluşturucu hizmetinde yaptığımız gibi gerekli paketleri ekleyin.

step0/src/client/main.go

import (
        "context"
        "encoding/json"
        "fmt"
        "io"
        "log"
        "net/http"
        "net/url"
        "os"
        "time"

        "opentelemetry-trace-codelab-go/client/shakesapp"
        // step1. add new import
        "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
        "go.opentelemetry.io/otel"
        "go.opentelemetry.io/otel/attribute"
        stdout "go.opentelemetry.io/otel/exporters/stdout/stdouttrace"
        "go.opentelemetry.io/otel/propagation"
        sdktrace "go.opentelemetry.io/otel/sdk/trace"
        "go.opentelemetry.io/otel/trace"
        "google.golang.org/grpc"
        "google.golang.org/grpc/credentials/insecure"
        // step1. end new import
)

OpenTelemetry'yi tekrar kurmamız gerekiyor. loadgen'deki initTracer işlevini kopyalayıp yapıştırmanız ve istemci hizmetinin main işlevinde de çağırmanız yeterlidir.

step0/src/client/main.go

// step1. add OpenTelemetry initialization function
func initTracer() (*sdktrace.TracerProvider, error) {
        // create a stdout exporter to show collected spans out to stdout.
        exporter, err := stdout.New(stdout.WithPrettyPrint())
        if err != nil {
                return nil, err
        }

        // for the demonstration, we use AlwaysSmaple sampler to take all spans.
        // do not use this option in production.
        tp := sdktrace.NewTracerProvider(
                sdktrace.WithSampler(sdktrace.AlwaysSample()),
                sdktrace.WithBatcher(exporter),
        )
        otel.SetTracerProvider(tp)
        otel.SetTextMapPropagator(propagation.TraceContext{})
        return tp, nil
}

Şimdi kapsamları izleme zamanı. Çünkü istemci hizmetinin, yük oluşturma hizmetinden gelen HTTP isteklerini kabul etmesi için işleyiciyi izlemesi gerekir. İstemci hizmetindeki HTTP sunucusu net/http ile uygulanır ve loadgen'de yaptığımız gibi otelhttp paketini kullanabilirsiniz.

İlk olarak, işleyici kaydını otelhttp işleyicisiyle değiştiririz. main işlevinde, HTTP işleyicinin http.HandleFunc() ile kaydedildiği satırları bulun.

step0/src/client/main.go

        // step1. change handler to intercept OpenTelemetry related headers
        // http.HandleFunc("/", svc.handler)
        otelHandler := otelhttp.NewHandler(http.HandlerFunc(svc.handler), "client.handler")
        http.Handle("/", otelHandler)
        // step1. end intercepter setting
        http.HandleFunc("/_genki", svc.health)

Ardından, işleyicinin içindeki gerçek aralığı ölçeriz. func (*clientService) handler() işleyicisini bulun ve trace.SpanFromContext() ile aralık enstrümantasyonu ekleyin.

step0/src/client/main.go

func (cs *clientService) handler(w http.ResponseWriter, r *http.Request) {
        ...
        ctx := r.Context()
        ctx, cancel := context.WithCancel(ctx)
        defer cancel()
        // step1. instrument trace
        span := trace.SpanFromContext(ctx)
        defer span.End()
        // step1. end instrument
        ...

Bu enstrümantasyon ile handler yönteminin başlangıcından sonuna kadar olan aralıkları elde edersiniz. Kapsamların analizini kolaylaştırmak için sorguya eşleşen sayıyı depolayan ek bir özellik ekleyin. Günlük satırının hemen öncesine aşağıdaki kodu ekleyin.

step0/src/client/main.go

func (cs *clientService) handler(w http.ResponseWriter, r *http.Request) {
        ...
        // step1. add span specific attribute
        span.SetAttributes(attribute.Key("matched").Int64(resp.MatchCount))
        // step1. end adding attribute
        log.Println(string(ret))
        ...

Yukarıdaki tüm enstrümantasyonlarla, yük oluşturucu ve istemci arasındaki izleme enstrümantasyonunu tamamladınız. İşleyiş şeklini inceleyelim. Kodu tekrar Skaffold ile çalıştırın.

skaffold dev

GKE kümesinde hizmetler bir süre çalıştırıldıktan sonra aşağıdaki gibi çok sayıda günlük mesajı görürsünüz:

Komut çıkışı

[loadgen] {
[loadgen]       "Name": "query.request",
[loadgen]       "SpanContext": {
[loadgen]               "TraceID": "cfa22247a542beeb55a3434392d46b89",
[loadgen]               "SpanID": "18b06404b10c418b",
[loadgen]               "TraceFlags": "01",
[loadgen]               "TraceState": "",
[loadgen]               "Remote": false
[loadgen]       },
[loadgen]       "Parent": {
[loadgen]               "TraceID": "00000000000000000000000000000000",
[loadgen]               "SpanID": "0000000000000000",
[loadgen]               "TraceFlags": "00",
[loadgen]               "TraceState": "",
[loadgen]               "Remote": false
[loadgen]       },
[loadgen]       "SpanKind": 1,
[loadgen]       "StartTime": "2022-07-14T13:13:36.686751087Z",
[loadgen]       "EndTime": "2022-07-14T13:14:31.849601964Z",
[loadgen]       "Attributes": [
[loadgen]               {
[loadgen]                       "Key": "telemetry.sdk.language",
[loadgen]                       "Value": {
[loadgen]                               "Type": "STRING",
[loadgen]                               "Value": "go"
[loadgen]                       }
[loadgen]               },
[loadgen]               {
[loadgen]                       "Key": "service.name",
[loadgen]                       "Value": {
[loadgen]                               "Type": "STRING",
[loadgen]                               "Value": "loadgen.runQuery"
[loadgen]                       }
[loadgen]               },
[loadgen]               {
[loadgen]                       "Key": "query",
[loadgen]                       "Value": {
[loadgen]                               "Type": "STRING",
[loadgen]                               "Value": "faith"
[loadgen]                       }
[loadgen]               }
[loadgen]       ],
[loadgen]       "Events": null,
[loadgen]       "Links": null,
[loadgen]       "Status": {
[loadgen]               "Code": "Unset",
[loadgen]               "Description": ""
[loadgen]       },
[loadgen]       "DroppedAttributes": 0,
[loadgen]       "DroppedEvents": 0,
[loadgen]       "DroppedLinks": 0,
[loadgen]       "ChildSpanCount": 5,
[loadgen]       "Resource": [
[loadgen]               {
[loadgen]                       "Key": "service.name",
[loadgen]                       "Value": {
[loadgen]                               "Type": "STRING",
[loadgen]                               "Value": "unknown_service:loadgen"
...

Bu iletiler stdout dışa aktarıcı tarafından verilir. Yük oluşturma aracı tarafından oluşturulan tüm aralıkların üst öğelerinin TraceID: 00000000000000000000000000000000 olduğunu görürsünüz. Bunun nedeni, bu aralığın kök aralık (izdeki ilk aralık) olmasıdır. Ayrıca, yerleştirme özelliğinin "query" müşteri hizmetlerine iletilen sorgu dizesine sahip olduğunu da görürsünüz.

Özet

Bu adımda, HTTP üzerinden iletişim kuran yük oluşturucu hizmetini ve istemci hizmetini enstrümante ettiniz. Ayrıca, izleme bağlamını hizmetler arasında başarıyla yayabildiğinizi ve her iki hizmetten de stdout'a aralık bilgilerini dışa aktarabildiğinizi doğruladınız.

Sıradaki

Bir sonraki adımda, İzleme Bağlamı'nın gRPC üzerinden nasıl yayılacağını onaylamak için istemci hizmetini ve sunucu hizmetini izleme araçlarıyla donatacaksınız.

5. gRPC için enstrümantasyon

Önceki adımda, bu mikro hizmetlerdeki isteğin ilk yarısını izledik. Bu adımda, istemci hizmeti ile sunucu hizmeti arasındaki gRPC iletişimini izlemeye çalışırız. (Aşağıdaki resimde yeşil ve mor dikdörtgen)

75310d8e0e3b1a30.png

gRPC istemcisi için önceden oluşturulmuş enstrümantasyon

OpenTelemetry'nin ekosistemi, geliştiricilerin uygulamaları izlemesine yardımcı olan birçok kullanışlı kitaplık sunar. Önceki adımda, net/http paketi için önceden oluşturulmuş enstrümantasyon kullandık. Bu adımda, izleme bağlamını gRPC üzerinden yaymaya çalıştığımız için kitaplığı kullanıyoruz.

Öncelikle otelgrpc adlı önceden oluşturulmuş gRPC paketini içe aktarırsınız.

step0/src/client/main.go

import (
        "context"
        "encoding/json"
        "fmt"
        "io"
        "log"
        "net/http"
        "net/url"
        "os"
        "time"

        "opentelemetry-trace-codelab-go/client/shakesapp"
        // step2. add prebuilt gRPC package (otelgrpc) 
        "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"
        "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
        "go.opentelemetry.io/otel"
        "go.opentelemetry.io/otel/attribute"
        stdout "go.opentelemetry.io/otel/exporters/stdout/stdouttrace"
        "go.opentelemetry.io/otel/propagation"
        sdktrace "go.opentelemetry.io/otel/sdk/trace"
        "go.opentelemetry.io/otel/trace"
        "google.golang.org/grpc"
        "google.golang.org/grpc/credentials/insecure"
)

Bu kez istemci hizmeti, sunucu hizmetine karşı bir gRPC istemcisi olduğundan gRPC istemcisini izlemeniz gerekir. mustConnGRPC işlevini bulun ve istemci sunucuya her istekte bulunduğunda yeni aralıklar oluşturan gRPC araya giren işlevlerini ekleyin.

step0/src/client/main.go

// Helper function for gRPC connections: Dial and create client once, reuse.
func mustConnGRPC(ctx context.Context, conn **grpc.ClientConn, addr string) {
        var err error
        // step2. add gRPC interceptor
        interceptorOpt := otelgrpc.WithTracerProvider(otel.GetTracerProvider())
        *conn, err = grpc.DialContext(ctx, addr,
                grpc.WithTransportCredentials(insecure.NewCredentials()),
                grpc.WithUnaryInterceptor(otelgrpc.UnaryClientInterceptor(interceptorOpt)),
                grpc.WithStreamInterceptor(otelgrpc.StreamClientInterceptor(interceptorOpt)),
                grpc.WithTimeout(time.Second*3),
        )
        // step2: end adding interceptor
        if err != nil {
                panic(fmt.Sprintf("Error %s grpc: failed to connect %s", err, addr))
        }
}

Önceki bölümde OpenTelemetry'yi zaten ayarladığınız için bu adımı uygulamanız gerekmez.

gRPC sunucusu için önceden oluşturulmuş enstrümantasyon

gRPC istemcisi için yaptığımız gibi, gRPC sunucusu için önceden oluşturulmuş enstrümantasyonu çağırıyoruz. İçe aktarma bölümüne aşağıdaki gibi yeni bir paket ekleyin:

step0/src/server/main.go

import (
        "context"
        "fmt"
        "io/ioutil"
        "log"
        "net"
        "os"
        "regexp"
        "strings"

        "opentelemetry-trace-codelab-go/server/shakesapp"

        "cloud.google.com/go/storage"
        // step2. add OpenTelemetry packages including otelgrpc
        "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"
        "go.opentelemetry.io/otel"
        stdout "go.opentelemetry.io/otel/exporters/stdout/stdouttrace"
        "go.opentelemetry.io/otel/propagation"
        sdktrace "go.opentelemetry.io/otel/sdk/trace"
        "google.golang.org/api/iterator"
        "google.golang.org/api/option"
        "google.golang.org/grpc"
        healthpb "google.golang.org/grpc/health/grpc_health_v1"
)

Sunucuya ilk kez araç eklediğiniz için önce OpenTelemetry'yi kurmanız gerekir. Bu işlem, loadgen ve istemci hizmetlerinde yaptığımıza benzer.

step0/src/server/main.go

// step2. add OpenTelemetry initialization function
func initTracer() (*sdktrace.TracerProvider, error) {
        // create a stdout exporter to show collected spans out to stdout.
        exporter, err := stdout.New(stdout.WithPrettyPrint())
        if err != nil {
                return nil, err
        }
        // for the demonstration, we use AlwaysSmaple sampler to take all spans.
        // do not use this option in production.
        tp := sdktrace.NewTracerProvider(
                sdktrace.WithSampler(sdktrace.AlwaysSample()),
                sdktrace.WithBatcher(exporter),
        )
        otel.SetTracerProvider(tp)
        otel.SetTextMapPropagator(propagation.TraceContext{})
        return tp, nil
}

func main() {
        ...

        // step2. setup OpenTelemetry
        tp, err := initTracer()
        if err != nil {
                log.Fatalf("failed to initialize TracerProvider: %v", err)
        }
        defer func() {
                if err := tp.Shutdown(context.Background()); err != nil {
                        log.Fatalf("error shutting down TracerProvider: %v", err)
                }
        }()
        // step2. end setup
        ...

Ardından, sunucu araya girenlerini eklemeniz gerekir. main işlevinde, grpc.NewServer() öğesinin çağrıldığı yeri bulun ve işleve araya giren işlevler ekleyin.

step0/src/server/main.go

func main() {
        ...
        svc := NewServerService()
        // step2: add interceptor
        interceptorOpt := otelgrpc.WithTracerProvider(otel.GetTracerProvider())
        srv := grpc.NewServer(
                grpc.UnaryInterceptor(otelgrpc.UnaryServerInterceptor(interceptorOpt)),
                grpc.StreamInterceptor(otelgrpc.StreamServerInterceptor(interceptorOpt)),
        )
        // step2: end adding interceptor
        shakesapp.RegisterShakespeareServiceServer(srv, svc)
        ...

Mikro hizmeti çalıştırın ve izlemeyi onaylayın

Ardından, değiştirilen kodunuzu skaffold komutuyla çalıştırın.

skaffold dev

Şimdi tekrar stdout'ta bir dizi span bilgisi görüyorsunuz.

Komut çıkışı

...
[server] {
[server]        "Name": "shakesapp.ShakespeareService/GetMatchCount",
[server]        "SpanContext": {
[server]                "TraceID": "89b472f213a400cf975e0a0041649667",
[server]                "SpanID": "96030dbad0061b3f",
[server]                "TraceFlags": "01",
[server]                "TraceState": "",
[server]                "Remote": false
[server]        },
[server]        "Parent": {
[server]                "TraceID": "89b472f213a400cf975e0a0041649667",
[server]                "SpanID": "cd90cc3859b73890",
[server]                "TraceFlags": "01",
[server]                "TraceState": "",
[server]                "Remote": true
[server]        },
[server]        "SpanKind": 2,
[server]        "StartTime": "2022-07-14T14:05:55.74822525Z",
[server]        "EndTime": "2022-07-14T14:06:03.449258891Z",
[server]        "Attributes": [
...
[server]        ],
[server]        "Events": [
[server]                {
[server]                        "Name": "message",
[server]                        "Attributes": [
...
[server]                        ],
[server]                        "DroppedAttributeCount": 0,
[server]                        "Time": "2022-07-14T14:05:55.748235489Z"
[server]                },
[server]                {
[server]                        "Name": "message",
[server]                        "Attributes": [
...
[server]                        ],
[server]                        "DroppedAttributeCount": 0,
[server]                        "Time": "2022-07-14T14:06:03.449255889Z"
[server]                }
[server]        ],
[server]        "Links": null,
[server]        "Status": {
[server]                "Code": "Unset",
[server]                "Description": ""
[server]        },
[server]        "DroppedAttributes": 0,
[server]        "DroppedEvents": 0,
[server]        "DroppedLinks": 0,
[server]        "ChildSpanCount": 0,
[server]        "Resource": [
[server]                {
...
[server]        ],
[server]        "InstrumentationLibrary": {
[server]                "Name": "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc",
[server]                "Version": "semver:0.33.0",
[server]                "SchemaURL": ""
[server]        }
[server] }
...

Hiçbir kapsam adı yerleştirmediğinizi ve trace.Start() veya span.SpanFromContext() ile kapsamları manuel olarak oluşturduğunuzu fark ediyorsunuz. Bununla birlikte, gRPC araya girenleri bunları oluşturduğu için çok sayıda kapsam elde edersiniz.

Özet

Bu adımda, OpenTelemetry ekosistem kitaplıklarının desteğiyle gRPC tabanlı iletişimi izlediniz.

Sıradaki

Sonraki adımda, izi Cloud Trace ile görselleştirecek ve toplanan aralıkları nasıl analiz edeceğinizi öğreneceksiniz.

6. Cloud Trace ile izlemeyi görselleştirme

OpenTelemetry ile tüm sistemdeki izleri enstrümante etmiş olmanız gerekir. Şu ana kadar HTTP ve gRPC hizmetlerini nasıl izleyeceğinizi öğrendiniz. Bu metrikleri nasıl kullanacağınızı öğrenmiş olsanız da nasıl analiz edeceğinizi henüz öğrenmediniz. Bu bölümde, stdout dışa aktarıcılarını Cloud Trace dışa aktarıcılarıyla değiştirecek ve izlerinizi nasıl analiz edeceğinizi öğreneceksiniz.

Cloud Trace dışa aktarıcısını kullanma

OpenTelemetry'nin güçlü özelliklerinden biri, eklenebilir olmasıdır. Enstrümantasyonunuz tarafından toplanan tüm aralıkları görselleştirmek için yapmanız gereken tek şey stdout dışa aktarıcısını Cloud Trace dışa aktarıcısıyla değiştirmektir.

Her hizmetin main.go dosyalarını açın ve initTracer() işlevini bulun. stdout dışa aktarıcı oluşturmak için satırı silin ve bunun yerine Cloud Trace dışa aktarıcı oluşturun.

step0/src/loadgen/main.go

import (
        ...
        // step3. add OpenTelemetry for Cloud Trace package
        cloudtrace "github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/trace"
)

// step1. add OpenTelemetry initialization function
func initTracer() (*sdktrace.TracerProvider, error) {
        // step3. replace stdout exporter with Cloud Trace exporter
        // cloudtrace.New() finds the credentials to Cloud Trace automatically following the
        // rules defined by golang.org/x/oauth2/google.findDefaultCredentailsWithParams.
        // https://pkg.go.dev/golang.org/x/oauth2/google#FindDefaultCredentialsWithParams
        exporter, err := cloudtrace.New()
        // step3. end replacing exporter
        if err != nil {
                return nil, err
        }

        // for the demonstration, we use AlwaysSmaple sampler to take all spans.
        // do not use this option in production.
        tp := sdktrace.NewTracerProvider(
                sdktrace.WithSampler(sdktrace.AlwaysSample()),
                sdktrace.WithBatcher(exporter),
        )
        otel.SetTracerProvider(tp)
        otel.SetTextMapPropagator(propagation.TraceContext{})
        return tp, nil
}

Aynı işlevi istemci ve sunucu hizmetinde de düzenlemeniz gerekir.

Mikro hizmeti çalıştırın ve izlemeyi onaylayın

Düzenlemeden sonra kümeyi her zamanki gibi skaffold komutuyla çalıştırın.

skaffold dev

Dışa aktarıcıyı Cloud Trace ile değiştirdiğiniz için artık stdout'ta yapılandırılmış günlükler biçiminde çok fazla aralık bilgisi görmüyorsunuz.

Komut çıkışı

[loadgen] 2022/07/14 15:01:07 simulated 20 requests
[loadgen] 2022/07/14 15:01:07 simulating client requests, round 37
[loadgen] 2022/07/14 15:01:14 query 'sweet': matched 958
[client] 2022/07/14 15:01:14 {"match_count":958}
[client] 2022/07/14 15:01:14 {"match_count":3040}
[loadgen] 2022/07/14 15:01:14 query 'love': matched 3040
[client] 2022/07/14 15:01:15 {"match_count":349}
[loadgen] 2022/07/14 15:01:15 query 'hello': matched 349
[client] 2022/07/14 15:01:15 {"match_count":484}
[loadgen] 2022/07/14 15:01:15 query 'faith': matched 484
[loadgen] 2022/07/14 15:01:15 query 'insolence': matched 14
[client] 2022/07/14 15:01:15 {"match_count":14}
[client] 2022/07/14 15:01:21 {"match_count":484}
[loadgen] 2022/07/14 15:01:21 query 'faith': matched 484
[client] 2022/07/14 15:01:21 {"match_count":728}
[loadgen] 2022/07/14 15:01:21 query 'world': matched 728
[client] 2022/07/14 15:01:22 {"match_count":484}
[loadgen] 2022/07/14 15:01:22 query 'faith': matched 484
[loadgen] 2022/07/14 15:01:22 query 'hello': matched 349
[client] 2022/07/14 15:01:22 {"match_count":349}
[client] 2022/07/14 15:01:23 {"match_count":1036}
[loadgen] 2022/07/14 15:01:23 query 'friend': matched 1036
[loadgen] 2022/07/14 15:01:28 query 'tear': matched 463
...

Şimdi tüm kapsamların Cloud Trace'e doğru şekilde gönderilip gönderilmediğini doğrulayalım. Cloud Console'a erişin ve "İzleme listesi"ne gidin. Arama kutusundan kolayca erişilebilir. Aksi takdirde, sol bölmedeki menüyü tıklayabilirsiniz. 8b3f8411bd737e06.png

Ardından, gecikme grafiğinde çok sayıda mavi nokta dağıtıldığını görürsünüz. Her nokta tek bir izi temsil eder.

3ecf131423fc4c40.png

Bunlardan birini tıkladığınızda izleme içindeki ayrıntıları görebilirsiniz. 4fd10960c6648a03.png

Bu basit ve hızlı bakıştan bile birçok analiz elde edebilirsiniz. Örneğin, şelale grafiğinden gecikmenin nedeninin çoğunlukla shakesapp.ShakespeareService/GetMatchCount adlı aralık olduğunu görebilirsiniz. (Yukarıdaki resimde 1 numaralı bölüm) Bunu özet tablosundan doğrulayabilirsiniz. (En sağdaki sütunda her aralığın süresi gösterilir.) Ayrıca bu izleme, "arkadaş" sorgusu için yapıldı. (Yukarıdaki resimde 2 numaralı öğeye bakın)

Bu kısa analizler sayesinde, GetMatchCount yönteminde daha ayrıntılı aralıklar bilmeniz gerektiğini fark edebilirsiniz. Görselleştirme, stdout bilgilerine kıyasla daha güçlüdür. Cloud Trace ayrıntıları hakkında daha fazla bilgi edinmek için lütfen resmi belgelerimizi ziyaret edin.

Özet

Bu adımda, stdout dışa aktarıcısını Cloud Trace ile değiştirdiniz ve izleri Cloud Trace'te görselleştirdiniz. Ayrıca izleri analiz etmeye nasıl başlayacağınızı da öğrendiniz.

Sıradaki

Sonraki adımda, GetMatchCount'a bir alt aralık eklemek için sunucu hizmetinin kaynak kodunu değiştireceksiniz.

7. Daha iyi analiz için alt aralık ekleme

Önceki adımda, loadgen'den gözlemlenen gidiş dönüş süresinin nedeninin büyük ölçüde sunucu hizmetindeki GetMatchCount yönteminin içindeki işlem, yani gRPC işleyicisi olduğu belirlendi. Ancak işleyici dışında hiçbir şeyi ölçmediğimiz için şelale grafiğinden daha fazla bilgi edinemiyoruz. Bu, mikro hizmetleri izlemeye başladığımızda sıkça karşılaştığımız bir durumdur.

3b63a1e471dddb8c.png

Bu bölümde, sunucunun Google Cloud Storage'i çağırdığı bir alt aralığı izleyeceğiz. Çünkü süreçte bazı harici ağ G/Ç'lerinin uzun sürmesi yaygın bir durumdur ve çağrının buna neden olup olmadığını belirlemek önemlidir.

Sunucuda bir alt aralık oluşturma

Sunucuda main.go simgesini açın ve readFiles işlevini bulun. Bu işlev, Shakespeare'in eserlerinin tüm metin dosyalarını getirmek için Google Cloud Storage'a istek gönderiyor. Bu işlevde, istemci hizmetinde HTTP sunucusu enstrümantasyonu için yaptığınız gibi bir alt aralık oluşturabilirsiniz.

step0/src/server/main.go

func readFiles(ctx context.Context, bucketName, prefix string) ([]string, error) {
        type resp struct {
                s   string
                err error
        }

        // step4: add an extra span
        span := trace.SpanFromContext(ctx)
        span.SetName("server.readFiles")
        span.SetAttributes(attribute.Key("bucketname").String(bucketName))
        defer span.End()
        // step4: end add span
        ...

Yeni bir aralık ekleme işlemi bu kadar. Uygulamayı çalıştırarak nasıl gittiğine bakalım.

Mikro hizmeti çalıştırın ve izlemeyi onaylayın

Düzenlemeden sonra kümeyi her zamanki gibi skaffold komutuyla çalıştırın.

skaffold dev

İz listesinden query.request adlı bir iz seçin. shakesapp.ShakespeareService/GetMatchCount altında yeni bir aralık dışında benzer bir izleme şelalesi grafiği görürsünüz. (Aşağıdaki kırmızı dikdörtgenle çevrili aralık)

3d4a891aa30d7a32.png

Bu grafikten şu anda Google Cloud Storage'e yapılan harici çağrının büyük bir gecikmeye neden olduğu ancak gecikmenin büyük kısmının başka işlemlerden kaynaklandığı anlaşılıyor.

İzleme şelale grafiğine birkaç kez bakarak bile birçok analiz elde edebilirsiniz. Uygulamanızdaki diğer performans ayrıntılarını nasıl elde ediyorsunuz? Burada profiler devreye girer ancak şimdilik bu codelab'i sonlandıralım ve tüm profiler eğitimlerini 2. bölüme bırakalım.

Özet

Bu adımda, sunucu hizmetinde başka bir aralık oluşturup sistem gecikmesiyle ilgili daha fazla bilgi edindiniz.

8. Tebrikler

OpenTelemetry ile dağıtılmış izlemeler oluşturmayı başardınız ve Google Cloud Trace'te mikro hizmet genelindeki istek gecikmelerini onayladınız.

Daha kapsamlı alıştırmalar için aşağıdaki konuları kendi başınıza deneyebilirsiniz.

  • Mevcut uygulama, durum denetimi tarafından oluşturulan tüm kapsamları gönderir. (grpc.health.v1.Health/Check) Bu aralıkları Cloud Trace'lerden nasıl filtreleyebilirsiniz? İpucunu burada bulabilirsiniz.
  • Etkinlik günlüklerini aralıklarla ilişkilendirin ve Google Cloud Trace ile Google Cloud Logging'de nasıl çalıştığını görün. İpucunu burada bulabilirsiniz.
  • Bir hizmeti başka dildeki bir hizmetle değiştirin ve bu dili kullanarak OpenTelemetry ile izlemeye çalışın.

Ayrıca, bu işlemden sonra profiler hakkında bilgi edinmek isterseniz lütfen 2. bölüme geçin. Bu durumda aşağıdaki temizleme bölümünü atlayabilirsiniz.

Temizleme

Bu codelab'den sonra lütfen Kubernetes kümesini durdurun ve Google Kubernetes Engine, Google Cloud Trace, Google Artifact Registry'de beklenmedik ücretler almamak için projeyi sildiğinizden emin olun.

Öncelikle kümeyi silin. Küme skaffold dev ile çalışıyorsa Ctrl-C tuşlarına basmanız yeterlidir. Kümeyi skaffold run ile çalıştırıyorsanız aşağıdaki komutu çalıştırın:

skaffold delete

Komut çıkışı

Cleaning up...
 - deployment.apps "clientservice" deleted
 - service "clientservice" deleted
 - deployment.apps "loadgen" deleted
 - deployment.apps "serverservice" deleted
 - service "serverservice" deleted

Küme silindikten sonra menü bölmesinde "IAM ve Yönetici" > "Ayarlar"ı seçin ve ardından "KAPAT" düğmesini tıklayın.

45aa37b7d5e1ddd1.png

Ardından, iletişim kutusundaki forma proje kimliğini (proje adını değil) girin ve kapatma işlemini onaylayın.