Instrumen untuk performa yang lebih baik di aplikasi Anda di Go (bagian 1: rekaman aktivitas)

1. Pengantar

505827108874614d.png

Terakhir Diperbarui: 15-07-2022

Kemampuan observasi aplikasi

Kemampuan observasi dan OpenTelemetry

Kemampuan observasi adalah istilah yang digunakan untuk mendeskripsikan atribut sistem. Sistem dengan kemampuan observasi memungkinkan tim men-debug sistem mereka secara aktif. Dalam konteks tersebut, tiga pilar observabilitas, yaitu log, metrik, dan rekaman aktivitas, adalah instrumentasi mendasar bagi sistem untuk mendapatkan observabilitas.

OpenTelemetry adalah serangkaian spesifikasi, library, dan agen yang mempercepat instrumentasi dan ekspor data telemetri (log, metrik, dan trace) yang diperlukan untuk kemampuan observasi. OpenTelemetry adalah project yang didorong komunitas dan standar terbuka di bawah CNCF. Dengan memanfaatkan library yang disediakan project dan ekosistemnya, developer dapat menginstrumentasikan aplikasi mereka dengan cara yang netral terhadap vendor dan terhadap beberapa arsitektur.

Selain tiga pilar kemampuan pengamatan, pembuatan profil berkelanjutan juga merupakan komponen utama lainnya untuk kemampuan pengamatan dan memperluas basis pengguna di industri. Cloud Profiler adalah salah satu pemrakarsa dan menyediakan antarmuka yang mudah untuk melihat perincian metrik performa di stack panggilan aplikasi.

Codelab ini adalah bagian 1 dari seri dan membahas cara menginstrumentasikan trace terdistribusi di microservice dengan OpenTelemetry dan Cloud Trace. Bagian 2 akan membahas pembuatan profil berkelanjutan dengan Cloud Profiler.

Distributed Trace

Di antara log, metrik, dan rekaman aktivitas, rekaman aktivitas adalah telemetri yang menunjukkan latensi bagian tertentu dari proses dalam sistem. Terutama di era microservice, pelacakan terdistribusi adalah pendorong yang kuat untuk mengetahui hambatan latensi dalam sistem terdistribusi secara keseluruhan.

Saat menganalisis trace terdistribusi, visualisasi data trace adalah kunci untuk memahami latensi sistem secara keseluruhan dalam sekejap. Dalam pelacakan terdistribusi, kami menangani serangkaian panggilan untuk memproses satu permintaan ke titik entri sistem dalam bentuk Pelacakan yang berisi beberapa Rentang.

Rentang mewakili setiap unit pekerjaan yang dilakukan dalam sistem terdistribusi, yang mencatat waktu mulai dan berhenti. Rentang sering kali memiliki hubungan hierarkis satu sama lain - dalam gambar di bawah, semua rentang yang lebih kecil adalah rentang turunan dari rentang /messages yang besar, dan dikumpulkan menjadi satu Rekaman Aktivitas yang menunjukkan jalur kerja melalui sistem.

Rekaman aktivitas

Google Cloud Trace adalah salah satu opsi untuk backend pelacakan terdistribusi dan terintegrasi dengan baik dengan produk lain di Google Cloud.

Yang akan Anda bangun

Dalam codelab ini, Anda akan mengumpulkan informasi rekaman aktivitas di layanan yang disebut "aplikasi Shakespeare" (alias Shakesapp) yang berjalan di cluster Google Kubernetes Engine. Arsitektur Shakesapp adalah seperti yang dijelaskan di bawah ini:

44e243182ced442f.png

  • Loadgen mengirimkan string kueri ke klien dalam HTTP
  • Klien meneruskan kueri dari loadgen ke server di gRPC
  • Server menerima kueri dari klien, mengambil semua karya Shakespeare dalam format teks dari Google Cloud Storage, menelusuri baris yang berisi kueri, dan menampilkan nomor baris yang cocok kepada klien

Anda akan menginstrumentasi informasi rekaman aktivitas di seluruh permintaan. Setelah itu, Anda akan menyematkan agen profiler di server dan menyelidiki hambatan.

Yang akan Anda pelajari

  • Cara mulai menggunakan library Trace OpenTelemetry di project Go
  • Cara membuat rentang dengan library
  • Cara menyebarkan konteks rentang melalui jaringan antara komponen aplikasi
  • Cara mengirim data trace ke Cloud Trace
  • Cara menganalisis rekaman aktivitas di Cloud Trace

