เครื่องมือสำหรับเพิ่มประสิทธิภาพของแอปใน Go (ตอนที่ 1: การติดตาม)

1. บทนำ

505827108874614d.png

อัปเดตล่าสุด 15-07-2022

ความสามารถในการสังเกตของแอปพลิเคชัน

ความสามารถในการสังเกตและ OpenTelemetry

การสังเกตเป็นคำที่ใช้เพื่ออธิบายแอตทริบิวต์ของระบบ ระบบที่มีความสามารถในการสังเกตช่วยให้ทีมแก้ไขข้อบกพร่องของระบบของตนได้ในเชิงรุก ในบริบทดังกล่าว เสาหลัก 3 ประการของความสามารถในการสังเกต บันทึก เมตริก และการติดตามเป็นเครื่องมือพื้นฐานสำหรับระบบเพื่อให้ได้ความสามารถในการสังเกต

OpenTelemetry คือชุดข้อกำหนด ไลบรารี และตัวแทนที่เร่งการใช้เครื่องมือและการส่งออกข้อมูลการวัดและส่งข้อมูลทางไกล (บันทึก เมตริก และการติดตาม) ที่ความสามารถในการสังเกตต้องการ OpenTelemetry คือโครงการมาตรฐานแบบเปิดและโครงการที่ขับเคลื่อนด้วยชุมชนภายใต้ CNCF การใช้ประโยชน์จากไลบรารีที่โครงการและระบบนิเวศมีให้ ทำให้นักพัฒนาซอฟต์แวร์สามารถนำแอปพลิเคชันของตนไปใช้ในแนวทางที่เป็นกลางของผู้ให้บริการและป้องกันการใช้สถาปัตยกรรมหลายๆ แบบได้

นอกจากเสาหลัก 3 ประการสำหรับความสามารถในการสังเกตแล้ว การทำโปรไฟล์อย่างต่อเนื่องก็เป็นองค์ประกอบหลักอีกอย่างหนึ่งของความสามารถในการสังเกต ทั้งยังเป็นการขยายฐานผู้ใช้ในอุตสาหกรรมอีกด้วย Cloud Profiler คือหนึ่งในผู้ริเริ่มและให้อินเทอร์เฟซง่ายๆ ในการเจาะลึกเมตริกประสิทธิภาพในสแต็กการเรียกใช้แอปพลิเคชัน

Codelab นี้เป็นส่วนที่ 1 ของซีรีส์ และครอบคลุมการใช้การติดตามที่มีการกระจายใน Microservice ด้วย OpenTelemetry และ Cloud Trace ส่วนที่ 2 จะครอบคลุมการทำโปรไฟล์อย่างต่อเนื่องด้วย Cloud Profiler

การติดตามแบบกระจาย

การติดตามเป็นการวัดและส่งข้อมูลทางไกลที่บอกเวลาในการตอบสนองของส่วนที่เฉพาะเจาะจงของกระบวนการในระบบ โดยในบันทึก เมตริก และการติดตาม โดยเฉพาะอย่างยิ่งในยุคของ Microservice การติดตามแบบกระจายเป็นตัวขับเคลื่อนที่แข็งแกร่งในการค้นหาจุดคอขวดของเวลาในการตอบสนองในระบบแบบกระจายโดยรวม

เมื่อวิเคราะห์การติดตามแบบกระจาย การแสดงภาพข้อมูลการติดตามเป็นกุญแจสำคัญในการทำความเข้าใจเวลาในการตอบสนองของระบบโดยรวมอย่างรวดเร็ว ในการติดตามแบบกระจาย เราจะจัดการชุดการเรียกใช้เพื่อประมวลผลคำขอเดียวไปยังจุดแรกเข้าของระบบในรูปแบบ Trace ที่มี Spans หลายรายการ

ช่วงแสดงถึงหน่วยงานแต่ละหน่วยที่ทำในระบบที่กระจายตัว ซึ่งจะบันทึกเวลาเริ่มต้นและเวลาสิ้นสุด Span มักจะมีความสัมพันธ์แบบลำดับชั้นระหว่างกัน - ในรูปภาพใต้สแปนที่เล็กกว่าทั้งหมดคือสแปนลูกของช่วง /messages ขนาดใหญ่ และถูกประกอบกันเป็น Trace เดียวที่จะแสดงเส้นทางการทำงานผ่านระบบ

การติดตาม

Google Cloud Trace เป็นหนึ่งในตัวเลือกสำหรับแบ็กเอนด์การติดตามแบบกระจายและผสานรวมกับผลิตภัณฑ์อื่นๆ ใน Google Cloud เป็นอย่างดี

สิ่งที่คุณจะสร้าง

ใน Codelab นี้ คุณจะป้อนข้อมูลการติดตามการใช้เครื่องมือในบริการที่มีชื่อว่า "แอปพลิเคชัน Shakespeare" (หรือที่รู้จักในชื่อ Shakesapp) ที่เรียกใช้บนคลัสเตอร์ Google Kubernetes Engine สถาปัตยกรรมของ Shakesapp อธิบายไว้ด้านล่าง

44e243182ced442f.png

  • Loadgen ส่งสตริงการค้นหาไปยังไคลเอ็นต์ใน HTTP
  • ไคลเอ็นต์ส่งผ่านการค้นหาจากตัวจัดสรรภาระงานไปยังเซิร์ฟเวอร์ใน gRPC
  • เซิร์ฟเวอร์ยอมรับคำค้นหาจากไคลเอ็นต์ ดึงข้อมูลงานของ Shakespare ทั้งหมดในรูปแบบข้อความจาก Google Cloud Storage, ค้นหาบรรทัดที่มีคำค้นหา และแสดงผลจำนวนบรรทัดที่ตรงกับไคลเอ็นต์

คุณจะใช้ข้อมูลการติดตามในคำขอ หลังจากนั้น คุณจะต้องฝัง Agent ของเครื่องมือสร้างโปรไฟล์ในเซิร์ฟเวอร์และตรวจสอบจุดคอขวด

สิ่งที่คุณจะได้เรียนรู้

  • วิธีเริ่มต้นใช้งานไลบรารี OpenTelemetry Trace ในโปรเจ็กต์ Go
  • วิธีสร้างระยะเวลาด้วยไลบรารี
  • วิธีเผยแพร่บริบทสแปนไปตามสายไฟระหว่างส่วนประกอบต่างๆ ของแอป
  • วิธีส่งข้อมูลการติดตามไปยัง Cloud Trace
  • วิธีวิเคราะห์การติดตามใน Cloud Trace

