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

1. Giriş

505827108874614d.png

Son Güncelleme: 15.07.2022

Uygulamanın gözlemlenebilirliği

Gözlemlenebilirlik ve OpenTelemetry

Gözlemlenebilirlik, bir sistemin özelliğini tanımlamak için kullanılan terimdir. Gözlemlenebilirliğe sahip bir sistem, ekiplerin sistemlerinde aktif olarak hata ayıklamalarına olanak tanır. Bu bağlamda, gözlemlenebilirliğin üç dayanağı olan günlükler, metrikler ve izler, sistemin gözlemlenebilirlik elde etmesi için temel araçlardır.

OpenTelemetry, gözlemlenebilirliğin gerektirdiği telemetri verilerinin (günlükler, metrikler ve izlemeler) enstrümantasyonunu ve dışa aktarımını hızlandıran bir dizi spesifikasyon, kitaplık ve aracıdır. OpenTelemetry, CNCF bünyesindeki açık standart ve topluluk odaklı bir projedir. Geliştiriciler, projenin ve ekosisteminin sağladığı kitaplıkları kullanarak uygulamalarını tedarikçi firmaya bağlı olmayan bir şekilde ve birden fazla mimariye göre enstrümante edebilir.

Ayrıca gözlemlenebilirliğin üç sütununa ek olarak sürekli profil oluşturma, gözlemlenebilirliğin başka bir önemli bileşenidir ve sektördeki kullanıcı tabanını genişletir. Cloud Profiler, bu tür araçların öncülerinden 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ünü oluşturur ve mikro hizmetlerde OpenTelemetry ve Cloud Trace ile dağıtılmış izlemeleri enstrümante etmeyi kapsar. 2. bölümde, Cloud Profiler ile sürekli profil oluşturma ele alınacaktır.

Dağıtılmış İz

Günlük, metrik ve iz arasında iz, sistemdeki sürecin belirli bir bölümünün gecikmesini belirten telemetridir. Özellikle mikro hizmetler çağında, dağıtılmış izleme, genel dağıtılmış sistemdeki gecikme darboğazlarını bulmak için güçlü bir itici güçtür.

Dağıtılmış izlekleri analiz ederken, genel sistem gecikmelerini bir bakışta anlamak için iz veri görselleştirmesi önemlidir. Dağıtılmış izlemede, sistem giriş noktasına yapılan tek bir isteği birden fazla Span içeren bir izleme biçiminde işlemek için bir dizi çağrıyı ele alırız.

Aralık, dağıtılmış bir sistemde yapılan tek bir çalışma birimini temsil eder ve başlangıç ile bitiş zamanlarını kaydeder. Aralıklar genellikle aralarında hiyerarşik ilişkilere sahiptir. Aşağıdaki resimde, tüm küçük aralıklar büyük bir /messages aralığının alt aralıklarıdır ve bir sistemdeki çalışmanın yolunu gösteren tek bir izlemeye birleştirilmiştir.

Bir iz

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

Oluşturacağınız uygulama

Bu codelab'de, bir Google Kubernetes Engine kümesinde çalışan "Shakespeare uygulaması" (diğer adıyla Shakesapp) adlı hizmetlerde bilgi izlemeyi kullanacaksınız. Shakesapp'in mimarisi aşağıda açıklandığı gibidir:

44e243182ced442f.png

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

İstekte izleme bilgilerini donanıma eklersiniz. Ardından, sunucuya bir profilleyici aracı yerleştirir ve darboğazları araştırırsınız.

Neler öğreneceksiniz?

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

Bu codelab'de, mikro hizmetlerinizi nasıl enstrümante edeceğiniz açıklanmaktadır. Anlaşılmasını kolaylaştırmak için bu örnekte yalnızca 3 bileşen (yük oluşturucu, istemci ve sunucu) bulunmaktadır ancak bu kod laboratuvarındaki süreci daha karmaşık ve büyük sistemlere de uygulayabilirsiniz.

Gerekenler

  • Go hakkında temel düzeyde bilgi
  • Kubernetes hakkında temel düzeyde bilgi

2. Kurulum ve Gereksinimler

Kendine ait tempoda 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çim açılır menüsünü tıklayın:

7a32e5469db69e9.png

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

7136b3ee36ebaf89.png

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

870a3cbd6541ee86.png

Ardından açılan proje oluşturma iletişim kutusunda yeni projenizin ayrıntılarını girebilirsiniz:

affdc444517ba805.png