Codelab ini menjelaskan cara menginstrumentasi microservice Anda. Agar mudah dipahami, contoh ini hanya berisi 3 komponen (generator beban, klien, dan server), tetapi Anda dapat menerapkan proses yang sama yang dijelaskan dalam codelab ini ke sistem yang lebih kompleks dan besar.

Yang Anda butuhkan

  • Pengetahuan dasar tentang Go
  • Pengetahuan dasar tentang Kubernetes

2. Penyiapan dan Persyaratan

Penyiapan lingkungan mandiri

Jika belum memiliki Akun Google (Gmail atau Google Apps), Anda harus membuatnya. Login ke Google Cloud Platform console (console.cloud.google.com) dan buat project baru.

Jika Anda sudah memiliki project, klik menu pull-down pilihan project di kiri atas konsol:

7a32e5469db69e9.png

dan klik tombol 'PROJECT BARU' dalam dialog yang dihasilkan untuk membuat project baru:

7136b3ee36ebaf89.png

Jika belum memiliki project, Anda akan melihat dialog seperti ini untuk membuat project pertama:

870a3cbd6541ee86.png

Dialog pembuatan project berikutnya memungkinkan Anda memasukkan detail project baru:

affdc444517ba805.png

Ingat project ID yang merupakan nama unik di semua project Google Cloud (maaf, nama di atas telah digunakan dan tidak akan berfungsi untuk Anda!) Project ID tersebut selanjutnya akan dirujuk di codelab ini sebagai PROJECT_ID.

Selanjutnya, jika Anda belum melakukannya, Anda harus mengaktifkan penagihan di Developers Console untuk menggunakan resource Google Cloud dan mengaktifkan Cloud Trace API.

15d0ef27a8fbab27.png

Menjalankan melalui codelab ini tidak akan menghabiskan biaya lebih dari beberapa dolar, tetapi bisa lebih jika Anda memutuskan untuk menggunakan lebih banyak resource atau jika Anda membiarkannya berjalan (lihat bagian "pembersihan" di akhir dokumen ini). Harga Google Cloud Trace, Google Kubernetes Engine, dan Google Artifact Registry tercantum dalam dokumentasi resmi.

Pengguna baru Google Cloud Platform memenuhi syarat untuk mendapatkan uji coba gratis senilai $300, yang menjadikan codelab ini sepenuhnya gratis.

Penyiapan Google Cloud Shell

Meskipun Google Cloud dan Google Cloud Trace dapat dioperasikan dari jarak jauh menggunakan laptop Anda, dalam codelab ini, kita akan menggunakan Google Cloud Shell, lingkungan command line yang berjalan di Cloud.

Mesin virtual berbasis Debian ini memuat semua alat pengembangan yang akan Anda perlukan. Layanan ini menawarkan direktori beranda tetap sebesar 5 GB dan beroperasi di Google Cloud, sehingga sangat meningkatkan performa dan autentikasi jaringan. Ini berarti bahwa semua yang Anda perlukan untuk codelab ini adalah browser (ya, ini berfungsi di Chromebook).

Untuk mengaktifkan Cloud Shell dari Cloud Console, cukup klik Aktifkan Cloud Shell gcLMt5IuEcJJNnMId-Bcz3sxCd0rZn7IzT_r95C8UZeqML68Y1efBG_B0VRp7hc7qiZTLAF-TXD7SsOadxn8uadgHhaLeASnVS3ZHK39eOlKJOgj9SJua_oeGhMxRrbOg3qigddS2A (hanya perlu beberapa saat untuk melakukan penyediaan dan terhubung ke lingkungan).

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

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

Setelah terhubung ke Cloud Shell, Anda akan melihat bahwa Anda sudah diautentikasi dan project sudah ditetapkan ke PROJECT_ID.

gcloud auth list

Output perintah

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

Output perintah

[core]
project = <PROJECT_ID>

Jika, untuk beberapa alasan, project belum disetel, cukup jalankan perintah berikut:

gcloud config set project <PROJECT_ID>

Mencari PROJECT_ID Anda? Periksa ID yang Anda gunakan di langkah-langkah penyiapan atau cari di dasbor Cloud Console:

158fNPfwSxsFqz9YbtJVZes8viTS3d1bV4CVhij3XPxuzVFOtTObnwsphlm6lYGmgdMFwBJtc-FaLrZU7XHAg_ZYoCrgombMRR3h-eolLPcvO351c5iBv506B3ZwghZoiRg6cz23Qw

Cloud Shell juga menetapkan beberapa variabel lingkungan secara default, yang mungkin berguna saat Anda menjalankan perintah di masa mendatang.

echo $GOOGLE_CLOUD_PROJECT