Codelab นี้จะอธิบายถึงวิธีใช้ Microservice เพื่อให้เข้าใจง่าย ตัวอย่างนี้มีเพียง 3 คอมโพเนนต์ (ตัวสร้างโหลด ไคลเอ็นต์ และเซิร์ฟเวอร์) แต่คุณสามารถใช้กระบวนการเดียวกันกับที่อธิบายใน Codelab นี้กับระบบที่ซับซ้อนและมีขนาดใหญ่

สิ่งที่คุณต้องมี

  • ความรู้พื้นฐานเกี่ยวกับ Go
  • ความรู้พื้นฐานเกี่ยวกับ Kubernetes

2. การตั้งค่าและข้อกำหนด

การตั้งค่าสภาพแวดล้อมตามเวลาที่สะดวก

หากยังไม่มีบัญชี Google (Gmail หรือ Google Apps) คุณต้องสร้างบัญชีก่อน ลงชื่อเข้าใช้คอนโซล Google Cloud Platform ( console.cloud.google.com) และสร้างโปรเจ็กต์ใหม่

หากคุณมีโปรเจ็กต์อยู่แล้ว ให้คลิกเมนูแบบเลื่อนลงสำหรับการเลือกโปรเจ็กต์ที่ด้านซ้ายบนของคอนโซล

7a32e5469db69e9.png

แล้วคลิก "โปรเจ็กต์ใหม่" ในกล่องโต้ตอบที่ปรากฏขึ้นเพื่อสร้างโปรเจ็กต์ใหม่ ดังนี้

7136b3ee36ebaf89.png

หากคุณยังไม่มีโปรเจ็กต์ คุณจะเห็นกล่องโต้ตอบลักษณะนี้ให้สร้างโปรเจ็กต์แรก

870a3cbd6541ee86.png

กล่องโต้ตอบการสร้างโปรเจ็กต์ที่ตามมาจะให้คุณป้อนรายละเอียดของโปรเจ็กต์ใหม่:

affdc444517ba805.png

โปรดจำรหัสโปรเจ็กต์ ซึ่งเป็นชื่อที่ไม่ซ้ำกันในโปรเจ็กต์ Google Cloud ทั้งหมด (ระบบใช้ชื่อด้านบนนี้ไปแล้ว และจะใช้ไม่ได้ ขออภัย) โดยจะเรียกใน Codelab ว่า PROJECT_ID ในภายหลัง

ขั้นตอนถัดไป คุณจะต้องเปิดใช้การเรียกเก็บเงินใน Developers Console เพื่อใช้ทรัพยากรของ Google Cloud และเปิดใช้ Cloud Trace API หากยังไม่ได้ดำเนินการ

15d0ef27a8fbab27.png

การใช้งาน Codelab นี้น่าจะมีค่าใช้จ่ายไม่เกิน 2-3 ดอลลาร์ แต่อาจมากกว่านี้หากคุณตัดสินใจใช้ทรัพยากรเพิ่มหรือปล่อยให้ทำงาน (ดูส่วน "ล้างข้อมูล" ในตอนท้ายของเอกสารนี้) ราคาของ Google Cloud Trace, Google Kubernetes Engine และ Google Artifact Registry ระบุไว้ในเอกสารอย่างเป็นทางการ

ผู้ใช้ใหม่ของ Google Cloud Platform จะมีสิทธิ์ทดลองใช้ฟรี$300 ซึ่งจะทำให้ Codelab นี้ไม่มีค่าใช้จ่ายทั้งหมด

การตั้งค่า Google Cloud Shell

แม้ว่า Google Cloud และ Google Cloud Trace จะทำงานจากระยะไกลจากแล็ปท็อปได้ แต่เราจะใช้ Google Cloud Shell ซึ่งเป็นสภาพแวดล้อมของบรรทัดคำสั่งที่ทำงานในระบบคลาวด์ใน Codelab

เครื่องเสมือนแบบ Debian นี้เต็มไปด้วยเครื่องมือการพัฒนาทั้งหมดที่คุณต้องการ โดยมีไดเรกทอรีหลักขนาด 5 GB ที่ทำงานอย่างต่อเนื่องใน Google Cloud ซึ่งจะช่วยเพิ่มประสิทธิภาพของเครือข่ายและการตรวจสอบสิทธิ์ได้อย่างมาก ซึ่งหมายความว่าสิ่งที่คุณต้องมีสำหรับ Codelab นี้คือเบราว์เซอร์ (ใช่แล้ว ทั้งหมดนี้ทำงานได้บน Chromebook)

หากต้องการเปิดใช้งาน Cloud Shell จาก Cloud Console เพียงคลิกเปิดใช้งาน Cloud Shell gcLMt5IuEcJJNnMId-Bcz3sxCd0rZn7IzT_r95C8UZeqML68Y1efBG_B0VRp7hc7qiZTLAF-TXD7SsOadxn8uadgHhaLeASnVS3ZHK39eOlKJOgj9SJua_oeGhMxRrbOg3qigddS2A (การจัดสรรและเชื่อมต่อกับสภาพแวดล้อมซึ่งจะใช้เวลาเพียงไม่นาน)

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

Screen Shot 14-06-2017 เวลา 22.13.43 น.

เมื่อเชื่อมต่อกับ Cloud Shell คุณควรเห็นว่าตนเองผ่านการตรวจสอบสิทธิ์แล้วและโปรเจ็กต์ได้รับการตั้งค่าเป็น PROJECT_ID แล้ว

gcloud auth list

เอาต์พุตจากคำสั่ง

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

เอาต์พุตจากคำสั่ง

[core]
project = <PROJECT_ID>

หากโปรเจ็กต์ไม่ได้ตั้งค่าไว้ด้วยเหตุผลบางประการ ให้ใช้คำสั่งต่อไปนี้

gcloud config set project <PROJECT_ID>

กำลังมองหา PROJECT_ID ของคุณอยู่ใช่ไหม ตรวจสอบรหัสที่คุณใช้ในขั้นตอนการตั้งค่าหรือดูในแดชบอร์ด Cloud Console

158fNPfwSxsFqz9YbtJVZes8viTS3d1bV4CVhij3XPxuzVFOtTObnwsphlm6lYGmgdMFwBJtc-FaLrZU7XHAg_ZYoCrgombMRR3h-eolLPcvO351c5iBv506B3ZwghZoiRg6cz23Qw

Cloud Shell ยังตั้งค่าตัวแปรสภาพแวดล้อมโดยค่าเริ่มต้นด้วย ซึ่งอาจเป็นประโยชน์เมื่อคุณเรียกใช้คำสั่งในอนาคต

