1. บทนำ
อัปเดตล่าสุด: 15-07-2022
ความสามารถในการสังเกตการณ์แอปพลิเคชัน
ความสามารถในการสังเกตการณ์และ OpenTelemetry
การสังเกตการณ์เป็นคําที่ใช้อธิบายแอตทริบิวต์ของระบบ ระบบที่มีการสังเกตการณ์ช่วยให้ทีมแก้ไขข้อบกพร่องของระบบได้อย่างต่อเนื่อง ในบริบทนี้ เสาหลัก 3 ประการของความสามารถในการสังเกตการณ์ ได้แก่ บันทึก เมตริก และร่องรอย เป็นเครื่องวัดพื้นฐานสําหรับให้ระบบมีความสามารถในการสังเกตการณ์
OpenTelemetry คือชุดข้อกำหนด ไลบรารี และตัวแทนที่เร่งความเร็วของเครื่องมือวัดและการส่งออกข้อมูลการวัด (บันทึก เมตริก และร่องรอย) ที่ความสามารถในการสังเกตการณ์จําเป็นต้องใช้ OpenTelemetry เป็นมาตรฐานแบบเปิดและโปรเจ็กต์ที่ขับเคลื่อนโดยชุมชนภายใต้ CNCF การใช้ไลบรารีที่โปรเจ็กต์และระบบนิเวศของโปรเจ็กต์มีให้จะช่วยให้นักพัฒนาแอปพลิเคชันสามารถวัดผลแอปพลิเคชันของตนในลักษณะที่เป็นกลางต่อผู้ให้บริการและกับสถาปัตยกรรมหลายแบบ
นอกจากนี้ นอกเหนือจากเสาหลัก 3 ประการของความสามารถในการสังเกตการณ์แล้ว การสร้างโปรไฟล์อย่างต่อเนื่องยังเป็นองค์ประกอบหลักอีกอย่างหนึ่งของความสามารถในการสังเกตการณ์ และขยายฐานผู้ใช้ในอุตสาหกรรมด้วย Cloud Profiler เป็นหนึ่งในเครื่องมือสําคัญและให้บริการอินเทอร์เฟซที่ใช้งานง่ายในการเจาะลึกเมตริกประสิทธิภาพในกองคําเรียกแอปพลิเคชัน
โค้ดแล็บนี้เป็นส่วนหนึ่งของชุดที่ 1 ซึ่งครอบคลุมเครื่องมือวัดร่องรอยแบบกระจายในไมโครเซอร์วิสด้วย OpenTelemetry และ Cloud Trace ส่วนที่ 2 จะกล่าวถึงการสร้างโปรไฟล์อย่างต่อเนื่องด้วย Cloud Profiler
การติดตามแบบกระจาย
ในการติดตาม บันทึก เมตริก และการติดตาม ข้อมูลการติดตามเป็นข้อมูลการวัดผลที่บอกเวลาในการตอบสนองของส่วนใดส่วนหนึ่งของกระบวนการในระบบ โดยเฉพาะอย่างยิ่งในยุคของไมโครเซอร์วิส การติดตามแบบกระจายเป็นปัจจัยที่กระตุ้นให้ค้นหาปัญหาคอขวดด้านเวลาในการตอบสนองในระบบแบบกระจายโดยรวม
เมื่อวิเคราะห์การติดตามแบบกระจาย การแสดงภาพข้อมูลการติดตามเป็นกุญแจสำคัญในการจับภาพเวลาในการตอบสนองโดยรวมของระบบได้อย่างรวดเร็ว ในการติดตามแบบกระจาย เราจะจัดการชุดการเรียกให้ประมวลผลคําขอเดียวไปยังจุดแรกเข้าของระบบในรูปแบบการติดตามที่มีหลายช่วง
ช่วงเวลาแสดงถึงหน่วยงานแต่ละหน่วยที่ทําในระบบแบบกระจาย โดยบันทึกเวลาเริ่มต้นและเวลาสิ้นสุด โดยทั่วไปแล้ว แต่ละช่วงมักจะมีความสัมพันธ์แบบลําดับชั้นต่อกัน ในภาพด้านล่าง ช่วงขนาดเล็กทั้งหมดเป็นช่วงย่อยของช่วง /messages ขนาดใหญ่ และประกอบกันเป็นการติดตามรายการเดียวซึ่งแสดงเส้นทางของงานในระบบ
Google Cloud Trace เป็นหนึ่งในตัวเลือกสําหรับแบ็กเอนด์การติดตามแบบกระจาย และผสานรวมกับผลิตภัณฑ์อื่นๆ ใน Google Cloud ได้อย่างดี
สิ่งที่คุณจะสร้าง
ในโค้ดแล็บนี้ คุณจะได้ติดตั้งเครื่องมือติดตามข้อมูลในบริการที่เรียกว่า "แอปพลิเคชัน Shakespeare" (หรือที่เรียกว่า Shakesapp) ที่ทำงานบนคลัสเตอร์ Google Kubernetes Engine สถาปัตยกรรมของ Shakesapp มีดังนี้
- Loadgen ส่งสตริงการค้นหาไปยังไคลเอ็นต์ใน HTTP
- ไคลเอ็นต์ส่งคําค้นหาจาก Loadgen ไปยังเซิร์ฟเวอร์ใน gRPC
- เซิร์ฟเวอร์ยอมรับการค้นหาจากไคลเอ็นต์ ดึงข้อมูลผลงานทั้งหมดของ Shakespeare ในรูปแบบข้อความจาก Google Cloud Storage ค้นหาบรรทัดที่มีคําค้นหา และแสดงจํานวนบรรทัดที่ตรงกับไคลเอ็นต์
คุณจะเครื่องมือวัดข้อมูลการติดตามในคําขอ หลังจากนั้น ให้ฝังตัวแทนเครื่องมือวิเคราะห์โปรไฟล์ในเซิร์ฟเวอร์และตรวจสอบปัญหาคอขวด
สิ่งที่คุณจะได้เรียนรู้
- วิธีเริ่มต้นใช้งานไลบรารีการติดตาม OpenTelemetry ในโปรเจ็กต์ Go
- วิธีสร้างช่วงด้วยไลบรารี
- วิธีเผยแพร่บริบทของช่วงระหว่างคอมโพเนนต์แอป
- วิธีส่งข้อมูลการติดตามไปยัง Cloud Trace
- วิธีวิเคราะห์การติดตามใน Cloud Trace
โค้ดแล็บนี้อธิบายวิธีเครื่องมือวัดผลไมโครเซอร์วิส ตัวอย่างนี้มีเพียง 3 คอมโพเนนต์ (เครื่องมือสร้างโหลด ไคลเอ็นต์ และเซิร์ฟเวอร์) เพื่อให้เข้าใจได้ง่าย แต่คุณใช้กระบวนการเดียวกันที่อธิบายไว้ในโค้ดแล็บนี้กับระบบที่ซับซ้อนและขนาดใหญ่มากขึ้นได้
สิ่งที่ต้องมี
- ความรู้พื้นฐานเกี่ยวกับ Go
- ความรู้พื้นฐานเกี่ยวกับ Kubernetes
2. การตั้งค่าและข้อกําหนด
การตั้งค่าสภาพแวดล้อมด้วยตนเอง
หากยังไม่มีบัญชี Google (Gmail หรือ Google Apps) คุณต้องสร้างบัญชี ลงชื่อเข้าใช้คอนโซล Google Cloud Platform ( console.cloud.google.com) และสร้างโปรเจ็กต์ใหม่
หากคุณมีโปรเจ็กต์อยู่แล้ว ให้คลิกเมนูแบบเลื่อนลงเพื่อเลือกโปรเจ็กต์ที่ด้านซ้ายบนของคอนโซล
และคลิกปุ่ม "โปรเจ็กต์ใหม่" ในกล่องโต้ตอบที่ปรากฏขึ้นเพื่อสร้างโปรเจ็กต์ใหม่
หากยังไม่มีโปรเจ็กต์ คุณควรเห็นกล่องโต้ตอบเช่นนี้เพื่อสร้างโปรเจ็กต์แรก
กล่องโต้ตอบการสร้างโปรเจ็กต์ที่ตามมาจะช่วยให้คุณป้อนรายละเอียดของโปรเจ็กต์ใหม่ได้ ดังนี้
โปรดจดจำรหัสโปรเจ็กต์ ซึ่งเป็นชื่อที่ไม่ซ้ำกันในโปรเจ็กต์ Google Cloud ทั้งหมด (ชื่อด้านบนมีผู้ใช้แล้วและจะใช้ไม่ได้ ต้องขออภัยด้วย) ซึ่งจะเรียกว่า PROJECT_ID ในภายหลังในโค้ดแล็บนี้
ถัดไป คุณจะต้องเปิดใช้การเรียกเก็บเงินในคอนโซลนักพัฒนาซอฟต์แวร์เพื่อใช้ทรัพยากร Google Cloud และเปิดใช้ Cloud Trace API หากยังไม่ได้ดำเนินการ
ค่าใช้จ่ายในการเรียกใช้ Codelab นี้ไม่ควรเกิน 200 บาท แต่อาจมากกว่านั้นหากคุณตัดสินใจใช้ทรัพยากรเพิ่มเติมหรือปล่อยไว้ให้ทำงาน (ดูส่วน "ล้างข้อมูล" ที่ท้ายเอกสารนี้) ดูราคาของ Google Cloud Trace, Google Kubernetes Engine และ Google Artifact Registry ได้ในเอกสารประกอบอย่างเป็นทางการ
- ราคาของชุดเครื่องมือการดำเนินการของ Google Cloud | ชุดเครื่องมือการดำเนินการ
- ราคา | เอกสารประกอบของ Kubernetes Engine
- ราคา Artifact Registry | เอกสารประกอบเกี่ยวกับ Artifact Registry
ผู้ใช้ใหม่ของ Google Cloud Platform มีสิทธิ์รับช่วงทดลองใช้ฟรีมูลค่า$300 ซึ่งจะทำให้โค้ดแล็บนี้ไม่มีค่าใช้จ่ายใดๆ ทั้งสิ้น
การตั้งค่า Google Cloud Shell
แม้ว่า Google Cloud และ Google Cloud Trace จะทำงานจากระยะไกลจากแล็ปท็อปได้ แต่ในโค้ดแล็บนี้เราจะใช้ Google Cloud Shell ซึ่งเป็นสภาพแวดล้อมบรรทัดคำสั่งที่ทำงานในระบบคลาวด์
เครื่องเสมือนที่ใช้ Debian นี้จะโหลดเครื่องมือการพัฒนาทั้งหมดที่คุณต้องการ ซึ่งจะมีไดเรกทอรีหลักขนาด 5 GB ถาวรและทำงานใน Google Cloud ซึ่งช่วยเพิ่มประสิทธิภาพเครือข่ายและการรับรองได้อย่างมีประสิทธิภาพ ซึ่งหมายความว่าสิ่งที่คุณต้องใช้สำหรับโค้ดแล็บนี้ก็มีเพียงเบราว์เซอร์ (ใช่ โค้ดแล็บนี้ใช้ได้ใน Chromebook)
หากต้องการเปิดใช้งาน Cloud Shell จาก Cloud Console เพียงคลิกเปิดใช้งาน Cloud Shell (ระบบจะใช้เวลาเพียงไม่กี่นาทีในการเตรียมการและเชื่อมต่อกับสภาพแวดล้อม)
เมื่อเชื่อมต่อกับ 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
นอกจากนี้ 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
ในโค้ดแล็บนี้ คุณจะเรียกใช้คลัสเตอร์ของไมโครเซอร์วิสใน Google Kubernetes Engine (GKE) กระบวนการของโค้ดแล็บนี้มีดังนี้
- ดาวน์โหลดโปรเจ็กต์พื้นฐานลงใน Cloud Shell
- สร้าง Microservice ลงในคอนเทนเนอร์
- อัปโหลดคอนเทนเนอร์ไปยัง Google Artifact Registry (GAR)
- ทำให้คอนเทนเนอร์ใช้งานได้ใน GKE
- แก้ไขซอร์สโค้ดของบริการสําหรับเครื่องมือวัดร่องรอย
- ไปที่ขั้นตอนที่ 2
เปิดใช้ Kubernetes Engine
ก่อนอื่นเราต้องตั้งค่าคลัสเตอร์ Kubernetes ที่ Shakesapp ทำงานบน GKE ดังนั้นเราต้องเปิดใช้ GKE ไปที่เมนู "Kubernetes Engine" แล้วกดปุ่มเปิดใช้งาน
ตอนนี้คุณก็พร้อมสร้างคลัสเตอร์ 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" แล้วกดปุ่มเปิดใช้งาน
หลังจากนั้นสักครู่ คุณจะเห็นเบราว์เซอร์ที่เก็บของ GAR คลิกปุ่ม "สร้างที่เก็บข้อมูล" แล้วป้อนชื่อที่เก็บข้อมูล
ในโค้ดแล็บนี้ เราจะตั้งชื่อที่เก็บข้อมูลใหม่ว่า trace-codelab
รูปแบบของอาร์ติแฟกต์คือ "Docker" และประเภทตำแหน่งคือ "ภูมิภาค" เลือกภูมิภาคที่อยู่ใกล้กับภูมิภาคที่คุณกำหนดเป็นโซนเริ่มต้นของ Google Compute Engine ตัวอย่างเช่น ในตัวอย่างนี้ เราได้เลือก "us-central1-f" ด้านบน ดังนั้นเราจะเลือก "us-central1 (Iowa)" ที่นี่ จากนั้นคลิกปุ่ม "สร้าง"
ตอนนี้คุณจะเห็น "trace-codelab" ในเบราว์เซอร์ที่เก็บ
เราจะกลับมาที่นี่ในภายหลังเพื่อตรวจสอบเส้นทางรีจิสทรี
การตั้งค่า Skaffold
Skaffold เป็นเครื่องมือที่มีประโยชน์เมื่อคุณสร้างไมโครเซอร์วิสที่ทำงานบน Kubernetes ซึ่งจะจัดการเวิร์กโฟลว์ของการสร้าง การพุช และการนำคอนเทนเนอร์ของแอปพลิเคชันไปใช้ด้วยชุดคำสั่งเล็กๆ โดยค่าเริ่มต้น Skaffold จะใช้ Docker Registry เป็นรีจิสทรีคอนเทนเนอร์ คุณจึงต้องกําหนดค่า Skaffold ให้รู้จัก GAR เมื่อมีการพุชคอนเทนเนอร์
เปิด Cloud Shell อีกครั้งและยืนยันว่าได้ติดตั้ง skaffold แล้ว (Cloud Shell จะติดตั้ง skaffold ลงในสภาพแวดล้อมโดยค่าเริ่มต้น) เรียกใช้คำสั่งต่อไปนี้และดูเวอร์ชัน skaffold
skaffold version
เอาต์พุตจากคำสั่ง
v1.38.0
ตอนนี้คุณลงทะเบียนที่เก็บเริ่มต้นสำหรับ skaffold ได้แล้ว หากต้องการดูเส้นทางรีจิสทรี ให้ไปที่แดชบอร์ดรีจิสทรีอาร์ติแฟกต์ แล้วคลิกชื่อที่เก็บข้อมูลที่เพิ่งตั้งค่าไว้ในขั้นตอนก่อนหน้า
จากนั้นคุณจะเห็นเส้นทางเบรดครัมบ์ที่ด้านบนของหน้า คลิกไอคอน เพื่อคัดลอกเส้นทางรีจิสทรีไปยังคลิปบอร์ด
เมื่อคลิกปุ่มคัดลอก คุณจะเห็นกล่องโต้ตอบที่ด้านล่างของเบราว์เซอร์พร้อมข้อความดังต่อไปนี้
คัดลอก "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 สำหรับรีจิสทรีคอนเทนเนอร์
- ตั้งค่า skaffold เพื่อใช้ที่เก็บคอนเทนเนอร์
- สร้างคลัสเตอร์ Kubernetes ที่ไมโครเซอร์วิสของ Codelab ทำงานอยู่
วิดีโอถัดไป
ในขั้นตอนถัดไป คุณจะต้องสร้าง พุช และติดตั้งใช้งานไมโครเซอร์วิสในคลัสเตอร์
3. สร้าง พุช และทำให้ไมโครเซอร์วิสใช้งานได้
ดาวน์โหลดเนื้อหาใน 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
- 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
แนวคิดของเครื่องมือวัดและการนำไปใช้ของร่องรอย
ก่อนแก้ไขซอร์สโค้ด เราขออธิบายวิธีการทํางานของร่องรอยแบบกระจายในแผนภาพง่ายๆ สักเล็กน้อย
ในตัวอย่างนี้ เราจะใช้เครื่องมือวัดผลโค้ดเพื่อส่งออกข้อมูลการติดตามและช่วงไปยัง Cloud Trace และเผยแพร่บริบทการติดตามในคําขอจากบริการ loadgen ไปยังบริการเซิร์ฟเวอร์
แอปพลิเคชันต้องส่งข้อมูลเมตาการติดตาม เช่น รหัสการติดตามและรหัสสแปน เพื่อให้การติดตามในระบบคลาวด์รวบรวมสแปนทั้งหมดที่มีรหัสการติดตามเดียวกันเข้าด้วยกันเป็นข้อมูลการติดตามรายการเดียว นอกจากนี้ แอปพลิเคชันยังต้องเผยแพร่บริบทการติดตาม (การรวมรหัสการติดตามและรหัสสแปนของสแปนหลัก) ในบริการดาวน์สตรีมที่ต้องการ เพื่อให้ทราบบริบทการติดตามที่จัดการอยู่
OpenTelemetry ช่วยให้คุณทำสิ่งต่อไปนี้ได้
- เพื่อสร้างรหัสการติดตามและรหัสช่วงที่ไม่ซ้ำกัน
- เพื่อส่งออกรหัสการติดตามและรหัส Span ไปยังแบ็กเอนด์
- เพื่อเผยแพร่บริบทการติดตามไปยังบริการอื่นๆ
- เพื่อฝังข้อมูลเมตาเพิ่มเติมซึ่งช่วยในการวิเคราะห์ร่องรอย
คอมโพเนนต์ในการติดตาม OpenTelemetry
กระบวนการวัดการติดตามแอปพลิเคชันด้วย OpenTelemetry มีดังนี้
- สร้างผู้ส่งออก
- สร้าง TracerProvider ที่เชื่อมโยงกับตัวส่งออกใน 1 และตั้งค่าเป็นค่าส่วนกลาง
- ตั้งค่า TextMapPropagaror เพื่อตั้งค่าวิธีการนำไปใช้
- รับ Tracer จาก TracerProvider
- สร้าง Span จากเครื่องมือติดตาม
ในตอนนี้ คุณไม่จำเป็นต้องเข้าใจคุณสมบัติโดยละเอียดในแต่ละคอมโพเนนต์ แต่สิ่งที่ควรจำไว้ที่สำคัญที่สุดมีดังนี้
- ผู้ส่งออกที่นี่สามารถเสียบเข้ากับ TracerProvider
- TracerProvider จะเก็บการกําหนดค่าทั้งหมดเกี่ยวกับการสุ่มตัวอย่างและการส่งออกการติดตาม
- ร่องรอยทั้งหมดจะรวมอยู่ในออบเจ็กต์ Tracer
เมื่อเข้าใจแล้ว เรามาเริ่มเขียนโค้ดกัน
ช่วงแรกของเครื่องดนตรี
บริการเครื่องมือสร้างโหลด
เปิดเครื่องมือแก้ไข Cloud Shell โดยกดปุ่ม ที่ด้านขวาบนของ 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 ในรูปแบบ Structured
จากนั้นเรียกใช้จากฟังก์ชันหลัก เรียกใช้ 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 ที่กําหนดเอง สิ่งที่คุณต้องทำมีดังนี้
- รับ Tracer จาก
TracerProvider
ทั่วโลกด้วยotel.Tracer()
- สร้างช่วงรูทด้วยเมธอด
Tracer.Start()
- สิ้นสุดช่วงรูทตามเวลาที่กำหนด (ในกรณีนี้คือสิ้นสุดฟังก์ชัน
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
บริการลูกค้าเกี่ยวกับเครื่องดนตรี
ในส่วนก่อนหน้านี้ เราได้ติดตั้งเครื่องมือวัดในส่วนที่ล้อมรอบด้วยสี่เหลี่ยมผืนผ้าสีแดงในภาพวาดด้านล่าง เราติดตั้งเครื่องมือวัดข้อมูลช่วงในบริการสร้างจํานวนการเรียกใช้ ตอนนี้เราต้องติดตั้งเครื่องมือวัดบริการไคลเอ็นต์ ซึ่งคล้ายกับบริการสร้างโหลด ความแตกต่างจากบริการสร้างโหลดคือบริการไคลเอ็นต์ต้องดึงข้อมูลรหัสการติดตามที่เผยแพร่จากบริการสร้างโหลดในส่วนหัว HTTP และใช้รหัสเพื่อสร้าง Span
เปิด 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
จาก 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 }
ตอนนี้ถึงเวลาติดเครื่องมือวัดใน Span เนื่องจากบริการไคลเอ็นต์ต้องยอมรับคําขอ HTTP จากบริการ loadgen จึงต้องติดตั้งใช้งานตัวแฮนเดิล เซิร์ฟเวอร์ HTTP ในบริการไคลเอ็นต์ติดตั้งใช้งานด้วย net/http และคุณใช้แพ็กเกจ otelhttp
ได้เช่นเดียวกับที่เราทำใน loadgen
ก่อนอื่น เราจะแทนที่การลงทะเบียนตัวแฮนเดิลด้วยตัวแฮนเดิล 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)
จากนั้นเราจะติดตั้งเครื่องมือวัดสแปนจริงภายในตัวแฮนเดิล ค้นหา func (*clientService) handler() และเพิ่มเครื่องมือวัดผลสแปนด้วย 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
ไปจนถึงตอนท้าย หากต้องการให้วิเคราะห์ช่วงได้ง่าย ให้เพิ่มแอตทริบิวต์เพิ่มเติมที่จัดเก็บจํานวนรายการที่ตรงกันในคําค้นหา เพิ่มโค้ดต่อไปนี้ก่อนบรรทัดบันทึก
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 ระหว่างบริการไคลเอ็นต์และบริการเซิร์ฟเวอร์ (สี่เหลี่ยมผืนผ้าสีเขียวและสีม่วงในรูปภาพด้านล่าง)
เครื่องมือวัดผลก่อนการบิลด์สําหรับไคลเอ็นต์ 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
ตอนนี้คุณจะเห็นข้อมูลสแปนจำนวนมากใน 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()
ด้วยตนเอง แต่คุณยังคงเห็นสแปนจำนวนมากเนื่องจากตัวขัดจังหวะ gRPC สร้างขึ้น
สรุป
ในขั้นตอนนี้ คุณจะวัดผลการสื่อสารแบบ gRPC โดยได้รับความช่วยเหลือจากไลบรารีระบบนิเวศ OpenTelemetry
วิดีโอถัดไป
ในขั้นตอนถัดไป คุณจะเห็นภาพการติดตามด้วย Cloud Trace และเรียนรู้วิธีวิเคราะห์ช่วงข้อมูลที่รวบรวม
6. แสดงภาพการติดตามด้วย Cloud Trace
คุณได้ติดตั้งเครื่องมือวัดร่องรอยในทั้งระบบด้วย OpenTelemetry คุณได้เรียนรู้วิธีตรวจสอบบริการ HTTP และ gRPC ไปแล้ว แม้ว่าคุณจะได้เรียนรู้วิธีวัดผลแล้ว แต่ก็ยังไม่ทราบวิธีวิเคราะห์ ในส่วนนี้ คุณจะนำตัวส่งออก stdout ไปแทนที่ตัวส่งออก Cloud Trace และเรียนรู้วิธีวิเคราะห์การติดตาม
ใช้เครื่องมือส่งออก Cloud Trace
ลักษณะที่มีประสิทธิภาพอย่างหนึ่งของ OpenTelemetry คือความสามารถในการเสียบ หากต้องการแสดงภาพสแปนที่เครื่องมือวัดรวบรวมทั้งหมด สิ่งที่คุณต้องทำคือแทนที่ตัวส่งออก 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
ตอนนี้คุณจึงไม่เห็นข้อมูลช่วงมากนักในรูปแบบบันทึกที่มีโครงสร้างใน 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 แล้วไปที่ "รายการการติดตาม" เข้าถึงได้ง่ายจากช่องค้นหา หรือคลิกเมนูในแผงด้านซ้ายก็ได้
จากนั้นคุณจะเห็นจุดสีน้ำเงินจำนวนมากกระจายอยู่ในกราฟเวลาในการตอบสนอง โดยแต่ละจุดแสดงการติดตาม 1 รายการ
คลิกรายการใดรายการหนึ่งแล้วคุณจะเห็นรายละเอียดในการติดตาม
คุณจะเห็นข้อมูลเชิงลึกมากมายได้จากการดูข้อมูลคร่าวๆ นี้ ตัวอย่างเช่น จากกราฟ Waterfall คุณจะเห็นสาเหตุของเวลาในการตอบสนองส่วนใหญ่มาจากช่วงที่มีชื่อว่า shakesapp.ShakespeareService/GetMatchCount
(ดู 1 ในรูปภาพด้านบน) คุณสามารถยืนยันได้จากตารางสรุป (คอลัมน์ด้านขวาสุดแสดงระยะเวลาของช่วงแต่ละช่วง) นอกจากนี้ การติดตามนี้ยังใช้กับการค้นหา "เพื่อน" ด้วย (ดู 2 ในรูปภาพด้านบน)
จากการวิเคราะห์สั้นๆ เหล่านี้ คุณอาจพบว่าคุณต้องทราบช่วงเวลาที่ละเอียดยิ่งขึ้นภายในเมธอด GetMatchCount
การแสดงภาพมีประสิทธิภาพมากกว่าข้อมูล stdout ดูข้อมูลเพิ่มเติมเกี่ยวกับรายละเอียดการติดตามในระบบคลาวด์ได้ที่เอกสารประกอบอย่างเป็นทางการ
สรุป
ในขั้นตอนนี้ คุณได้แทนที่เครื่องมือส่งออก stdout ด้วยเครื่องมือส่งออก Cloud Trace และแสดงภาพร่องรอยใน Cloud Trace นอกจากนี้ คุณยังได้เรียนรู้วิธีเริ่มวิเคราะห์ร่องรอย
วิดีโอถัดไป
ในขั้นตอนถัดไป คุณจะแก้ไขซอร์สโค้ดของบริการเซิร์ฟเวอร์เพื่อเพิ่มช่วงย่อยใน GetMatchCount
7. เพิ่มช่วงย่อยเพื่อให้การวิเคราะห์ดีขึ้น
ในขั้นตอนก่อนหน้า คุณได้พบว่าสาเหตุของเวลาในการไปกลับที่สังเกตได้จาก loadgen ส่วนใหญ่เป็นกระบวนการภายในเมธอด GetMatchCount ซึ่งเป็นตัวแฮนเดิล gRPC ในบริการเซิร์ฟเวอร์ อย่างไรก็ตาม เนื่องจากเราไม่ได้ติดตั้งเครื่องมือวัดผลอื่นๆ นอกเหนือจากตัวแฮนเดิล เราจึงไม่สามารถค้นหาข้อมูลเชิงลึกเพิ่มเติมจากกราฟ Waterfall กรณีนี้เกิดขึ้นได้บ่อยเมื่อเราเริ่มเครื่องมือวัดประสิทธิภาพไมโครเซอร์วิส
ในส่วนนี้ เราจะติดตั้งเครื่องมือวัดค่าสแปนย่อยเมื่อเซิร์ฟเวอร์เรียกใช้ Google Cloud Storage เนื่องจากเป็นเรื่องปกติที่ I/O เครือข่ายภายนอกบางรายการจะใช้เวลานานในกระบวนการ และเราต้องระบุว่าการเรียกใช้คือสาเหตุหรือไม่
ติดตั้งเครื่องมือวัดใน Span ย่อยในเซิร์ฟเวอร์
เปิด main.go
ในเซิร์ฟเวอร์ แล้วค้นหาฟังก์ชัน readFiles
ฟังก์ชันนี้จะเรียกคําขอไปยัง Google Cloud Storage เพื่อดึงข้อมูลไฟล์ข้อความทั้งหมดของผลงานของ Shakespeare ในฟังก์ชันนี้ คุณสามารถสร้างช่วงย่อยได้ เช่นเดียวกับที่ทำในเครื่องมือวัดเซิร์ฟเวอร์ 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
แล้วเลือกการติดตามชื่อ query.request
รายการใดรายการหนึ่งจากรายการการติดตาม คุณจะเห็นกราฟ Waterfall ของการติดตามที่คล้ายกัน ยกเว้นช่วงใหม่ในส่วน shakesapp.ShakespeareService/GetMatchCount
(ช่วงที่ถูกล้อมรอบด้วยสี่เหลี่ยมผืนผ้าสีแดงด้านล่าง)
สิ่งที่คุณบอกได้จากกราฟนี้คือการเรียกใช้ภายนอกไปยัง Google Cloud Storage ใช้เวลาในการตอบสนองนานมาก แต่ยังมีสิ่งอื่นๆ ที่ทำให้เกิดความล่าช้าส่วนใหญ่
คุณได้รับข้อมูลเชิงลึกมากมายแล้วจากการดูกราฟ Waterfall ของการติดตามเพียง 2-3 ครั้ง คุณดูรายละเอียดประสิทธิภาพเพิ่มเติมในแอปพลิเคชันได้อย่างไร เครื่องมือวิเคราะห์จะเข้ามามีบทบาทในขั้นตอนนี้ แต่ตอนนี้เราขอจบ Codelab นี้และส่งต่อบทแนะนำเครื่องมือวิเคราะห์ทั้งหมดไปยังส่วนที่ 2
สรุป
ในขั้นตอนนี้ คุณได้ติดตั้งใช้งานช่วงในบริการเซิร์ฟเวอร์อีกช่วงหนึ่งและรับข้อมูลเชิงลึกเพิ่มเติมเกี่ยวกับเวลาในการตอบสนองของระบบ
8. ขอแสดงความยินดี
คุณสร้างการติดตามแบบกระจายด้วย OpenTelemery และยืนยันเวลาในการตอบสนองของคําขอในไมโครเซอร์วิสใน 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 และผู้ใช้ที่ดูแลระบบ" > "การตั้งค่า" จากแผงเมนู แล้วคลิกปุ่ม "ปิดระบบ"
จากนั้นป้อนรหัสโปรเจ็กต์ (ไม่ใช่ชื่อโปรเจ็กต์) ในแบบฟอร์มในกล่องโต้ตอบและยืนยันการปิด