Output perintah

<PROJECT_ID>

Terakhir, tetapkan zona dan konfigurasi project default.

gcloud config set compute/zone us-central1-f

Anda dapat memilih berbagai zona yang berbeda. Untuk informasi selengkapnya, lihat Region & Zona.

Penyiapan bahasa Go

Dalam codelab ini, kita menggunakan Go untuk semua kode sumber. Jalankan perintah berikut di Cloud Shell dan konfirmasi apakah versi Go adalah 1.17+

go version

Output perintah

go version go1.18.3 linux/amd64

Menyiapkan Cluster Google Kubernetes

Dalam codelab ini, Anda akan menjalankan cluster microservice di Google Kubernetes Engine (GKE). Proses codelab ini adalah sebagai berikut:

  1. Download project dasar ke Cloud Shell
  2. Membangun microservice ke dalam container
  3. Mengupload container ke Google Artifact Registry (GAR)
  4. Men-deploy container ke GKE
  5. Ubah kode sumber layanan untuk instrumentasi pelacakan
  6. Lanjutkan ke langkah 2

Aktifkan Kubernetes Engine

Pertama, kita menyiapkan cluster Kubernetes tempat Shakesapp berjalan di GKE, jadi kita perlu mengaktifkan GKE. Buka menu "Kubernetes Engine" dan tekan tombol AKTIFKAN.

548cfd95bc6d344d.png

Sekarang Anda siap membuat cluster Kubernetes.

Membuat cluster Kubernetes

Di Cloud Shell, jalankan perintah berikut untuk membuat cluster Kubernetes. Pastikan nilai zona berada di bawah region yang akan Anda gunakan untuk pembuatan repositori Artifact Registry. Ubah nilai zona us-central1-f jika region repositori Anda tidak mencakup zona tersebut.

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

Output perintah

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

Penyiapan Artifact Registry dan skaffold

Sekarang kita memiliki cluster Kubernetes yang siap untuk deployment. Selanjutnya, kita menyiapkan container registry untuk mengirim dan men-deploy container. Untuk langkah-langkah ini, kita perlu menyiapkan Artifact Registry (GAR) dan skaffold untuk menggunakannya.

Penyiapan Artifact Registry

Buka menu "Artifact Registry" dan tekan tombol AKTIFKAN.

45e384b87f7cf0db.png

Setelah beberapa saat, Anda akan melihat browser repositori GAR. Klik tombol "CREATE REPOSITORY" dan masukkan nama repositori.

d6a70f4cb4ebcbe3.png

Dalam codelab ini, saya menamai repositori baru dengan trace-codelab. Format artefak adalah "Docker" dan jenis lokasi adalah "Region". Pilih region yang dekat dengan region yang Anda tetapkan untuk zona default Google Compute Engine. Misalnya, contoh ini memilih "us-central1-f" di atas, jadi di sini kita memilih "us-central1 (Iowa)". Kemudian, klik tombol "BUAT".

9c2d1ce65258ef70.png

Sekarang Anda melihat "trace-codelab" di browser repositori.

7a3c1f47346bea15.png

Kita akan kembali ke sini nanti untuk memeriksa jalur registri.

Penyiapan Skaffold

Skaffold adalah alat praktis saat Anda mengerjakan pembangunan microservice yang berjalan di Kubernetes. Alat ini menangani alur kerja pembuatan, pengiriman, dan deployment container aplikasi dengan serangkaian kecil perintah. Secara default, Skaffold menggunakan Docker Registry sebagai registry container, jadi Anda perlu mengonfigurasi Skaffold agar mengenali GAR saat mengirim container ke.

Buka kembali Cloud Shell dan konfirmasi apakah skaffold sudah diinstal. (Cloud Shell menginstal skaffold ke lingkungan secara default.) Jalankan perintah berikut dan lihat versi skaffold.

skaffold version

Output perintah

v1.38.0

Sekarang, Anda dapat mendaftarkan repositori default untuk digunakan skaffold. Untuk mendapatkan jalur registri, buka dasbor Artifact Registry dan klik nama repositori yang baru saja Anda siapkan di langkah sebelumnya.

7a3c1f47346bea15.png

Kemudian, Anda akan melihat jejak breadcrumb di bagian atas halaman. Klik ikon e157b1359c3edc06.png untuk menyalin jalur registri ke papan klip.

e0f2ae2144880b8b.png

Saat mengklik tombol salin, Anda akan melihat dialog di bagian bawah browser dengan pesan seperti:

"us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab" telah disalin