echo $GOOGLE_CLOUD_PROJECT

เอาต์พุตจากคำสั่ง

<PROJECT_ID>

สุดท้าย ให้ตั้งค่าโซนและการกำหนดค่าโปรเจ็กต์เริ่มต้น

gcloud config set compute/zone us-central1-f

คุณเลือกโซนต่างๆ ได้หลากหลาย ดูข้อมูลเพิ่มเติมได้ที่ภูมิภาคและ โซน

ตั้งค่าภาษา Go

ใน Codelab นี้ เราใช้ Go สำหรับซอร์สโค้ดทั้งหมด เรียกใช้คำสั่งต่อไปนี้บน Cloud Shell และยืนยันว่าเวอร์ชันของ Go คือ 1.17 ขึ้นไป

go version

เอาต์พุตจากคำสั่ง

go version go1.18.3 linux/amd64

ตั้งค่าคลัสเตอร์ Google Kubernetes

ใน Codelab นี้ คุณจะได้เรียกใช้คลัสเตอร์ของ Microservice บน Google Kubernetes Engine (GKE) กระบวนการของ Codelab มีดังนี้

  1. ดาวน์โหลดโปรเจ็กต์พื้นฐานลงใน Cloud Shell
  2. สร้าง Microservice ลงในคอนเทนเนอร์
  3. อัปโหลดคอนเทนเนอร์ไปยัง Google Artifact Registry (GAR)
  4. ทำให้คอนเทนเนอร์ใช้งานได้บน GKE
  5. แก้ไขซอร์สโค้ดของบริการสำหรับการวัดคุมการติดตาม
  6. ไปที่ขั้นตอนที่ 2

เปิดใช้ Kubernetes Engine

ก่อนอื่น เราตั้งค่าคลัสเตอร์ Kubernetes ที่ Shakesapp ทำงานบน GKE เราจึงต้องเปิดใช้ GKE ไปที่เมนู "Kubernetes Engine" และกดปุ่ม "เปิดใช้"

548cfd95bc6d344d.png

ตอนนี้คุณพร้อมที่จะสร้างคลัสเตอร์ Kubernetes แล้ว

สร้างคลัสเตอร์ Kubernetes

เรียกใช้คำสั่งต่อไปนี้บน Cloud Shell เพื่อสร้างคลัสเตอร์ Kubernetes โปรดยืนยันว่าค่าโซนอยู่ภายใต้ภูมิภาคที่คุณจะใช้ในการสร้างที่เก็บ Artifact Registry เปลี่ยนค่าโซน us-central1-f หากภูมิภาคที่เก็บไม่ครอบคลุมโซน

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

เอาต์พุตจากคำสั่ง

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 และการตั้งค่า Skaffold

ตอนนี้เรามีคลัสเตอร์ Kubernetes ที่พร้อมติดตั้งใช้งานแล้ว ถัดไป เราจะเตรียมพร้อมสำหรับ Container Registry สำหรับพุชและติดตั้งใช้งานคอนเทนเนอร์ สำหรับขั้นตอนเหล่านี้ เราต้องตั้งค่า Artifact Registry (GAR) และ Skaffold เพื่อใช้งาน

การตั้งค่า Artifact Registry

ไปที่เมนูของ "Artifact Registry" และกดปุ่ม "เปิดใช้"

45e384b87f7cf0db.png

หลังจากนั้นสักครู่ คุณจะเห็นเบราว์เซอร์ที่เก็บของ GAR คลิก "สร้างที่เก็บ" แล้วป้อนชื่อที่เก็บ

d6a70f4cb4ebcbe3.png

ใน Codelab นี้ ฉันตั้งชื่อที่เก็บใหม่เป็น trace-codelab รูปแบบของอาร์ติแฟกต์คือ "Docker" และประเภทสถานที่ตั้งคือ "ภูมิภาค" เลือกภูมิภาคที่ใกล้เคียงกับภูมิภาคที่คุณตั้งค่าไว้สำหรับโซนเริ่มต้นของ Google Compute Engine เช่น ตัวอย่างนี้เลือก "us-central1-f" ด้านบน ดังนั้นตรงนี้เราจะเลือก "us-central1 (ไอโอวา)" จากนั้นคลิก "สร้าง"

9c2d1ce65258ef70.png

ตอนนี้คุณจะเห็น "trace-codelab" ในเบราว์เซอร์ที่เก็บ

7a3c1f47346bea15.png

เราจะกลับมาที่นี่ในภายหลังเพื่อตรวจสอบเส้นทางรีจิสทรี

การตั้งค่า Skaf Fold

Skaffold เป็นเครื่องมือที่มีประโยชน์เมื่อคุณสร้าง Microservice ที่ทำงานบน Kubernetes โดยจะจัดการกระบวนการสร้าง พุช และติดตั้งใช้งานคอนเทนเนอร์ของแอปพลิเคชันด้วยคำสั่งสั้นๆ โดยค่าเริ่มต้น Skaffold จะใช้ Docker Registry เป็นรีจิสทรีคอนเทนเนอร์ คุณจึงต้องกำหนดค่า Skaffold ให้จดจำ GAR ในการพุชคอนเทนเนอร์ไป

เปิด Cloud Shell อีกครั้งและยืนยันว่าติดตั้ง Skaffold แล้ว (Cloud Shell จะติดตั้ง Skaffold ลงในสภาพแวดล้อมโดยค่าเริ่มต้น) เรียกใช้คำสั่งต่อไปนี้และดูเวอร์ชัน Skaffold

skaffold version

เอาต์พุตจากคำสั่ง

v1.38.0

ตอนนี้คุณลงทะเบียนที่เก็บเริ่มต้นสำหรับ Skaffold ที่จะใช้ได้แล้ว หากต้องการดูเส้นทางรีจิสทรี ให้ไปที่แดชบอร์ด Artifact Registry แล้วคลิกชื่อที่เก็บที่คุณเพิ่งตั้งค่าในขั้นตอนก่อนหน้า

7a3c1f47346bea15.png

จากนั้นคุณจะเห็นเส้นทางเบรดครัมบ์ที่ด้านบนของหน้า คลิกไอคอน e157b1359c3edc06.png เพื่อคัดลอกเส้นทางรีจิสทรีไปยังคลิปบอร์ด

e0f2ae2144880b8b.png

เมื่อคลิกปุ่มคัดลอก คุณจะเห็นกล่องโต้ตอบที่ด้านล่างของเบราว์เซอร์พร้อมข้อความดังนี้

&quot;us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab&quot; คัดลอกแล้ว