Tüm Google Cloud projeleri genelinde benzersiz bir ad olan proje kimliğini unutmayın (yukarıdaki ad zaten alınmış ve kullanılamıyor, özür dileriz). Bu codelab'de daha sonra PROJECT_ID olarak anılacaktır.

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

15d0ef27a8fbab27.png

Bu kod laboratuvarını çalıştırmak birkaç dolardan fazlaya mal olmaz ancak daha fazla kaynak kullanmaya karar verirseniz veya kaynakları çalışır durumda bırakırsanız maliyet daha yüksek olabilir (bu dokümanın sonundaki "temizlik" bölümüne bakın). Google Cloud Trace, Google Kubernetes Engine ve Google Artifact Registry'nin fiyatları resmi dokümanda belirtilmiştir.

Google Cloud Platform'un yeni kullanıcıları 300 ABD doları değerinde ücretsiz deneme sürümü için uygundur. Bu sayede bu kod laboratuvarını tamamen ücretsiz kullanabilirsiniz.

Google Cloud Shell Kurulumu

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

Debian tabanlı bu sanal makinede ihtiyaç duyacağınız tüm geliştirme araçları yüklüdür. 5 GB boyutunda kalıcı bir ana dizin sunar ve Google Cloud'da çalışır. Bu sayede ağ performansını ve kimlik doğrulamayı büyük ölçüde iyileştirir. Bu, bu codelab için tek ihtiyacınız olan şeyin bir tarayıcı olduğu anlamına gelir (evet, Chromebook'ta ç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 sağlanıp bağlantı kurulabilmesi için birkaç dakika beklemeniz gerekir).

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 olarak 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 aşağıdaki komutu vermeniz yeterlidir:

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, bazı ortam değişkenlerini varsayılan olarak da ayarlar. Bu değişkenler, gelecekte komut çalıştırırken faydalı olabilir.

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 farklı bölgeler seçebilirsiniz. Daha fazla bilgi için Bölgeler ve Alt Bölgeler başlıklı makaleyi inceleyin.

Dil ayarlarına gitme

Bu kod laboratuvarındaki tüm kaynak kodlarda 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 sonraki bir sürüm olup olmadığını onaylayın.

go version

Komut çıkışı

go version go1.18.3 linux/amd64

Google Kubernetes kümesi oluşturma

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

  1. Referans projesini Cloud Shell'e indirme
  2. Mikro hizmetleri kapsayıcılara derleme
  3. Container'ları Google Artifact Registry'ye (GAR) yükleme
  4. Container'ları GKE'ye dağıtma
  5. İzleme enstrümasyonu 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ışacağı bir Kubernetes kümesi oluşturduk. 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 Artifact Registry deposu oluşturmak için kullanacağınız bölge değerinin bölgenin altında olduğunu onaylayın. Depo bölgeniz bölgeyi kapsamıyorsa bölge değerini us-central1-f 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ı yüklemek ve dağıtmak için bir kapsayıcı kayıt otoritesi oluşturmaya hazırlanırız. Bu adımlar için bir Artifact Registry (GAR) oluşturmamız ve bunu kullanmak için skaffold'u kurmamız gerekir.

Artifact Registry kurulumu

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

45e384b87f7cf0db.png

Birkaç dakika sonra GAR'ın depo tarayıcısını görürsünüz. "DEPOLAMA ALANI OLUŞTUR" düğmesini tıklayın ve depolama alanının adını girin.

d6a70f4cb4ebcbe3.png

Bu kod laboratuvarındaki yeni depoya trace-codelab adını veriyorum. Yapının biçimi "Docker", konum türü ise "Bölge"dir. Google Compute Engine varsayılan bölgesi için ayarladığınız bölgeye yakın bir bölge seçin. Örneğin, bu örnekte yukarıda "us-central1-f" seçilmiştir. Bu nedenle burada "us-central1 (Iowa)"yı seçiyoruz. Ardından "OLUŞTUR" düğmesini tıklayın.

9c2d1ce65258ef70.png

Artık depo tarayıcısında "trace-codelab" ifadesini görürsünüz.

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şturmaya çalışırken kullanabileceğiniz kullanışlı bir araçtır. Küçük bir komut grubuyla uygulama kapsayıcıları oluşturma, yayınlama ve dağıtma iş akışını yönetir. Skaffold varsayılan olarak container kayıt defteri olarak Docker Registry'yi kullanır. Bu nedenle, skaffold'u, container'ları gönderirken GAR'ı tanıyacak şekilde yapılandırmanız gerekir.

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