Kembali ke cloud shell. Jalankan perintah skaffold config set default-repo dengan nilai yang baru saja Anda salin dari dasbor.

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

Output perintah

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

Selain itu, Anda perlu mengonfigurasi registry ke konfigurasi Docker. Jalankan perintah berikut:

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

Output perintah

{
  "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

Sekarang Anda siap melanjutkan ke langkah berikutnya untuk menyiapkan container Kubernetes di GKE.

Ringkasan

Pada langkah ini, Anda akan menyiapkan lingkungan codelab:

  • Menyiapkan Cloud Shell
  • Membuat repositori Artifact Registry untuk registry container
  • Menyiapkan Skaffold untuk menggunakan container registry
  • Membuat cluster Kubernetes tempat microservice codelab berjalan

Berikutnya

Pada langkah berikutnya, Anda akan mem-build, mengirim, dan men-deploy microservice ke cluster

3. Membangun, mengirim, dan men-deploy microservice

Download materi codelab

Pada langkah sebelumnya, kita telah menyiapkan semua prasyarat untuk codelab ini. Sekarang Anda siap menjalankan seluruh microservice di atasnya. Materi codelab dihosting di GitHub, jadi download ke lingkungan Cloud Shell dengan perintah git berikut.

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

Struktur direktori project adalah sebagai berikut:

.
├── 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
  • manifes: File manifes Kubernetes
  • proto: definisi proto untuk komunikasi antara klien dan server
  • src: direktori untuk kode sumber setiap layanan
  • skaffold.yaml: File konfigurasi untuk skaffold

Dalam codelab ini, Anda akan memperbarui kode sumber yang ada di folder step0. Anda juga dapat melihat kode sumber di folder step[1-6] untuk mendapatkan jawaban pada langkah-langkah berikut. (Bagian 1 mencakup langkah 0 hingga langkah 4, dan Bagian 2 mencakup langkah 5 dan 6)

Jalankan perintah skaffold

Terakhir, Anda siap membangun, mengirim, dan men-deploy seluruh konten ke cluster Kubernetes yang baru saja Anda buat. Tampaknya ada beberapa langkah, tetapi sebenarnya skaffold melakukan semuanya untuk Anda. Mari kita coba dengan perintah berikut:

cd step0
skaffold dev

Segera setelah menjalankan perintah, Anda akan melihat output log docker build dan dapat mengonfirmasi bahwa image berhasil di-push ke registry.

Output perintah

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

Setelah semua container layanan di-push, deployment Kubernetes akan dimulai secara otomatis.

Output perintah

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

Setelah deployment, Anda akan melihat log aplikasi sebenarnya yang dikeluarkan ke stdout di setiap container seperti ini:

Output perintah

[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

Perhatikan bahwa pada tahap ini, Anda ingin melihat pesan apa pun dari server. Oke, akhirnya Anda siap untuk mulai menginstrumentasi aplikasi dengan OpenTelemetry untuk pelacakan terdistribusi layanan.

Sebelum mulai menginstrumentasi layanan, matikan cluster Anda dengan Ctrl-C.

Output perintah

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

Ringkasan

Pada langkah ini, Anda telah menyiapkan materi codelab di lingkungan Anda dan mengonfirmasi bahwa skaffold berjalan seperti yang diharapkan.

Berikutnya

Pada langkah berikutnya, Anda akan mengubah kode sumber layanan loadgen untuk menginstrumentasi informasi rekaman aktivitas.

4. Instrumentasi untuk HTTP

Konsep instrumentasi dan propagasi rekaman aktivitas

Sebelum mengedit kode sumber, kami akan menjelaskan secara singkat cara kerja rekaman aktivitas terdistribusi dalam diagram sederhana.

6be42e353b9bfd1d.png

Dalam contoh ini, kita menginstrumentasikan kode untuk mengekspor informasi Trace dan Span ke Cloud Trace serta memperluas konteks trace di seluruh permintaan dari layanan loadgen ke layanan server.

Aplikasi perlu mengirim metadata Trace seperti ID Trace dan ID Span agar Cloud Trace dapat mengumpulkan semua span yang memiliki ID Trace yang sama menjadi satu trace. Selain itu, aplikasi perlu menyebarkan konteks rekaman aktivitas (kombinasi ID Rekaman Aktivitas dan ID Rentang dari rentang induk) saat meminta layanan hilir, sehingga layanan tersebut dapat mengetahui konteks rekaman aktivitas yang sedang ditangani.

OpenTelemetry membantu Anda:

  • untuk membuat ID Aktivitas dan ID Rentang yang unik
  • untuk mengekspor Trace ID dan Span ID ke backend
  • untuk menyebarkan konteks rekaman aktivitas ke layanan lain
  • untuk menyematkan metadata tambahan yang membantu menganalisis rekaman aktivitas

Komponen di OpenTelemetry Trace

b01f7bb90188db0d.png

Proses untuk menginstrumentasi trace aplikasi dengan OpenTelemetry adalah sebagai berikut:

  1. Buat eksportir
  2. Buat TracerProvider yang mengikat pengekspor di 1 dan tetapkan secara global.
  3. Tetapkan TextMapPropagator untuk menetapkan metode propagasi
  4. Mendapatkan Tracer dari TracerProvider
  5. Membuat Span dari Tracer

Saat ini, Anda tidak perlu memahami properti mendetail di setiap komponen, tetapi hal terpenting yang perlu diingat adalah:

  • pengekspor di sini dapat dihubungkan ke TracerProvider
  • TracerProvider menyimpan semua konfigurasi terkait pengambilan sampel dan ekspor trace
  • semua rekaman aktivitas digabungkan dalam objek Tracer

Setelah memahami hal ini, mari kita lanjutkan ke pekerjaan coding yang sebenarnya.

Span pertama instrumen

Mengukur layanan pembuat beban

Buka Cloud Shell Editor dengan menekan tombol 776a11bfb2122549.png di kanan atas Cloud Shell. Buka step0/src/loadgen/main.go dari penjelajah di panel kiri dan temukan fungsi utama.

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++
        }
}