กลับไปที่ Cloud Shell เรียกใช้คำสั่ง skaffold config set default-repo ด้วยค่าที่คุณเพิ่งคัดลอกจากแดชบอร์ด

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

เอาต์พุตจากคำสั่ง

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

นอกจากนี้คุณต้องกำหนดค่ารีจิสทรีเป็นการกำหนดค่า Docker ด้วย เรียกใช้คำสั่งต่อไปนี้

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

เอาต์พุตจากคำสั่ง

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

ตอนนี้คุณก็พร้อมเข้าสู่ขั้นตอนถัดไปในการตั้งค่าคอนเทนเนอร์ Kubernetes บน GKE แล้ว

สรุป

ในขั้นตอนนี้ คุณจะได้ตั้งค่าสภาพแวดล้อม Codelab ด้วยคำสั่งต่อไปนี้

  • ตั้งค่า Cloud Shell
  • สร้างที่เก็บ Artifact Registry สำหรับคอนเทนเนอร์รีจิสทรี
  • ตั้งค่า Skaffold เพื่อใช้ Container Registry
  • สร้างคลัสเตอร์ Kubernetes ที่ Codelab Microservice ทำงาน

ถัดไป

ในขั้นตอนถัดไป คุณจะสร้าง พุช และทำให้ Microservice ใช้งานได้บนคลัสเตอร์

3. สร้าง พุช และติดตั้งใช้งาน Microservice

ดาวน์โหลดเนื้อหา Codelab

ในขั้นตอนก่อนหน้า เราได้กำหนดข้อกำหนดเบื้องต้นทั้งหมดสำหรับ Codelab แล้ว ตอนนี้คุณพร้อมที่จะเรียกใช้ Microservice ทั้งระบบแล้ว เนื้อหา Codelab จะโฮสต์อยู่บน GitHub ดังนั้นให้ดาวน์โหลดเนื้อหาดังกล่าวไปยังสภาพแวดล้อม Cloud Shell ด้วยคำสั่ง git ต่อไปนี้

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

โครงสร้างไดเรกทอรีของโครงการมีดังต่อไปนี้

.
├── 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
  • ไฟล์ Manifest: ไฟล์ Manifest ของ Kubernetes
  • Proto: คำจำกัดความของ Proto สำหรับการสื่อสารระหว่างไคลเอ็นต์กับเซิร์ฟเวอร์
  • src: ไดเรกทอรีสำหรับซอร์สโค้ดของแต่ละบริการ
  • skaffold.yaml: ไฟล์การกำหนดค่าสำหรับ skaffold

ใน Codelab นี้ คุณจะอัปเดตซอร์สโค้ดที่อยู่ภายใต้โฟลเดอร์ step0 นอกจากนี้ คุณสามารถดูซอร์สโค้ดใน step[1-6] โฟลเดอร์เพื่อดูคำตอบในขั้นตอนต่อไปนี้ (ส่วนที่ 1 ครอบคลุมขั้นตอนที่ 0 ถึงขั้นตอนที่ 4 และส่วนที่ 2 ครอบคลุมขั้นตอนที่ 5 และ 6)

เรียกใช้คำสั่ง Skaffold

ขั้นตอนสุดท้าย ก็พร้อมสร้าง พุช และทำให้เนื้อหาทั้งหมดใช้งานได้บนคลัสเตอร์ Kubernetes ที่เพิ่งสร้างขึ้นแล้ว นี่อาจดูเหมือนว่ามีหลายขั้นตอน แต่จริงๆ แล้ว skaffold ทำทุกอย่างให้คุณแล้ว ให้ลองใช้คำสั่งต่อไปนี้แทน

cd step0
skaffold dev

เมื่อเรียกใช้คำสั่ง คุณจะเห็นเอาต์พุตบันทึกของ docker build และสามารถยืนยันได้ว่ามีการพุชไปยังรีจิสทรีสำเร็จแล้ว

เอาต์พุตจากคำสั่ง

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

หลังจากพุชคอนเทนเนอร์บริการทั้งหมด การทำให้ Kubernetes ใช้งานได้จะเริ่มต้นโดยอัตโนมัติ

เอาต์พุตจากคำสั่ง

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

หลังจากการทำให้ใช้งานได้ คุณจะเห็นบันทึกแอปพลิเคชันจริงที่ปล่อยออกมาให้กับ stdout ในแต่ละคอนเทนเนอร์ ดังนี้

เอาต์พุตจากคำสั่ง