skaffold version

Komut çıkışı

v1.38.0

Artık skaffold'un kullanacağı varsayılan depoyu kaydedebilirsiniz. Kayıt defteri yolunu 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 kutusunu 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 ç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 ayarlamanı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
  • Kapsayıcı kayıt defteri için bir Artifact Registry deposu oluşturuldu
  • skaffold'u, Container Registry'yi kullanacak şekilde ayarlama
  • Codelab mikro hizmetlerinin çalıştığı bir Kubernetes kümesi oluşturma

Sonraki bölüm

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

3. Mikro hizmetleri derleme, yayınlama ve dağıtma

Codelab materyalini indirin

Önceki adımda, bu kod laboratuvarının tüm ön koşullarını ayarladık. Artık bunların üzerinde tüm mikro hizmetleri çalıştırmaya hazırsınız. Codelab materyali GitHub'da barındırılır. Bu nedenle, aşağıdaki git komutunu kullanarak materyali Cloud Shell 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: istemci ile sunucu arasındaki iletişim için proto tanımı
  • src: Her hizmetin kaynak kodunun bulunduğu dizinler
  • skaffold.yaml: Skaffold için yapılandırma dosyası

Bu codelab'de, step0 klasöründe bulunan kaynak kodu güncelleyeceksiniz. Aşağıdaki adımlardaki yanıtlar için step[1-6] klasörlerindeki kaynak koda da bakabilirsiniz. (1. Bölüm 0 ile 4 arasındaki adımları, 2. Bölüm ise 5 ve 6. adımları kapsar)

Skaffold komutunu çalıştırma

Artık içeriğin tamamını derleyip yeni oluşturduğunuz Kubernetes kümesine aktarmaya ve dağıtmaya hazırsınız. Bu işlem birden fazla adımdan oluşsa da skaffold her şeyi sizin için yapar. Bunu aşağıdaki komutla deneyelim:

cd step0
skaffold dev

Komutu çalıştırır çalıştırmaz docker build dosyasının günlük çıkışını görürsünüz ve dosyaları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ı yayınlandıktan 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 aşağıdaki gibi 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, artık hizmetlerin dağıtık izlemesi için uygulamanızı OpenTelemetry ile enstrümante etmeye hazırsınız.

Hizmeti enstrümante etmeye 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, codelab materyalini ortamınızda hazırladınız ve skaffold'un beklendiği gibi çalıştığını doğruladınız.

Sonraki bölüm

Bir sonraki adımda, izleme bilgilerini gösterecek şekilde loadgen hizmetinin kaynak kodunu değiştireceksiniz.

4. HTTP için araçlar

İzleme aracı ve yayma kavramı

Kaynak kodunu düzenlemeden önce, dağıtılmış izlemelerin işleyiş şeklini basit bir şema üzerinden kısaca açıklayayım.

6be42e353b9bfd1d.png

Bu örnekte, kodu, Trace ve Span bilgilerini Cloud Trace'e aktaracak ve iz bağlamını loadgen hizmetinden sunucu hizmetine istek boyunca dağıtacak şekilde donatıyoruz.

Cloud Trace'in aynı Trace kimliğine sahip tüm aralıklarını tek bir izde toplayabilmesi için uygulamaların Trace kimliği ve Aralık kimliği gibi Trace meta verilerini göndermesi gerekir. Ayrıca, uygulamanın hangi izleme bağlamını işlediğini bilebilmek için istek gönderen alt hizmetlere izleme bağlamlarını (üst aralığın izleme kimliği ve aralığı kimliğinin birleşimi) yayması gerekir.

OpenTelemetry şunları yapmanıza yardımcı olur:

  • benzersiz Trace-ID ve Span-ID oluşturmak için
  • Trace-ID ve Span-ID'yi arka uca aktarmak için
  • izleme bağlamlarını diğer hizmetlere yaymak için
  • İzleri analiz etmeye yardımcı olacak ek meta veriler eklemek için

OpenTelemetry İzinde Bileşenler

b01f7bb90188db0d.png

Uygulama izlemeyi OpenTelemetry ile enstrümante etme işlemi aşağıdaki gibidir:

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