Di fungsi utama, Anda melihat loop yang memanggil fungsi run di dalamnya. Dalam penerapan saat ini, bagian ini memiliki 2 baris log yang mencatat awal dan akhir panggilan fungsi. Sekarang, mari kita instrumentasikan informasi Span untuk melacak latensi panggilan fungsi.

Pertama, seperti yang disebutkan di bagian sebelumnya, mari siapkan seluruh konfigurasi untuk OpenTelemetry. Tambahkan paket OpenTelemetry sebagai berikut:

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
)

Agar mudah dibaca, kita membuat fungsi penyiapan bernama initTracer dan memanggilnya dalam fungsi main.

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
}

Anda mungkin menyadari bahwa prosedur untuk menyiapkan OpenTelemetry adalah seperti yang dijelaskan di bagian sebelumnya. Dalam implementasi ini, kita menggunakan eksportir stdout yang mengekspor semua informasi rekaman aktivitas ke stdout dalam format terstruktur.

Kemudian, Anda memanggilnya dari fungsi utama. Panggil initTracer() dan pastikan untuk memanggil TracerProvider.Shutdown() saat Anda menutup aplikasi.

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

Setelah menyelesaikan penyiapan, Anda perlu membuat Span dengan Trace ID dan Span ID yang unik. OpenTelemetry menyediakan library praktis untuk hal ini. Tambahkan paket baru tambahan ke klien HTTP instrumentasi.

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"
)

Karena generator beban memanggil layanan klien di HTTP dengan net/http dalam fungsi runQuery, kita menggunakan paket contrib untuk net/http dan mengaktifkan instrumentasi dengan ekstensi paket httptrace dan otelhttp.

Pertama, tambahkan variabel global paket httpClient untuk memanggil permintaan HTTP melalui klien yang diinstrumentasikan.

step0/src/loadgen/main.go

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

Selanjutnya, tambahkan instrumentasi dalam fungsi runQuery untuk membuat rentang kustom menggunakan OpenTelemetry dan rentang yang dibuat otomatis dari klien HTTP kustom. Yang akan Anda lakukan adalah:

  1. Dapatkan Tracer dari TracerProvider global dengan otel.Tracer()
  2. Buat rentang root dengan metode Tracer.Start()
  3. Mengakhiri rentang root pada waktu yang arbitrer (dalam hal ini, akhir fungsi runQuery)

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)
        }

Sekarang Anda telah menyelesaikan instrumentasi di loadgen (aplikasi klien HTTP). Pastikan untuk memperbarui go.mod dan go.sum dengan perintah go mod.

go mod tidy

Mengukur layanan klien

Di bagian sebelumnya, kita menginstrumentasikan bagian yang berada dalam kotak merah pada gambar di bawah. Kami menginstrumentasikan informasi rentang di layanan generator beban. Mirip dengan layanan pembuat beban, sekarang kita perlu menginstrumentasi layanan klien. Perbedaannya dengan layanan pembuat beban adalah layanan klien perlu mengekstrak informasi ID Aktivitas yang disebarkan dari layanan pembuat beban di header HTTP dan menggunakan ID tersebut untuk membuat Rentang.