[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

โปรดทราบว่า ณ จุดนี้ คุณต้องการดูข้อความใดๆ จากเซิร์ฟเวอร์ เอาล่ะ ในที่สุดคุณพร้อมที่จะเริ่มวัดคุมแอปพลิเคชันของคุณด้วย OpenTelemetry สำหรับการติดตามแบบกระจายของบริการ

ก่อนเริ่มวัดคุมบริการ โปรดปิดคลัสเตอร์ของคุณด้วย Ctrl-C

เอาต์พุตจากคำสั่ง

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

สรุป

ในขั้นตอนนี้ คุณได้เตรียมวัสดุ Codelab ในสภาพแวดล้อมของคุณและยืนยันว่าสเกฟโฟลด์ทำงานได้ตามที่คาดไว้

ถัดไป

ในขั้นตอนถัดไป คุณจะต้องแก้ไขซอร์สโค้ดของบริการ กำลังโหลดข้อมูลเพื่อใช้ข้อมูลการติดตาม

4. เครื่องมือสำหรับ HTTP

แนวคิดของการใช้เครื่องมือการติดตามและการเผยแพร่

ก่อนแก้ไขซอร์สโค้ด เราขออธิบายคร่าวๆ ว่าการติดตามแบบกระจายตัวทำงานอย่างไรในแผนภาพง่ายๆ

6be42e353b9bfd1d.png

ในตัวอย่างนี้ เราใช้เครื่องมือของโค้ดเพื่อส่งออกข้อมูลการติดตามและข้อมูล Span ไปยัง Cloud Trace และเผยแพร่บริบทของการติดตามในคำขอจากบริการโหลดข้อมูลไปยังบริการเซิร์ฟเวอร์

แอปพลิเคชันต้องส่งข้อมูลเมตาของการติดตาม เช่น รหัสการติดตามและรหัส Span เพื่อให้ Cloud Trace รวมสแปนทั้งหมดที่มีรหัสการติดตามเดียวกันไว้ในการติดตามเดียว นอกจากนี้ แอปพลิเคชันจำเป็นต้องเผยแพร่บริบทการติดตาม (ชุดค่าผสมของรหัสการติดตามและรหัส Span ของสแปนหลัก) ในการขอบริการดาวน์สตรีม เพื่อให้แอปพลิเคชันรับรู้บริบทการติดตามที่กำลังจัดการอยู่

OpenTelemetry ช่วยคุณทำสิ่งต่อไปนี้

  • เพื่อสร้างรหัสการติดตามและรหัส Span ที่ไม่ซ้ำกัน
  • เพื่อส่งออกรหัสการติดตามและรหัส Span ไปยังแบ็กเอนด์
  • เพื่อเผยแพร่บริบทการติดตามไปยังบริการอื่นๆ
  • เพื่อฝังข้อมูลเมตาเพิ่มเติมที่จะช่วยวิเคราะห์การติดตาม

คอมโพเนนต์ใน OpenTelemetry Trace

b01f7bb90188db0d.png

กระบวนการในการใช้เครื่องมือการติดตามแอปพลิเคชันด้วย OpenTelemetry มีดังนี้

  1. สร้างผู้ส่งออก
  2. สร้าง TracerProvider ที่ใช้เชื่อมโยงผู้ส่งออกในขั้นตอนเดียวและตั้งค่าให้เป็นทั่วโลก
  3. ตั้งค่า TextMapPropagaror เพื่อตั้งค่าวิธีการนำไปใช้
  4. รับ Tracer จาก TracerProvider
  5. สร้างช่วงจากเครื่องมือติดตาม

ปัจจุบันคุณไม่จำเป็นต้องเข้าใจคุณสมบัติโดยละเอียดในแต่ละคอมโพเนนต์ แต่สิ่งสำคัญที่สุดที่ควรคำนึงถึงคือ

  • ผู้ส่งออกที่นี่สามารถเสียบเข้ากับ TracerProvider ได้
  • TracerProvider จะเก็บการกำหนดค่าทั้งหมดเกี่ยวกับการสุ่มตัวอย่างการติดตามและการส่งออก
  • การติดตามทั้งหมดจะรวมอยู่ในออบเจ็กต์ Tracer

สำหรับความเข้าใจในเรื่องนี้ เรามาดูงานการเขียนโค้ดจริงกันดีกว่า

ช่วงแรกของเครื่องมือ

บริการสร้างโหลดเครื่องมือ

เปิด Cloud Shell Editor โดยกดปุ่ม776a11bfb2122549.pngที่ด้านบนขวาของ Cloud Shell เปิด step0/src/loadgen/main.go จากเครื่องมือสำรวจในแผงด้านซ้าย และค้นหาฟังก์ชันหลัก

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

ในฟังก์ชันหลัก คุณจะเห็นการวนซ้ำที่เรียกใช้ฟังก์ชัน run ในฟังก์ชันหลัก ในการใช้งานปัจจุบัน ส่วนนี้มีบรรทัดในบันทึก 2 บรรทัดที่บันทึกจุดเริ่มต้นและจุดสิ้นสุดของการเรียกใช้ฟังก์ชัน คราวนี้เราจะลองใช้ข้อมูล Span เพื่อติดตามเวลาในการตอบสนองของการเรียกใช้ฟังก์ชัน

อย่างแรก ตามที่ระบุไว้ในส่วนก่อนหน้านี้ เรามากำหนดค่าทั้งหมดสำหรับ OpenTelemetry กัน เพิ่มแพ็กเกจ OpenTelemetry ดังนี้

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
)

เราสร้างฟังก์ชันการตั้งค่าที่เรียกว่า initTracer แล้วเรียกใช้ในฟังก์ชัน 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
}

คุณอาจทราบว่าขั้นตอนการตั้งค่า OpenTelemetry ตามที่อธิบายไว้ในหัวข้อก่อนหน้านี้ ในการใช้งานนี้ เราใช้ผู้ส่งออก stdout ที่ส่งออกข้อมูลการติดตามทั้งหมดไปยัง stdout ในรูปแบบที่มีโครงสร้าง

จากนั้นคุณจะเรียกใช้จากฟังก์ชันหลัก โทรหา initTracer() และอย่าลืมโทรหา TracerProvider.Shutdown() เมื่อปิดแอปพลิเคชัน

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

เมื่อตั้งค่าเสร็จแล้ว คุณต้องสร้าง Span ที่มีรหัสการติดตามและรหัส Span ที่ไม่ซ้ำกัน OpenTelemetry มีไลบรารีที่เป็นประโยชน์ เพิ่มแพ็กเกจใหม่เพิ่มเติมลงในไคลเอ็นต์ HTTP ของเครื่องมือ

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

เนื่องจากตัวสร้างโหลดเรียกใช้บริการไคลเอ็นต์ใน HTTP ด้วยฟังก์ชัน net/http ในฟังก์ชัน runQuery เราจึงใช้แพ็กเกจ Contrib สำหรับ net/http และเปิดใช้การใช้เครื่องมือกับส่วนขยายของแพ็กเกจ httptrace และ otelhttp

ก่อนอื่นให้เพิ่ม httpClient ที่เป็นตัวแปรร่วมของแพ็กเกจเพื่อเรียกใช้คำขอ HTTP ผ่านไคลเอ็นต์ที่มีการวัดคุม

step0/src/loadgen/main.go

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

ถัดไปให้เพิ่มการวัดคุมในฟังก์ชัน runQuery เพื่อสร้างช่วงเวลาที่กำหนดเองโดยใช้ OpenTelemetry และช่วงที่สร้างโดยอัตโนมัติจากไคลเอ็นต์ HTTP ที่กำหนดเอง สิ่งที่คุณต้องดำเนินการมีดังต่อไปนี้

  1. รับเครื่องมือติดตามจาก TracerProvider ทั่วโลกด้วย otel.Tracer()
  2. สร้างสแปนรูทด้วยเมธอด Tracer.Start()
  3. สิ้นสุดระยะรูทในช่วงเวลาที่กําหนดเอง (ในกรณีนี้คือสิ้นสุดฟังก์ชัน 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)
        }

ตอนนี้คุณก็ทำการติดตั้งใช้งานในตัวจัดสรรภาระงาน (แอปพลิเคชันไคลเอ็นต์ HTTP) เรียบร้อยแล้ว โปรดอัปเดต go.mod และ go.sum ด้วยคำสั่ง go mod

go mod tidy

บริการไคลเอ็นต์สำหรับเครื่องมือ