Şu anda her bileşendeki ayrıntılı özellikleri anlamanız gerekmiyor ancak şu noktaları hatırlamanız önemlidir:

  • Buradaki dışa aktarıcı, TracerProvider'a takılabilir.
  • TracerProvider, izleme örnekleme ve dışa aktarma ile ilgili tüm yapılandırmaları barındırır.
  • Tüm izler Tracer nesnesinde gruplandırılır

Bu bilgiler ışığında, asıl kodlama işlemine geçelim.

Enstrüman ilk aralığı

Araç 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. Sol bölmede bulunan gezginden step0/src/loadgen/main.go'ü 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, run işlevini çağıran döngüyü görürsünüz. Mevcut uygulamada, bölümde işlev çağrısının başlangıcını ve sonunu kaydeden 2 günlük satırı vardır. Şimdi, işlev çağrısının gecikmesini izlemek için Span bilgilerini kaydedelim.

Öncelikle, önceki bölümde belirtildiği gibi OpenTelemetry için tüm yapılandırmaları 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
)

Okunabilirlik için initTracer adlı bir kurulum işlevi oluşturup main işlevinde çağırıyoruz.

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ış biçimde stdout'a aktaran bir stdout dışa aktarıcı kullanıyoruz.

Ardından, ana işlevden çağırırsınız. initTracer() numaralı telefonu arayın ve uygulamayı kapatırken TracerProvider.Shutdown() numaralı telefonu arayın.

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 Span kimliği içeren bir Span oluşturmanız gerekir. OpenTelemetry bunun için kullanışlı bir kitaplık sağlar. Araç 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 ve otelhttp paketinin uzantısını kullanarak enstrümantasyonu etkinleştiririz.

Öncelikle, HTTP isteklerini enstrümante edilmiş istemci aracılığıyla çağırmak için httpClient adlı bir paket genel değişkeni ekleyin.

step0/src/loadgen/main.go

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

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

  1. otel.Tracer() ile global TracerProvider'den izleyici alma
  2. Tracer.Start() yöntemiyle kök aralığı oluşturma
  3. Kök aralığı isteğe bağlı bir zamanlamada sonlandırın (bu durumda, 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 loadgen'deki (HTTP istemci uygulaması) enstrümantasyon işlemini tamamladınız. Lütfen go.mod ve go.sum alanlarınızı go mod komutuyla güncellediğinizden emin olun.

go mod tidy

Araç müşteri hizmetleri

Önceki bölümde, aşağıdaki çizimde kırmızı dikdörtgenle çevrili olan kısmı enstrümante ettik. Yük oluşturucu hizmetinde span bilgilerini enstrümante ettik. Yük oluşturucu hizmete benzer şekilde, istemci hizmetini de enstrümante etmemiz gerekir. Yük oluşturucu hizmetinden farkı, istemci hizmetinin HTTP üstbilgisinde yük oluşturucu hizmetinden yayılan Trace-ID bilgilerini çıkarması ve Span oluşturmak için bu kimliği kullanması gerektiğidir.

bcaccd06691269f8.png

Cloud Shell Düzenleyici'yi açın ve yük oluşturucu hizmeti için 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
)

OpenTelemtry'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 aralıklara alet ekleme zamanı. Müşteri hizmetinin, loadgen hizmetinden gelen HTTP isteklerini kabul etmesi gerektiğinden işleyiciyi donatması 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 İşleyici ile 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ığı enstrümante ederiz. func (*clientService) handler() işlevini bulun ve trace.SpanFromContext() ile span 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ümantasyonla, handler yönteminin başından sonuna kadar olan aralıkları alırsınız. Aralıkların analiz edilmesini kolaylaştırmak için eşleşen sayıyı depolayan ek bir özellik ekleyin. Günlük satırının hemen önüne 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, loadgen ile istemci arasındaki izleme enstrümantasyonunu tamamladınız. Bunun nasıl çalıştığına bakalım. Kodu skaffold ile tekrar çalıştırın.

skaffold dev

Hizmetler GKE kümesinde çalıştırıldıktan bir süre 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"
...

stdout dışa aktarıcısı bu iletileri yayınlar. loadgen tarafından oluşturulan tüm aralıkların üst öğelerinin TraceID: 00000000000000000000000000000000 değerine sahip olduğunu göreceksiniz. Bunun nedeni, kök aralığın (yani izlemedeki ilk aralığın) bu olmasıdır. Ayrıca, "query" yerleştirme özelliğinin müşteri hizmetine iletilen sorgu dizesini içerdiğini 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 ve izleme bağlamını hizmetler arasında başarılı bir şekilde dağıtabileceğinizi ve her iki hizmetten de Span bilgilerini stdout'a aktarabileceğinizi doğruladınız.