bcaccd06691269f8.png

Buka Cloud Shell Editor dan tambahkan paket yang diperlukan seperti yang kita lakukan untuk layanan pembuat muatan.

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
)

Sekali lagi, kita perlu menyiapkan OpenTelemetry. Cukup salin dan tempel fungsi initTracer dari loadgen dan panggil di fungsi main layanan klien juga.

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
}

Sekarang saatnya menginstrumentasi rentang. Karena layanan klien harus menerima permintaan HTTP dari layanan loadgen, layanan tersebut harus menginstrumentasi handler. Server HTTP di layanan klien diimplementasikan dengan net/http, dan Anda dapat menggunakan paket otelhttp seperti yang kami lakukan di loadgen.

Pertama, kita mengganti pendaftaran pengendali dengan Pengendali otelhttp. Dalam fungsi main, temukan baris tempat pengendali HTTP didaftarkan dengan http.HandleFunc().

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)

Kemudian, kita mengukur rentang sebenarnya di dalam handler. Temukan handler func (*clientService), dan tambahkan instrumentasi rentang dengan trace.SpanFromContext().

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

Dengan instrumentasi ini, Anda akan mendapatkan rentang dari awal metode handler hingga akhir metode tersebut. Untuk memudahkan rentang dianalisis, tambahkan atribut tambahan yang menyimpan jumlah kecocokan ke kueri. Tepat sebelum baris log, tambahkan kode berikut.

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

Dengan semua instrumentasi di atas, Anda telah menyelesaikan instrumentasi rekaman aktivitas antara loadgen dan klien. Mari kita lihat cara kerjanya. Jalankan kembali kode dengan skaffold.

skaffold dev

Setelah beberapa waktu untuk menjalankan layanan di cluster GKE, Anda akan melihat sejumlah besar pesan log seperti ini:

Output perintah

[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"
...

Ekspor stdout memancarkan pesan ini. Anda akan melihat bahwa induk semua rentang menurut loadgen memiliki TraceID: 00000000000000000000000000000000, karena ini adalah rentang root, yaitu rentang pertama dalam rekaman aktivitas. Anda juga menemukan bahwa atribut sematan "query" memiliki string kueri yang diteruskan ke layanan klien.

Ringkasan

Pada langkah ini, Anda telah menginstrumentasi layanan pembuat beban dan layanan klien yang berkomunikasi dalam HTTP dan mengonfirmasi bahwa Anda dapat berhasil menyebarkan Konteks Pelacakan di seluruh layanan dan mengekspor informasi Span dari kedua layanan ke stdout.

Berikutnya

Pada langkah berikutnya, Anda akan menginstrumentasikan layanan klien dan layanan server untuk mengonfirmasi cara menyebarkan Konteks Trace melalui gRPC.

5. Instrumentasi untuk gRPC

Pada langkah sebelumnya, kita telah menginstrumentasi paruh pertama permintaan di microservice ini. Pada langkah ini, kita mencoba menginstrumentasikan komunikasi gRPC antara layanan klien dan layanan server. (Persegi panjang hijau dan ungu pada gambar di bawah)

75310d8e0e3b1a30.png

Instrumentasi pra-build untuk klien gRPC

Ekosistem OpenTelemetry menawarkan banyak library praktis yang membantu developer menginstrumentasikan aplikasi. Pada langkah sebelumnya, kita menggunakan instrumentasi bawaan untuk paket net/http. Pada langkah ini, karena kita mencoba menyebarkan Konteks Pelacakan melalui gRPC, kita menggunakan library untuk melakukannya.

Pertama, Anda mengimpor paket gRPC bawaan yang disebut otelgrpc.

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"
)

Kali ini, layanan klien adalah klien gRPC terhadap layanan server, jadi Anda perlu menginstrumentasikan klien gRPC. Temukan fungsi mustConnGRPC dan tambahkan interseptor gRPC yang mengukur rentang baru setiap kali klien membuat permintaan ke server.

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))
        }
}

Karena Anda telah menyiapkan OpenTelemetry di bagian sebelumnya, Anda tidak perlu melakukannya.

Instrumentasi bawaan untuk server gRPC

Seperti yang kita lakukan untuk klien gRPC, kita memanggil instrumentasi bawaan untuk server gRPC. Tambahkan paket baru ke bagian impor seperti:

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"
)

Karena ini adalah pertama kalinya menginstrumentasikan server, Anda harus menyiapkan OpenTelemetry terlebih dahulu, mirip dengan yang kita lakukan untuk layanan loadgen dan klien.

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