ในส่วนก่อนหน้านี้ เราติดตั้งอุปกรณ์ไว้กับส่วนที่อยู่ในสี่เหลี่ยมผืนผ้าสีแดงในภาพวาดด้านล่าง เราวัดคุมข้อมูล span ในบริการสร้างโหลด เช่นเดียวกับบริการตัวสร้างโหลด ตอนนี้เราจำเป็นต้องวัดการทำงานของบริการลูกค้า ข้อแตกต่างจากบริการตัวสร้างภาระงานคือ บริการไคลเอ็นต์ต้องดึงข้อมูลรหัสการติดตามที่เผยแพร่จากบริการตัวสร้างภาระงานในส่วนหัว HTTP และใช้รหัสนั้นเพื่อสร้างระยะเวลา

bcaccd06691269f8.png

เปิด Cloud Shell Editor และเพิ่มแพ็กเกจที่จำเป็นเช่นเดียวกับที่เราทำสำหรับบริการสร้างโหลด

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 เพียงคัดลอกและวางฟังก์ชัน initTracer จากตัวจัดสรรภาระงาน แล้วเรียกใช้ในฟังก์ชัน main ของบริการไคลเอ็นต์ด้วย

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
}

ตอนนี้ได้เวลาของ Span แล้ว เนื่องจากบริการไคลเอ็นต์ต้องยอมรับคำขอ HTTP จากบริการตัวจัดสรรภาระงาน บริการจึงต้องใช้เครื่องจัดการ เซิร์ฟเวอร์ HTTP ในบริการไคลเอ็นต์มีการใช้งานร่วมกับ net/http และคุณใช้แพ็กเกจ otelhttp ได้เหมือนกับที่เราทำในโหลด

ก่อนอื่น เราแทนที่การลงทะเบียนตัวแฮนเดิลด้วยตัวแฮนเดิล otelhttp ในฟังก์ชัน main ให้ค้นหาบรรทัดที่มีการลงทะเบียนตัวแฮนเดิล HTTP กับ 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)

จากนั้น เราวัดระยะเวลาจริงภายในเครื่องจัดการ ค้นหาเครื่องจัดการฟังก์ (*clientService)() และเพิ่มการวัดระยะเวลาด้วย 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
        ...

เมื่อใช้การวัดนี้ คุณจะได้รับระยะเวลาตั้งแต่ต้นของเมธอด handler จนถึงสิ้นสุด เพื่อให้วิเคราะห์ระยะเวลาได้ง่าย ให้เพิ่มแอตทริบิวต์เพิ่มเติมที่จัดเก็บจำนวนที่ตรงกันไปยังข้อความค้นหา เพิ่มโค้ดต่อไปนี้ก่อนบรรทัดบันทึก

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

การใช้เครื่องมือทั้งหมดข้างต้นช่วยให้คุณทำการใช้เครื่องมือการติดตามระหว่างภาระงานและไคลเอ็นต์ได้เสร็จสมบูรณ์ มาดูวิธีการทำงานของฟังก์ชันนี้กัน เรียกใช้โค้ดด้วย Skaffold อีกครั้ง

skaffold dev

หลังจากเรียกใช้บริการบนคลัสเตอร์ GKE มาระยะหนึ่งแล้ว คุณจะเห็นข้อความบันทึกจำนวนมากเช่นนี้

เอาต์พุตจากคำสั่ง

[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 จะส่งข้อความเหล่านี้ คุณจะเห็นว่าสแปนระดับบนของสแปนตามโหลดมี TraceID: 00000000000000000000000000000000 เพราะนี่คือสแปนราก ซึ่งก็คือสแปนแรกในการติดตาม นอกจากนี้ คุณยังพบว่าแอตทริบิวต์การฝัง "query" มีสตริงคำค้นหาที่ส่งไปยังฝ่ายบริการลูกค้า

สรุป

ในขั้นตอนนี้ คุณได้ติดตั้งบริการตัวสร้างโหลดและบริการไคลเอ็นต์ที่สื่อสารใน HTTP และยืนยันว่าคุณสามารถเผยแพร่ Trace Context ไปยังบริการต่างๆ และส่งออกข้อมูล Span จากทั้ง 2 บริการไปยัง Sttdout ได้สำเร็จ

ถัดไป

ในขั้นตอนถัดไป คุณจะต้องใช้บริการลูกค้าและบริการเซิร์ฟเวอร์เพื่อยืนยันวิธีเผยแพร่บริบทการติดตามผ่าน gRPC

5. การวัดคุมสำหรับ gRPC

ในขั้นตอนก่อนหน้า เราได้บังคับใช้ช่วงครึ่งแรกของคำขอใน Microservice นี้ ในขั้นตอนนี้ เราพยายามวัดคุมการสื่อสารด้วย gRPC ระหว่างบริการลูกค้าและบริการของเซิร์ฟเวอร์ (สี่เหลี่ยมผืนผ้าสีเขียวและม่วงในรูปภาพด้านล่าง)

75310d8e0e3b1a30.png

การใช้เครื่องมือก่อนการสร้างสำหรับไคลเอ็นต์ gRPC

ระบบนิเวศของ OpenTelemetry มีไลบรารีที่มีประโยชน์มากมายซึ่งช่วยให้นักพัฒนาซอฟต์แวร์วัดคุมแอปพลิเคชันได้ ในขั้นตอนก่อนหน้า เราใช้เครื่องมือก่อนสร้างสำหรับแพ็กเกจ net/http ในขั้นตอนนี้ เมื่อเราพยายามเผยแพร่บริบทการติดตามผ่าน gRPC เราจะใช้ไลบรารีสำหรับการติดตาม

ก่อนอื่น ให้คุณนำเข้าแพ็กเกจ gRPC ที่สร้างไว้ล่วงหน้าชื่อ 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"
)

ครั้งนี้บริการไคลเอ็นต์จะเป็นไคลเอ็นต์ gRPC เทียบกับบริการเซิร์ฟเวอร์ คุณจึงต้องใช้เครื่องมือไคลเอ็นต์ gRPC ค้นหาฟังก์ชัน mustConnGRPC และเพิ่มตัวสกัดกั้น gRPC ที่สร้างสแปนใหม่ทุกครั้งที่ไคลเอ็นต์ส่งคำขอไปยังเซิร์ฟเวอร์

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 ในหัวข้อก่อนหน้าไว้แล้ว จึงไม่จำเป็นต้องทำ

การใช้เครื่องมือที่สร้างไว้ล่วงหน้าสำหรับเซิร์ฟเวอร์ gRPC

เราเรียกเครื่องมือที่สร้างไว้ล่วงหน้าสำหรับเซิร์ฟเวอร์ gRPC เช่นเดียวกับที่เราทำกับไคลเอ็นต์ gRPC เพิ่มแพ็กเกจใหม่ในส่วนการนำเข้า เช่น

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