Sonraki bölüm

Sonraki adımda, gRPC üzerinden izleme bağlamının nasıl dağıtılacağını doğrulamak için istemci hizmetini ve sunucu hizmetini donatacaksınız.

5. gRPC için araçlar

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

75310d8e0e3b1a30.png

gRPC istemcisi için ön derleme enstrümantasyonu

OpenTelemetry'nin ekosistemi, geliştiricilerin uygulamaları enstrümante etmesine yardımcı olacak birçok kullanışlı kitaplık sunar. Önceki adımda, net/http paketi için derleme öncesi enstrümantasyon kullandık. Bu adımda, Trace Context'i gRPC üzerinden yaymaya çalıştığımız için kitaplığı kullanırız.

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

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 sefer istemci hizmeti, sunucu hizmetine karşı bir gRPC istemcisidir. Bu nedenle, gRPC istemcisini donatmanız gerekir. mustConnGRPC işlevini bulun ve istemci sunucuya her istek gönderdiğinde yeni kapsamlar oluşturan gRPC müdahalecileri 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))
        }
}

OpenTelemetry'yi önceki bölümde zaten ayarladığınız için bunu yapmanı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"
)

Sunucu ilk kez araçlandırıldığı için loadgen ve istemci hizmetleri için yaptığımıza benzer şekilde önce OpenTelemetry'yi ayarlamanız gerekir.

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 müdahalecileri eklemeniz gerekir. main işlevinde, grpc.NewServer() işlevinin çağrıldığı yeri bulun ve işleve müdahaleciler 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ştirilmiş kodunuzu skaffold komutuyla çalıştırın.

skaffold dev

Şimdi yine stdout'da bir sürü 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] }
...

Herhangi bir span adı yerleştirmediğinizi ve trace.Start() veya span.SpanFromContext() ile manuel olarak span oluşturduğunuzu fark edersiniz. gRPC müdahalecileri tarafından oluşturuldukları için yine çok sayıda span alırsınız.

Özet

Bu adımda, OpenTelemetry ekosistem kitaplıklarının desteğiyle gRPC tabanlı iletişimi araçlandırdınız.

Sonraki bölüm

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

6. Cloud Trace ile izlemeyi görselleştirme

OpenTelemetry ile sistemin tamamında iz eklediniz. Şu ana kadar HTTP ve gRPC hizmetlerini nasıl enstrümante edeceğinizi öğrendiniz. Bu metrikleri nasıl ölçeceğinizi öğrendiniz ancak 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 takılabilir olmasıdır. Enstrümantasyonunuz tarafından toplanan tüm aralıkları görselleştirmek için stdout dışa aktarıcısını Cloud Trace dışa aktarıcısıyla değiştirmeniz yeterlidir.

Her hizmetin main.go dosyalarını açın ve initTracer() işlevini bulun. stdout dışa aktarıcısı oluşturmak için satırı silin ve bunun yerine Cloud Trace dışa aktarıcısı 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 skaffold komutuyla normal şekilde çalıştırmanız yeterlidir.

skaffold dev

Ardından, dışa aktarıcıyı Cloud Trace ile değiştirdiğiniz için stdout'da yapılandırılmış günlükler biçiminde çok fazla ara bilgi 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 aralıkları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şebilirsiniz. Aksi takdirde, sol bölmede menüyü tıklayabilirsiniz. 8b3f8411bd737e06.png

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

3ecf131423fc4c40.png

Bunlardan birini tıkladığınızda izlemenin ayrıntılarını görebilirsiniz. 4fd10960c6648a03.png