Selanjutnya, Anda perlu menambahkan interseptor server. Dalam fungsi main, temukan tempat grpc.NewServer() dipanggil dan tambahkan interceptor ke fungsi.

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

Menjalankan microservice dan mengonfirmasi rekaman aktivitas

Kemudian, jalankan kode yang telah diubah dengan perintah skaffold.

skaffold dev

Sekarang, Anda akan melihat banyak informasi rentang di stdout.

Output perintah

...
[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] }
...

Anda menyadari bahwa Anda belum menyematkan nama rentang dan membuat rentang secara manual dengan trace.Start() atau span.SpanFromContext(). Namun, Anda akan mendapatkan banyak rentang karena interceptor gRPC membuatnya.

Ringkasan

Pada langkah ini, Anda menginstrumentasi komunikasi berbasis gRPC dengan dukungan dari library ekosistem OpenTelemetry.

Berikutnya

Pada langkah berikutnya, Anda akan memvisualisasikan rekaman aktivitas dengan Cloud Trace dan mempelajari cara menganalisis rentang yang dikumpulkan.

6. Memvisualisasikan rekaman aktivitas dengan Cloud Trace

Anda telah menginstrumentasi rekaman aktivitas di seluruh sistem dengan OpenTelemetry. Sejauh ini, Anda telah mempelajari cara menginstrumentasi layanan HTTP dan gRPC. Meskipun Anda telah mempelajari cara mengukurnya, Anda belum mempelajari cara menganalisisnya. Di bagian ini, Anda akan mengganti eksportir stdout dengan eksportir Cloud Trace, dan mempelajari cara menganalisis rekaman aktivitas.

Menggunakan eksportir Cloud Trace

Salah satu karakteristik canggih OpenTelemetry adalah kemampuannya untuk dihubungkan. Untuk memvisualisasikan semua rentang yang dikumpulkan oleh instrumentasi Anda, yang perlu Anda lakukan hanyalah mengganti eksportir stdout dengan eksportir Cloud Trace.

Buka file main.go setiap layanan, dan temukan fungsi initTracer(). Hapus baris untuk membuat pengekspor stdout dan membuat pengekspor Cloud Trace.

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
}

Anda juga perlu mengedit fungsi yang sama di layanan klien dan server.

Menjalankan microservice dan mengonfirmasi rekaman aktivitas

Setelah pengeditan, cukup jalankan cluster seperti biasa dengan perintah skaffold.

skaffold dev

Kemudian, Anda tidak akan melihat banyak informasi rentang dalam format log terstruktur di stdout, karena Anda mengganti eksportir dengan eksportir Cloud Trace.

Output perintah

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

Sekarang, mari kita konfirmasi apakah semua rentang dikirim dengan benar ke Cloud Trace. Akses Konsol Cloud, lalu buka "Daftar trace". Fitur ini mudah diakses dari kotak penelusuran. Atau, Anda dapat mengklik menu di panel kiri. 8b3f8411bd737e06.png

Kemudian, Anda melihat banyak titik biru yang tersebar di seluruh grafik latensi. Setiap titik mewakili satu rekaman aktivitas.

3ecf131423fc4c40.png

Klik salah satunya dan Anda dapat melihat detail di dalam rekaman aktivitas. 4fd10960c6648a03.png

Bahkan dari sekilas pandang sederhana ini, Anda sudah mengetahui banyak insight. Misalnya, dari grafik waterfall, Anda dapat melihat bahwa penyebab latensi sebagian besar adalah karena rentang bernama shakesapp.ShakespeareService/GetMatchCount. (Lihat 1 pada gambar di atas) Anda dapat mengonfirmasinya dari tabel ringkasan. (Kolom paling kanan menampilkan durasi setiap rentang.) Selain itu, rekaman aktivitas ini adalah untuk kueri "teman". (Lihat 2 pada gambar di atas)

Dengan analisis singkat ini, Anda mungkin menyadari bahwa Anda perlu mengetahui rentang yang lebih terperinci di dalam metode GetMatchCount. Dibandingkan dengan informasi stdout, visualisasi sangat efektif. Untuk mempelajari lebih lanjut detail Cloud Trace, buka dokumentasi resmi kami.

Ringkasan

Pada langkah ini, Anda mengganti pengekspor stdout dengan pengekspor Cloud Trace dan memvisualisasikan trace di Cloud Trace. Anda juga telah mempelajari cara mulai menganalisis rekaman aktivitas.

Berikutnya

Pada langkah berikutnya, Anda akan mengubah kode sumber layanan server untuk menambahkan sub-span di GetMatchCount.