เนื่องจากนี่เป็นครั้งแรกสำหรับการใช้เครื่องมือเซิร์ฟเวอร์ คุณจึงต้องตั้งค่า OpenTelemetry ก่อน คล้ายกับที่เราทำสำหรับโหลดและให้บริการลูกค้า

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

ขั้นตอนต่อไป คุณจะต้องเพิ่มตัวสกัดกั้นเซิร์ฟเวอร์ ในฟังก์ชัน main ให้ค้นหาตำแหน่งที่มีการเรียก grpc.NewServer() แล้วเพิ่มอินเตอร์เซกเตอร์ลงในฟังก์ชัน

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

เรียกใช้ Microservice และยืนยันการติดตาม

จากนั้นเรียกใช้โค้ดที่แก้ไขแล้วด้วยคำสั่ง skaffold

skaffold dev

คุณจะเห็นข้อมูล span มากมายใน stdout

เอาต์พุตจากคำสั่ง

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

คุณสังเกตเห็นว่าคุณไม่ได้ฝังชื่อสแปนใดๆ และระยะเวลาที่สร้างขึ้นด้วยตนเองโดยใช้ trace.Start() หรือ span.SpanFromContext() แต่คุณยังได้รับ Span จำนวนมากเนื่องจาก Interceptor ของ gRPC สร้างขึ้น

สรุป

ในขั้นตอนนี้ คุณใช้การสื่อสารที่ใช้ gRPC ด้วยการสนับสนุนจากไลบรารีระบบนิเวศ OpenTelemetry

ถัดไป

ในขั้นตอนถัดไป คุณจะแสดงภาพการติดตามด้วย Cloud Trace และดูวิธีวิเคราะห์ระยะเวลาที่เก็บรวบรวม

6. แสดงภาพการติดตามด้วย Cloud Trace

คุณมีการติดตามในเครื่องทั้งระบบด้วย OpenTelemetry คุณได้เรียนรู้วิธีใช้งานบริการ HTTP และ gRPC แล้ว แม้คุณจะเรียนรู้วิธีใช้งานเครื่องมือดังกล่าวไปแล้ว แต่ก็ยังไม่ได้เรียนรู้วิธีวิเคราะห์เครื่องมือ ในส่วนนี้ คุณจะใช้ผู้ส่งออก Cloud Trace แทนผู้ส่งออก stdout และดูวิธีวิเคราะห์การติดตาม

ใช้เครื่องมือส่งออก Cloud Trace

คุณสมบัติที่ทรงพลังอย่างหนึ่งของ OpenTelemetry คือความสามารถในการเสียบปลั๊ก หากต้องการดูภาพ Span ทั้งหมดที่เก็บรวบรวมตามเครื่องมือของคุณ สิ่งที่คุณต้องทำมีเพียงการแทนที่ผู้ส่งออก Stdout ด้วยเครื่องมือส่งออก Cloud Trace

เปิดไฟล์ main.go ไฟล์ของแต่ละบริการ และค้นหาฟังก์ชัน initTracer() โปรดลบบรรทัดดังกล่าวเพื่อสร้างเครื่องมือส่งออก Stdout และสร้างเครื่องมือส่งออก 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
}

คุณต้องแก้ไขฟังก์ชันเดียวกันในบริการไคลเอ็นต์และเซิร์ฟเวอร์ด้วย

เรียกใช้ Microservice และยืนยันการติดตาม

หลังจากแก้ไขแล้ว ให้เรียกใช้คลัสเตอร์ตามปกติด้วยคำสั่ง Skaffold

skaffold dev

ตอนนี้คุณจะไม่เห็นข้อมูล span จำนวนมากในรูปแบบบันทึกที่มีโครงสร้างใน stdout เนื่องจากคุณได้แทนที่ผู้ส่งออกด้วย Cloud Trace

เอาต์พุตจากคำสั่ง

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

ตอนนี้ให้ยืนยันว่าส่ง Span ทั้งหมดไปยัง Cloud Trace อย่างถูกต้องหรือไม่ เข้าถึง Cloud Console แล้วไปที่ "รายการการติดตาม" คุณสามารถเข้าถึงได้ง่ายๆ จากช่องค้นหา หรือคลิกเมนูในแผงด้านซ้าย 8b3f8411bd737e06.png

จากนั้นคุณจะเห็นจุดสีน้ำเงินจำนวนมากกระจายอยู่ในกราฟเวลาในการตอบสนอง แต่ละจุดจะแสดงการติดตามเดียว

3ecf131423fc4c40.png

คลิกตัวเลือกที่ต้องการเพื่อดูรายละเอียดภายในการติดตาม 4fd10960c6648a03.png

แม้จะดูง่ายๆ เพียงสั้นๆ นี้แล้ว คุณก็รู้ข้อมูลเชิงลึกมากมายอยู่แล้ว ตัวอย่างเช่น จากกราฟ Waterfall คุณจะเห็นว่าสาเหตุของเวลาในการตอบสนองนั้นส่วนใหญ่เกิดจากสแปนที่ชื่อว่า shakesapp.ShakespeareService/GetMatchCount (ดู 1 ในรูปภาพด้านบน) คุณสามารถยืนยันได้จากตารางสรุป (คอลัมน์ด้านขวาสุดแสดงระยะเวลาของแต่ละช่วง) นอกจากนี้ การติดตามนี้ยังใช้สำหรับคำค้นหา "เพื่อน" (ดู 2 ในรูปภาพด้านบน)

จากการวิเคราะห์สั้นๆ เหล่านี้ คุณอาจพบว่าต้องการรู้ระยะเวลาที่ละเอียดขึ้นในเมธอด GetMatchCount เมื่อเทียบกับข้อมูล stdout การแสดงภาพนั้นมีประสิทธิภาพมาก หากต้องการดูข้อมูลเพิ่มเติมเกี่ยวกับรายละเอียด Cloud Trace โปรดไปที่เอกสารอย่างเป็นทางการ

สรุป

ในขั้นตอนนี้ คุณได้แทนที่เครื่องมือส่งออก stdout ด้วย Cloud Trace 1 และแสดงภาพการติดตามบน Cloud Trace และคุณยังได้เรียนรู้วิธีเริ่มวิเคราะห์การติดตามด้วย

ถัดไป

ในขั้นตอนถัดไป คุณจะต้องแก้ไขซอร์สโค้ดของบริการเซิร์ฟเวอร์เพื่อเพิ่มช่วงเวลาย่อยใน GetMatchCount

7. เพิ่มช่วงย่อยเพื่อให้วิเคราะห์ได้ดีขึ้น