Bu basit ve hızlı bir bakışta bile birçok analiz hakkında bilgi sahibi olabilirsiniz. Örneğin, şelale grafiğinde gecikmenin çoğunlukla shakesapp.ShakespeareService/GetMatchCount adlı aralığa bağlı olduğunu görebilirsiniz. (Yukarıdaki resimde 1 numaralı yere bakın.) Bunu özet tablosundan onaylayabilirsiniz. (En sağdaki sütunda her aralığın süresi gösterilir.) Ayrıca bu izleme, "arkadaş" sorgusu içindi. (Yukarıdaki resimde 2'ye bakın)

Bu kısa analizler göz önüne alındığında, GetMatchCount yönteminde daha ayrıntılı aralıklar hakkında bilgi sahibi olmanız gerektiğini fark edebilirsiniz. Görselleştirme, stdout bilgilerine kıyasla güçlüdür. Cloud Trace ayrıntıları hakkında daha fazla bilgi edinmek için lütfen resmi dokümanlarımızı inceleyin.

Özet

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

Sonraki bölüm

Sonraki adımda, GetMatchCount işlevine bir alt span eklemek için sunucu hizmetinin kaynak kodunu değiştireceksiniz.

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

Önceki adımda, loadgen'den gözlemlenen gidiş dönüş süresinin nedeninin çoğunlukla sunucu hizmetindeki GetMatchCount yöntemi içindeki işlem (gRPC işleyicisi) olduğunu tespit etmiştiniz. Ancak işleyici dışında bir şeye enstrüman eklemediğimiz için şelale grafiğinden başka analizler elde edemiyoruz. Bu durum, mikro hizmetlere ölçüm eklemeye başladığımızda sık karşılaşılan bir durumdur.

3b63a1e471dddb8c.png

Bu bölümde, sunucunun Google Cloud Storage'ı çağırdığı bir alt aralığı göstereceğiz. Bunun nedeni, bazı harici ağ I/O'larının işlemde uzun zaman almasının yaygın olması ve bunun nedeninin çağrı olup olmadığını belirlemenin önemli olmasıdır.

Sunucuda alt aralığı ayarlama

Sunucuda main.go dosyasını açın ve readFiles işlevini bulun. Bu işlev, Shakespeare eserlerinin tüm metin dosyalarını almak için Google Cloud Storage'a bir istek gönderir. Bu işlevde, istemci hizmetinde HTTP sunucusu enstrümantasyonu için yaptığınız gibi bir alt span 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 span eklemeyle ilgili tüm bilgiler bu kadar. Uygulamayı çalıştırarak nasıl sonuç alacağınıza bakalım.

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

Düzenlemeden sonra kümeyi skaffold komutuyla normal şekilde çalıştırmanız yeterlidir.

skaffold dev

İzleme listesinden query.request adlı bir izleme seçin. shakesapp.ShakespeareService/GetMatchCount altında yeni bir aralığın bulunması 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, Google Cloud Storage'a yapılan harici çağrının büyük miktarda gecikmeye neden olduğu ancak gecikmenin büyük bir kısmının başka kaynaklardan kaynaklandığı sonucunu çıkarabilirsiniz.

Henüz yalnızca birkaç kez izleyici akış şelalesi grafiğini inceleyerek çok sayıda analiz elde ettiniz. Uygulamanızdaki diğer performans ayrıntılarını nasıl elde edersiniz? Bu noktada profilleyici devreye girer. Ancak şimdilik bu codelab'in sonuna gelelim ve tüm profilleyici eğitimlerini 2. bölüme bırakalım.

Özet

Bu adımda, sunucu hizmetinde başka bir span eklediniz ve sistem gecikmesi hakkında daha fazla analiz elde ettiniz.

8. Tebrikler

OpenTelemery ile dağıtılmış izlemeler oluşturdunuz ve Google Cloud Trace'te mikro hizmet genelinde istek gecikmeleri olduğunu doğruladınız.

Daha uzun alıştırmalar için aşağıdaki konuları kendiniz deneyebilirsiniz.

  • Mevcut uygulama, durum denetimi tarafından oluşturulan tüm aralıkları gönderir. (grpc.health.v1.Health/Check) Bu aralıkları Cloud Trace'lerden nasıl filtrelersiniz? İpucu burada.
  • Etkinlik günlüklerini kapsamlarla ilişkilendirin ve Google Cloud Trace ile Google Cloud Logging'da nasıl çalıştığını öğrenin. İpucu burada.
  • Bazı hizmetleri başka bir dilde olan hizmetlerle değiştirin ve bu dil için OpenTelemetry ile enstrümante etmeye çalışın.

Ayrıca, bu bölümden sonra profilleyici 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 kod laboratuvarından sonra, Google Kubernetes Engine, Google Cloud Trace ve Google Artifact Registry'de beklenmedik ücretler ödememek için lütfen Kubernetes kümesini durdurun ve projeyi sildiğinizden emin olun.

Öncelikle kümeyi silin. Kümeyi skaffold dev ile çalıştırıyorsanız 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ümeyi sildikten sonra menü bölmesinde "IAM ve Yönetici" > "Ayarlar"ı seçin ve ardından "KAPATIN" 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.