7. Menambahkan sub rentang untuk analisis yang lebih baik

Pada langkah sebelumnya, Anda menemukan bahwa penyebab waktu perjalanan pulang pergi yang diamati dari loadgen sebagian besar adalah proses di dalam metode GetMatchCount, handler gRPC, di layanan server. Namun, karena kita belum menginstrumentasi apa pun selain handler, kita tidak dapat menemukan insight lebih lanjut dari grafik waterfall. Ini adalah kasus umum saat kita mulai menginstrumentasi microservice.

3b63a1e471dddb8c.png

Di bagian ini, kita akan mengukur sub-span tempat server memanggil Google Cloud Storage, karena beberapa I/O jaringan eksternal sering kali membutuhkan waktu yang lama dalam prosesnya dan penting untuk mengidentifikasi apakah panggilan tersebut adalah penyebabnya.

Mengukur sub-rentang di server

Buka main.go di server dan temukan fungsi readFiles. Fungsi ini memanggil permintaan ke Google Cloud Storage untuk mengambil semua file teks karya Shakespeare. Dalam fungsi ini, Anda dapat membuat sub-span, seperti yang Anda lakukan untuk instrumentasi server HTTP di layanan klien.

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

Dan itulah cara menambahkan rentang baru. Mari kita lihat cara kerjanya dengan menjalankan aplikasi.

Menjalankan microservice dan mengonfirmasi rekaman aktivitas

Setelah pengeditan, cukup jalankan cluster seperti biasa dengan perintah skaffold.

skaffold dev

Lalu, pilih satu rekaman aktivitas bernama query.request dari daftar rekaman aktivitas. Anda akan melihat grafik waterfall rekaman aktivitas yang serupa, kecuali untuk rentang baru di bagian shakesapp.ShakespeareService/GetMatchCount. (Rentang yang disertakan dalam persegi panjang merah di bawah)

3d4a891aa30d7a32.png

Dari grafik ini, Anda dapat melihat bahwa panggilan eksternal ke Google Cloud Storage menggunakan latensi yang besar, tetapi masih ada hal lain yang menyebabkan sebagian besar latensi.

Anda sudah mendapatkan banyak insight hanya dari beberapa tampilan grafik waterfall rekaman aktivitas. Bagaimana cara Anda mendapatkan detail performa lebih lanjut di aplikasi? Di sinilah profiler berperan, tetapi untuk saat ini, mari kita akhiri codelab ini dan mendelegasikan semua tutorial profiler ke bagian 2.

Ringkasan

Pada langkah ini, Anda telah menginstrumentasikan rentang lain di layanan server dan mendapatkan insight lebih lanjut tentang latensi sistem.

8. Selamat

Anda telah berhasil membuat trace terdistribusi dengan OpenTelemetry dan mengonfirmasi latensi permintaan di seluruh microservice di Google Cloud Trace.

Untuk latihan yang lebih panjang, Anda dapat mencoba topik berikut sendiri.

  • Implementasi saat ini mengirimkan semua rentang yang dihasilkan oleh health check. (grpc.health.v1.Health/Check) Bagaimana cara memfilter rentang tersebut dari Cloud Trace? Petunjuknya ada di sini.
  • Hubungkan log peristiwa dengan rentang dan lihat cara kerjanya di Google Cloud Trace dan Google Cloud Logging. Petunjuknya ada di sini.
  • Ganti beberapa layanan dengan layanan dalam bahasa lain dan coba instrumentasikan dengan OpenTelemetry untuk bahasa tersebut.

Selain itu, jika Anda ingin mempelajari profiler setelah ini, lanjutkan ke bagian 2. Jika demikian, Anda dapat melewati bagian pembersihan di bawah.

Pembersihan

Setelah menyelesaikan codelab ini, hentikan cluster Kubernetes dan pastikan untuk menghapus project agar Anda tidak dikenai biaya yang tidak terduga di Google Kubernetes Engine, Google Cloud Trace, Google Artifact Registry.

Pertama, hapus cluster. Jika Anda menjalankan cluster dengan skaffold dev, Anda hanya perlu menekan Ctrl-C. Jika Anda menjalankan cluster dengan skaffold run, jalankan perintah berikut:

skaffold delete

Output perintah

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

Setelah menghapus cluster, dari panel menu, pilih "IAM & Admin" > "Settings", lalu klik tombol "SHUT DOWN".

45aa37b7d5e1ddd1.png

Kemudian, masukkan Project ID (bukan Project Name) dalam formulir di dialog dan konfirmasi penonaktifan.