ในขั้นตอนก่อนหน้า คุณพบสาเหตุของระยะเวลาไป-กลับที่สังเกตจากการโหลดเกนมักเป็นกระบวนการภายในเมธอด GetMatchCount ซึ่งเป็นตัวแฮนเดิล gRPC ในบริการเซิร์ฟเวอร์ อย่างไรก็ตาม เนื่องจากเราไม่ได้ใช้เครื่องมืออื่นใดนอกเหนือจากเครื่องจัดการ ทำให้เราไม่สามารถดูข้อมูลเชิงลึกเพิ่มเติมจากกราฟ Waterfall ซึ่งเป็นกรณีที่พบบ่อยเมื่อเราเริ่มวัดคุม Microservice

3b63a1e471dddb8c.png

ในส่วนนี้ เราจะกล่าวถึงช่วงย่อยที่เซิร์ฟเวอร์เรียกใช้ Google Cloud Storage เนื่องจากเป็นเรื่องปกติที่ I/O เครือข่ายภายนอกบางรายการใช้เวลานานในกระบวนการนี้ และสิ่งสำคัญคือต้องระบุว่าการโทรเป็นสาเหตุหรือไม่

วัดระยะเวลาย่อยในเซิร์ฟเวอร์

เปิด main.go ในเซิร์ฟเวอร์และค้นหาฟังก์ชัน readFiles ฟังก์ชันนี้เรียกใช้คำขอไปยัง Google Cloud Storage เพื่อดึงไฟล์ข้อความทั้งหมดของเชกสเปียร์ ในฟังก์ชันนี้ คุณจะสร้างช่วงเวลาย่อยได้ เช่น สิ่งที่คุณทำสำหรับการวัดคุมเซิร์ฟเวอร์ HTTP ในบริการไคลเอ็นต์

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

ทั้งหมดนี้คือวิธีเพิ่มระยะเวลาใหม่ มาดูกันว่าผลเป็นอย่างไรเมื่อเรียกใช้แอป

เรียกใช้ Microservice และยืนยันการติดตาม

หลังจากแก้ไขแล้ว ให้เรียกใช้คลัสเตอร์ตามปกติด้วยคำสั่ง Skaffold

skaffold dev

และเลือกการติดตาม 1 รายการที่ชื่อ query.request จากรายการการติดตาม คุณจะเห็นกราฟ Waterfall การติดตามที่คล้ายกันยกเว้นระยะเวลาใหม่ที่ต่ำกว่า shakesapp.ShakespeareService/GetMatchCount (ช่วงระยะเวลาที่อยู่ในรูปสี่เหลี่ยมผืนผ้าสีแดงด้านล่าง)

3d4a891aa30d7a32.png

สิ่งที่คุณสามารถบอกได้จากกราฟนี้ในตอนนี้คือการเรียกภายนอกไปยัง Google Cloud Storage จะใช้เวลาในการตอบสนองปริมาณมาก แต่ยังคงมีสิ่งอื่นๆ ที่ทำให้เวลาในการตอบสนองส่วนใหญ่ยังคงเป็นอยู่

คุณได้รับข้อมูลเชิงลึกมากมายจากกราฟ Waterfall ของการติดตาม 2-3 รูปแบบแล้ว คุณจะได้รับรายละเอียดด้านประสิทธิภาพเพิ่มเติมในใบสมัครได้อย่างไร จากตรงนี้ เครื่องมือสร้างโปรไฟล์จะเข้ามา แต่ในตอนนี้เราจะทำให้ตอนท้ายของ Codelab นี้จบลง และนำเสนอบทแนะนำเครื่องมือสร้างโปรไฟล์ทั้งหมดในตอนที่ 2

สรุป

ในขั้นตอนนี้ คุณได้ใช้อีกช่วงเวลาหนึ่งในบริการเซิร์ฟเวอร์ และได้รับข้อมูลเชิงลึกเพิ่มเติมเกี่ยวกับเวลาในการตอบสนองของระบบ

8. ขอแสดงความยินดี

คุณสร้างการติดตามแบบกระจายด้วย OpenTelemery และยืนยันเวลาในการตอบสนองของคำขอสำหรับ Microservice บน Google Cloud Trace เรียบร้อยแล้ว

สำหรับการออกกำลังกายระยะยาว คุณลองทำตามหัวข้อต่อไปนี้ด้วยตนเองได้

  • การใช้งานปัจจุบันจะส่ง Span ทั้งหมดที่สร้างโดยการตรวจสอบประสิทธิภาพการทำงาน (grpc.health.v1.Health/Check) คุณจะกรองระยะเวลาเหล่านั้นออกจาก Cloud Traces อย่างไร คำแนะนำอยู่ที่นี่
  • เชื่อมโยงบันทึกเหตุการณ์กับระยะเวลา แล้วดูว่าบันทึกนั้นทำงานอย่างไรใน Google Cloud Trace และ Google Cloud Logging คำแนะนำอยู่ที่นี่
  • แทนที่บางบริการด้วยบริการที่เป็นภาษาอื่น แล้วลองใช้ OpenTelemetry สำหรับภาษานั้น

นอกจากนี้ ถ้าคุณต้องการทราบเกี่ยวกับเครื่องมือสร้างโปรไฟล์หลังจากนี้ โปรดไปยังส่วนที่ 2 ในกรณีนี้ คุณสามารถข้ามส่วน "ล้างข้อมูล" ด้านล่างได้

ล้างข้อมูล

หลังจาก Codelab นี้ โปรดหยุดคลัสเตอร์ Kubernetes และตรวจสอบว่าได้ลบโปรเจ็กต์แล้ว เพื่อไม่ให้มีการเรียกเก็บเงินที่ไม่คาดคิดใน Google Kubernetes Engine, Google Cloud Trace, Google Artifact Registry

ขั้นแรก ให้ลบคลัสเตอร์ หากคุณเรียกใช้คลัสเตอร์ด้วย skaffold dev คุณเพียงแค่กด Ctrl-C หากคุณกำลังเรียกใช้คลัสเตอร์ด้วย skaffold run ให้เรียกใช้คำสั่งต่อไปนี้

skaffold delete

เอาต์พุตจากคำสั่ง

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

หลังจากลบคลัสเตอร์แล้ว ให้เลือก "IAM & จากแผงเมนู ผู้ดูแลระบบ" "การตั้งค่า" แล้วคลิก "ปิด"

45aa37b7d5e1ddd1.png

จากนั้นป้อนรหัสโปรเจ็กต์ (ไม่ใช่ชื่อโปรเจ็กต์) ในแบบฟอร์มในกล่องโต้ตอบและยืนยันการปิดเครื่อง