เครื่องมือสำหรับเพิ่มประสิทธิภาพของแอปใน 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

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

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

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

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

การติดตาม

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

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

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

44e243182ced442f.png

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

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

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

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

Codelab นี้อธิบายวิธีติดตั้งเครื่องมือในไมโครเซอร์วิส ตัวอย่างนี้มีเพียง 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 ทั้งหมด (ชื่อด้านบนมีผู้ใช้แล้วและจะใช้ไม่ได้ ขออภัย) ซึ่งจะเรียกว่า PROJECT_ID ในภายหลังใน Codelab นี้

จากนั้นหากยังไม่ได้ดำเนินการ คุณจะต้องเปิดใช้การเรียกเก็บเงินใน 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 จากระยะไกลในแล็ปท็อปได้ แต่ใน Codelab นี้เราจะใช้ Google Cloud Shell ซึ่งเป็นสภาพแวดล้อมบรรทัดคำสั่งที่ทำงานในระบบคลาวด์

เครื่องเสมือนที่ใช้ Debian นี้มาพร้อมเครื่องมือพัฒนาทั้งหมดที่คุณต้องการ โดยมีไดเรกทอรีหลักแบบถาวรขนาด 5 GB และทำงานใน Google Cloud ซึ่งช่วยเพิ่มประสิทธิภาพเครือข่ายและการตรวจสอบสิทธิ์ได้อย่างมาก ซึ่งหมายความว่าคุณจะต้องมีเพียงเบราว์เซอร์เท่านั้นสำหรับโค้ดแล็บนี้ (ใช่แล้ว ใช้ได้ใน 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 2017-06-14 at 10.13.43 PM.png

เมื่อเชื่อมต่อกับ 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

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

ไปที่การตั้งค่าภาษา

ใน 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" และประเภทตำแหน่งคือ "Region" เลือกภูมิภาคที่ใกล้กับภูมิภาคที่คุณตั้งค่าสำหรับโซนเริ่มต้นของ Google Compute Engine ตัวอย่างเช่น ตัวอย่างนี้เลือก "us-central1-f" ด้านบน ดังนั้นเราจึงเลือก "us-central1 (ไอโอวา)" ที่นี่ จากนั้นคลิกปุ่ม "สร้าง"

9c2d1ce65258ef70.png

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

7a3c1f47346bea15.png

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

การตั้งค่า Skaffold

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

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

skaffold version

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

v1.38.0

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

7a3c1f47346bea15.png

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

e0f2ae2144880b8b.png

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

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

กลับไปที่ 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 สำหรับ Container Registry
  • ตั้งค่า Skaffold เพื่อใช้ Container Registry
  • สร้างคลัสเตอร์ Kubernetes ที่ไมโครเซอร์วิสของ Codelab ทำงาน

ถัดไป

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

3. สร้าง พุช และติดตั้งใช้งานไมโครเซอร์วิส

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

ในขั้นตอนก่อนหน้า เราได้ตั้งค่าข้อกำหนดเบื้องต้นทั้งหมดสำหรับ Codelab นี้แล้ว ตอนนี้คุณพร้อมที่จะเรียกใช้ไมโครเซอร์วิสทั้งหมดบนแพลตฟอร์มดังกล่าวแล้ว เนื้อหา Codelab โฮสต์อยู่ใน GitHub ดังนั้นให้ดาวน์โหลดลงในสภาพแวดล้อมของ Shell ใน 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
  • manifests: ไฟล์ 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 ในสภาพแวดล้อมและยืนยันว่า Skaffold ทำงานตามที่คาดไว้

ถัดไป

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

4. การวัดคุมสำหรับ HTTP

แนวคิดของการวัดคุมและการเผยแพร่การติดตาม

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

6be42e353b9bfd1d.png

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

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

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

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

คอมโพเนนต์ในการติดตาม OpenTelemetry

b01f7bb90188db0d.png

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

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

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

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

เมื่อเข้าใจเรื่องนี้แล้ว เรามาดูงานเขียนโค้ดจริงกัน

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

บริการเครื่องมือสร้างภาระงาน

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

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 เพื่อสร้าง Span ที่กำหนดเองโดยใช้ OpenTelemetry และ Span ที่สร้างขึ้นโดยอัตโนมัติจากไคลเอ็นต์ HTTP ที่กำหนดเอง สิ่งที่คุณต้องทำมีดังนี้

  1. รับ Tracer จาก 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)
        }

ตอนนี้คุณได้ทำการวัดคุมใน Loadgen (แอปพลิเคชันไคลเอ็นต์ 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
)

อีกครั้งที่เราต้องตั้งค่า OpenTelemetry เพียงคัดลอกและวางฟังก์ชัน initTracer จาก loadgen แล้วเรียกใช้ในฟังก์ชัน 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
}

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

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

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

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

สรุป

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

ถัดไป

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

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

ในขั้นตอนก่อนหน้า เราได้ติดตั้งเครื่องมือในครึ่งแรกของคำขอในไมโครเซอร์วิสนี้ ในขั้นตอนนี้ เราจะพยายามวัดการสื่อสาร 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 ก่อน เช่นเดียวกับที่เราทำสำหรับบริการ Loadgen และไคลเอ็นต์

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

เรียกใช้ไมโครเซอร์วิสและยืนยันการติดตาม

จากนั้นเรียกใช้โค้ดที่แก้ไขด้วยคำสั่ง 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] }
...

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

สรุป

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

ถัดไป

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

6. แสดงภาพร่องรอยด้วย Cloud Trace

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

ใช้เครื่องมือส่งออก 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
}

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

เรียกใช้ไมโครเซอร์วิสและยืนยันการติดตาม

หลังจากแก้ไขแล้ว ให้เรียกใช้คลัสเตอร์ตามปกติด้วยคำสั่ง 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
...

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

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

3ecf131423fc4c40.png

คลิกรายการใดรายการหนึ่ง แล้วคุณจะเห็นรายละเอียดภายในร่องรอย 4fd10960c6648a03.png

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

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

สรุป

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

ถัดไป

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

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

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

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

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

เรียกใช้ไมโครเซอร์วิสและยืนยันการติดตาม

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

skaffold dev

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

3d4a891aa30d7a32.png

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

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

สรุป

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

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

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

หากต้องการฝึกเพิ่มเติม คุณสามารถลองทำตามหัวข้อต่อไปนี้ด้วยตนเอง

  • การติดตั้งใช้งานปัจจุบันจะส่งช่วงทั้งหมดที่สร้างขึ้นโดยการตรวจสอบประสิทธิภาพการทำงาน (grpc.health.v1.Health/Check) คุณกรองช่วงเหล่านั้นออกจาก Cloud Trace ได้อย่างไร ดูเคล็ดลับได้ที่นี่
  • เชื่อมโยงบันทึกเหตุการณ์กับช่วง และดูวิธีการทำงานใน 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

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