1. บทนำ

อัปเดตล่าสุด: 14-07-2022
การสังเกตการณ์แอปพลิเคชัน
การสังเกตการณ์และโปรไฟล์เลอร์แบบต่อเนื่อง
การสังเกตการณ์เป็นคำที่ใช้อธิบายแอตทริบิวต์ของระบบ ระบบที่มีความสามารถในการสังเกตได้ช่วยให้ทีมแก้ไขข้อบกพร่องของระบบได้อย่างมีประสิทธิภาพ ในบริบทดังกล่าว เสาหลัก 3 ประการของความสามารถในการสังเกตการณ์ ได้แก่ บันทึก เมตริก และการติดตาม เป็นเครื่องมือพื้นฐานสำหรับระบบในการรับความสามารถในการสังเกตการณ์
นอกจากเสาหลัก 3 ประการของความสามารถในการสังเกตการณ์แล้ว การสร้างโปรไฟล์อย่างต่อเนื่องยังเป็นอีกองค์ประกอบสำคัญสำหรับความสามารถในการสังเกตการณ์ และขยายฐานผู้ใช้ในอุตสาหกรรม Cloud Profiler เป็นหนึ่งในผู้ริเริ่มและมีอินเทอร์เฟซที่ใช้งานง่ายเพื่อเจาะลึกเมตริกประสิทธิภาพในสแต็กการเรียกแอปพลิเคชัน
Codelab นี้เป็นส่วนที่ 2 ของซีรีส์และครอบคลุมการติดตั้งเครื่องมือในเอเจนต์โปรไฟล์อย่างต่อเนื่อง ส่วนที่ 1 ครอบคลุมการติดตามแบบกระจายด้วย OpenTelemetry และ Cloud Trace และคุณจะได้เรียนรู้เพิ่มเติมเกี่ยวกับการระบุคอขวดของไมโครเซอร์วิสได้ดียิ่งขึ้นด้วยส่วนที่ 1
สิ่งที่คุณจะสร้าง
ในโค้ดแล็บนี้ คุณจะติดตั้งเครื่องมือตัวแทน Continuous Profiler ในบริการเซิร์ฟเวอร์ของ "แอปพลิเคชันเชกสเปียร์" (หรือที่เรียกว่า Shakesapp) ซึ่งทำงานในคลัสเตอร์ Google Kubernetes Engine สถาปัตยกรรมของ Shakesapp เป็นไปตามที่อธิบายไว้ด้านล่าง

- Loadgen ส่งสตริงการค้นหาไปยังไคลเอ็นต์ใน HTTP
- ไคลเอ็นต์ส่งคำค้นหาจาก Loadgen ไปยังเซิร์ฟเวอร์ใน gRPC
- เซิร์ฟเวอร์ยอมรับคำค้นหาจากไคลเอ็นต์ ดึงข้อมูลผลงานทั้งหมดของเชกสเปียร์ในรูปแบบข้อความจาก Google Cloud Storage ค้นหาบรรทัดที่มีคำค้นหา และแสดงผลหมายเลขบรรทัดที่ตรงกันให้ไคลเอ็นต์
ในส่วนที่ 1 คุณพบว่าคอขวดอยู่ที่ใดที่หนึ่งในบริการเซิร์ฟเวอร์ แต่ไม่สามารถระบุสาเหตุที่แน่ชัดได้
สิ่งที่คุณจะได้เรียนรู้
- วิธีฝังเอเจนต์โปรไฟล์
- วิธีตรวจสอบคอขวดใน Cloud Profiler
Codelab นี้อธิบายวิธีติดตั้งเครื่องมือตัวแทนโปรไฟล์ต่อเนื่องในแอปพลิเคชัน
สิ่งที่คุณต้องมี
- มีความรู้พื้นฐานเกี่ยวกับ Go
- มีความรู้พื้นฐานเกี่ยวกับ Kubernetes
2. การตั้งค่าและข้อกำหนด
การตั้งค่าสภาพแวดล้อมแบบเรียนรู้ด้วยตนเอง
หากยังไม่มีบัญชี Google (Gmail หรือ Google Apps) คุณต้องสร้างบัญชี ลงชื่อเข้าใช้คอนโซล Google Cloud Platform ( console.cloud.google.com) แล้วสร้างโปรเจ็กต์ใหม่
หากมีโปรเจ็กต์อยู่แล้ว ให้คลิกเมนูแบบเลื่อนลงเพื่อเลือกโปรเจ็กต์ที่ด้านซ้ายบนของคอนโซล

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

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

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

โปรดจดจำรหัสโปรเจ็กต์ ซึ่งเป็นชื่อที่ไม่ซ้ำกันในโปรเจ็กต์ Google Cloud ทั้งหมด (ชื่อด้านบนมีผู้ใช้แล้วและจะใช้ไม่ได้ ขออภัย) ซึ่งจะเรียกว่า PROJECT_ID ในภายหลังใน Codelab นี้
จากนั้นหากยังไม่ได้ดำเนินการ คุณจะต้องเปิดใช้การเรียกเก็บเงินใน Developers Console เพื่อใช้ทรัพยากร Google Cloud และเปิดใช้ Cloud Trace API

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


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

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

เราจะกลับมาที่นี่ในภายหลังเพื่อตรวจสอบเส้นทางรีจิสทรี
การตั้งค่า 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 แล้วคลิกชื่อที่เก็บที่คุณเพิ่งตั้งค่าในขั้นตอนก่อนหน้า

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

เมื่อคลิกปุ่มคัดลอก คุณจะเห็นกล่องโต้ตอบที่ด้านล่างของเบราว์เซอร์พร้อมข้อความ เช่น
คัดลอก "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 ทำงาน
ถัดไป
ในขั้นตอนถัดไป คุณจะติดตั้งเครื่องมือตัวแทน Continuous Profiler ในบริการเซิร์ฟเวอร์
3. สร้าง พุช และติดตั้งใช้งานไมโครเซอร์วิส
ดาวน์โหลดเนื้อหา Codelab
ในขั้นตอนก่อนหน้า เราได้ตั้งค่าข้อกำหนดเบื้องต้นทั้งหมดสำหรับ Codelab นี้แล้ว ตอนนี้คุณก็พร้อมที่จะเรียกใช้ไมโครเซอร์วิสทั้งหมดบนแพลตฟอร์มดังกล่าวแล้ว เนื้อหา 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 นี้ คุณจะอัปเดตซอร์สโค้ดที่อยู่ในโฟลเดอร์ step4 นอกจากนี้ คุณยังดูซอร์สโค้ดในโฟลเดอร์ step[1-6] เพื่อดูการเปลี่ยนแปลงตั้งแต่ต้นได้ด้วย (ส่วนที่ 1 ครอบคลุมขั้นตอนที่ 0 ถึง 4 และส่วนที่ 2 ครอบคลุมขั้นตอนที่ 5 และ 6)
เรียกใช้คำสั่ง skaffold
สุดท้ายนี้ คุณก็พร้อมที่จะสร้าง พุช และติดตั้งใช้งานเนื้อหาทั้งหมดในคลัสเตอร์ Kubernetes ที่เพิ่งสร้าง ฟังดูเหมือนจะมีหลายขั้นตอน แต่จริงๆ แล้ว Skaffold จะจัดการทุกอย่างให้คุณ ลองใช้คำสั่งต่อไปนี้
cd step4 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. การตรวจสอบ Agent ของ Cloud Profiler
แนวคิดของการจัดทำโปรไฟล์อย่างต่อเนื่อง
ก่อนที่จะอธิบายแนวคิดของการสร้างโปรไฟล์อย่างต่อเนื่อง เราต้องทำความเข้าใจแนวคิดของการสร้างโปรไฟล์ก่อน การสร้างโปรไฟล์เป็นวิธีหนึ่งในการวิเคราะห์แอปพลิเคชันแบบไดนามิก (การวิเคราะห์โปรแกรมแบบไดนามิก) และมักจะดำเนินการในระหว่างการพัฒนาแอปพลิเคชันในกระบวนการทดสอบโหลด เป็นต้น ซึ่งเป็นกิจกรรมแบบครั้งเดียวเพื่อวัดเมตริกระบบ เช่น การใช้งาน CPU และหน่วยความจำ ในช่วงระยะเวลาที่เฉพาะเจาะจง หลังจากรวบรวมข้อมูลโปรไฟล์แล้ว นักพัฒนาแอปจะวิเคราะห์ข้อมูลดังกล่าวนอกโค้ด
การทำโปรไฟล์อย่างต่อเนื่องเป็นแนวทางที่ขยายจากการทำโปรไฟล์ปกติ โดยจะเรียกใช้โปรไฟล์หน้าต่างสั้นๆ กับแอปพลิเคชันที่ทำงานเป็นเวลานานเป็นระยะๆ และรวบรวมข้อมูลโปรไฟล์จำนวนมาก จากนั้นระบบจะสร้างการวิเคราะห์ทางสถิติโดยอัตโนมัติตามแอตทริบิวต์บางอย่างของแอปพลิเคชัน เช่น หมายเลขเวอร์ชัน โซนการติดตั้งใช้งาน เวลาในการวัด และอื่นๆ ดูรายละเอียดเพิ่มเติมเกี่ยวกับแนวคิดนี้ได้ในเอกสารประกอบของเรา
เนื่องจากเป้าหมายคือแอปพลิเคชันที่ทำงานอยู่ จึงมีวิธีรวบรวมข้อมูลโปรไฟล์เป็นระยะๆ และส่งไปยังแบ็กเอนด์บางส่วนที่ประมวลผลข้อมูลทางสถิติภายหลัง ซึ่งก็คือเอเจนต์ Cloud Profiler และคุณจะฝังเอเจนต์นี้ลงในบริการเซิร์ฟเวอร์ในเร็วๆ นี้
ฝังเอเจนต์ Cloud Profiler
เปิด Cloud Shell Editor โดยกดปุ่ม
ที่ด้านขวาบนของ Cloud Shell เปิด step4/src/server/main.go จาก Explorer ในแผงด้านซ้าย แล้วค้นหาฟังก์ชันหลัก
step4/src/server/main.go
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
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)
healthpb.RegisterHealthServer(srv, svc)
if err := srv.Serve(lis); err != nil {
log.Fatalf("error serving server: %v", err)
}
}
ในmainฟังก์ชัน คุณจะเห็นโค้ดการตั้งค่าบางอย่างสำหรับ OpenTelemetry และ gRPC ซึ่งได้ดำเนินการใน Codelab ส่วนที่ 1 แล้ว ตอนนี้คุณจะเพิ่มการตรวจสอบสำหรับตัวแทน Cloud Profiler ที่นี่ เช่นเดียวกับที่เราทำกับ initTracer() คุณสามารถเขียนฟังก์ชันที่ชื่อ initProfiler() เพื่อให้อ่านง่ายได้
step4/src/server/main.go
import (
...
"cloud.google.com/go/profiler" // step5. add profiler package
"cloud.google.com/go/storage"
...
)
// step5: add Profiler initializer
func initProfiler() {
cfg := profiler.Config{
Service: "server",
ServiceVersion: "1.0.0",
NoHeapProfiling: true,
NoAllocProfiling: true,
NoGoroutineProfiling: true,
NoCPUProfiling: false,
}
if err := profiler.Start(cfg); err != nil {
log.Fatalf("failed to launch profiler agent: %v", err)
}
}
มาดูตัวเลือกที่ระบุในออบเจ็กต์ profiler.Config{} กัน
- บริการ: ชื่อบริการที่คุณเลือกและเปิดได้ในแดชบอร์ดโปรไฟล์
- ServiceVersion: ชื่อเวอร์ชันของบริการ คุณสามารถเปรียบเทียบชุดข้อมูลโปรไฟล์ตามค่านี้ได้
- NoHeapProfiling: ปิดใช้การสร้างโปรไฟล์การใช้หน่วยความจำ
- NoAllocProfiling: ปิดใช้การสร้างโปรไฟล์การจัดสรรหน่วยความจำ
- NoGoroutineProfiling: ปิดใช้การทำโปรไฟล์ Goroutine
- NoCPUProfiling: ปิดใช้การสร้างโปรไฟล์ CPU
ใน Codelab นี้ เราจะเปิดใช้การสร้างโปรไฟล์ CPU เท่านั้น
ตอนนี้สิ่งที่คุณต้องทำคือเรียกใช้ฟังก์ชันนี้ในฟังก์ชัน main อย่าลืมนำเข้าแพ็กเกจ Cloud Profiler ในบล็อกการนำเข้า
step4/src/server/main.go
func main() {
...
defer func() {
if err := tp.Shutdown(context.Background()); err != nil {
log.Fatalf("error shutting down TracerProvider: %v", err)
}
}()
// step2. end setup
// step5. start profiler
go initProfiler()
// step5. end
svc := NewServerService()
// step2: add interceptor
...
}
โปรดทราบว่าคุณกำลังเรียกใช้ฟังก์ชัน initProfiler() ด้วยคีย์เวิร์ด go เนื่องจาก profiler.Start() บล็อก คุณจึงต้องเรียกใช้ใน Goroutine อื่น ตอนนี้ก็พร้อมสร้างแล้ว โปรดเรียกใช้ go mod tidy ก่อนการติดตั้งใช้งาน
go mod tidy
ตอนนี้ให้ติดตั้งใช้งานคลัสเตอร์ด้วยบริการเซิร์ฟเวอร์ใหม่
skaffold dev
โดยปกติแล้วจะใช้เวลา 2-3 นาทีจึงจะเห็นกราฟเปลวไฟใน Cloud Profiler พิมพ์ "Profiler" ในช่องค้นหาที่ด้านบน แล้วคลิกไอคอนของ Profiler

จากนั้นคุณจะเห็นกราฟเปลวไฟต่อไปนี้

สรุป
ในขั้นตอนนี้ คุณได้ฝังเอเจนต์ Cloud Profiler ลงในบริการเซิร์ฟเวอร์และยืนยันว่าเอเจนต์สร้างกราฟเปลวไฟ
ถัดไป
ในขั้นตอนถัดไป คุณจะตรวจสอบสาเหตุของคอขวดในแอปพลิเคชันด้วย Flame Graph
5. วิเคราะห์กราฟเปลวไฟของ Cloud Profiler
กราฟ Flame คืออะไร
กราฟเปลวไฟเป็นวิธีหนึ่งในการแสดงข้อมูลโปรไฟล์ ดูคำอธิบายโดยละเอียดได้ในเอกสารของเรา แต่สรุปสั้นๆ มีดังนี้
- แต่ละแท่งแสดงการเรียกเมธอด/ฟังก์ชันในแอปพลิเคชัน
- ทิศทางแนวตั้งคือสแต็กการเรียกใช้ ซึ่งจะขยายจากบนลงล่าง
- ทิศทางแนวนอนคือการใช้ทรัพยากร ยิ่งนานยิ่งแย่
มาดูกราฟเปลวไฟที่ได้กัน

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

ในกรณีของเรา เห็นได้ชัดว่า grpc.(*Server).serveStreams.func1.2 ใช้เวลา CPU มากที่สุด และเมื่อดูที่สแต็กการเรียกจากบนลงล่าง จะเห็นว่าใช้เวลาส่วนใหญ่ใน main.(*serverService).GetMatchCount ซึ่งเป็นตัวแฮนเดิลเซิร์ฟเวอร์ gRPC ในบริการเซิร์ฟเวอร์
ในส่วน GetMatchCount คุณจะเห็นชุดฟังก์ชัน regexp ได้แก่ regexp.MatchString และ regexp.Compile ซึ่งมาจากแพ็กเกจมาตรฐาน นั่นคือควรได้รับการทดสอบอย่างดีจากหลายมุมมอง รวมถึงประสิทธิภาพ แต่ผลลัพธ์ที่นี่แสดงให้เห็นว่าการใช้งานทรัพยากรเวลา CPU สูงใน regexp.MatchString และ regexp.Compile จากข้อเท็จจริงดังกล่าว สมมติฐานในที่นี้คือการใช้ regexp.MatchString มีส่วนเกี่ยวข้องกับปัญหาด้านประสิทธิภาพ ดังนั้นมาอ่านซอร์สโค้ดที่ใช้ฟังก์ชันนี้กัน
step4/src/server/main.go
func (s *serverService) GetMatchCount(ctx context.Context, req *shakesapp.ShakespeareRequest) (*shakesapp.ShakespeareResponse, error) {
resp := &shakesapp.ShakespeareResponse{}
texts, err := readFiles(ctx, bucketName, bucketPrefix)
if err != nil {
return resp, fmt.Errorf("fails to read files: %s", err)
}
for _, text := range texts {
for _, line := range strings.Split(text, "\n") {
line, query := strings.ToLower(line), strings.ToLower(req.Query)
isMatch, err := regexp.MatchString(query, line)
if err != nil {
return resp, err
}
if isMatch {
resp.MatchCount++
}
}
}
return resp, nil
}
นี่คือที่ที่เรียกใช้ regexp.MatchString เมื่ออ่านซอร์สโค้ด คุณอาจสังเกตเห็นว่าฟังก์ชันนี้ถูกเรียกใช้ภายในลูป for ที่ซ้อนกัน ดังนั้นการใช้ฟังก์ชันนี้อาจไม่ถูกต้อง มาดู GoDoc ของ regexp กัน

ตามเอกสาร regexp.MatchString จะคอมไพล์รูปแบบนิพจน์ทั่วไปในการเรียกใช้ทุกครั้ง ดังนั้นสาเหตุของการใช้ทรัพยากรจำนวนมากจึงเป็นดังนี้
สรุป
ในขั้นตอนนี้ คุณได้ตั้งสมมติฐานเกี่ยวกับสาเหตุของการใช้ทรัพยากรโดยการวิเคราะห์กราฟเปลวไฟ
ถัดไป
ในขั้นตอนถัดไป คุณจะอัปเดตซอร์สโค้ดของบริการเซิร์ฟเวอร์และยืนยันการเปลี่ยนแปลงจากเวอร์ชัน 1.0.0
6. อัปเดตซอร์สโค้ดและเปรียบเทียบกราฟเปลวไฟ
อัปเดตซอร์สโค้ด
ในขั้นตอนก่อนหน้า คุณได้ตั้งสมมติฐานว่าการใช้งาน regexp.MatchString มีความเกี่ยวข้องกับการใช้ทรัพยากรจำนวนมาก มาแก้ปัญหานี้กัน เปิดโค้ดและเปลี่ยนส่วนนั้นเล็กน้อย
step4/src/server/main.go
func (s *serverService) GetMatchCount(ctx context.Context, req *shakesapp.ShakespeareRequest) (*shakesapp.ShakespeareResponse, error) {
resp := &shakesapp.ShakespeareResponse{}
texts, err := readFiles(ctx, bucketName, bucketPrefix)
if err != nil {
return resp, fmt.Errorf("fails to read files: %s", err)
}
// step6. considered the process carefully and naively tuned up by extracting
// regexp pattern compile process out of for loop.
query := strings.ToLower(req.Query)
re := regexp.MustCompile(query)
for _, text := range texts {
for _, line := range strings.Split(text, "\n") {
line = strings.ToLower(line)
isMatch := re.MatchString(line)
// step6. done replacing regexp with strings
if isMatch {
resp.MatchCount++
}
}
}
return resp, nil
}
ดังที่คุณเห็น ตอนนี้กระบวนการคอมไพล์รูปแบบนิพจน์ทั่วไปได้แยกออกจาก regexp.MatchString และย้ายออกจากลูป for ที่ซ้อนกันแล้ว
ก่อนที่จะนำโค้ดนี้ไปใช้ โปรดอัปเดตสตริงเวอร์ชันในฟังก์ชัน initProfiler()
step4/src/server/main.go
func initProfiler() {
cfg := profiler.Config{
Service: "server",
ServiceVersion: "1.1.0", // step6. update version
NoHeapProfiling: true,
NoAllocProfiling: true,
NoGoroutineProfiling: true,
NoCPUProfiling: false,
}
if err := profiler.Start(cfg); err != nil {
log.Fatalf("failed to launch profiler agent: %v", err)
}
}
มาดูวิธีการทำงานกัน ทําให้คลัสเตอร์ใช้งานได้ด้วยคําสั่ง skaffold
skaffold dev
หลังจากนั้นสักพัก ให้โหลดแดชบอร์ด Cloud Profiler ซ้ำแล้วดูว่าแดชบอร์ดเป็นอย่างไร

อย่าลืมเปลี่ยนเวอร์ชันเป็น "1.1.0" เพื่อให้คุณเห็นเฉพาะโปรไฟล์จากเวอร์ชัน 1.1.0 ดังที่เห็นได้ว่าความยาวของแถบ GetMatchCount ลดลง และอัตราส่วนการใช้งานเวลา CPU (กล่าวคือ แถบสั้นลง)

คุณไม่เพียงดูที่กราฟเปลวไฟของเวอร์ชันเดียวเท่านั้น แต่ยังเปรียบเทียบความแตกต่างระหว่าง 2 เวอร์ชันได้ด้วย

เปลี่ยนค่าของเมนูแบบเลื่อนลง "เปรียบเทียบกับ" เป็น "เวอร์ชัน" และเปลี่ยนค่าของ "เวอร์ชันที่เปรียบเทียบ" เป็น "1.0.0" ซึ่งเป็นเวอร์ชันเดิม

คุณจะเห็นกราฟเปลวไฟแบบนี้ รูปร่างของกราฟจะเหมือนกับ 1.1.0 แต่การระบายสีจะแตกต่างกัน ในโหมดเปรียบเทียบ ความหมายของสีมีดังนี้
- สีน้ำเงิน: ค่า (การใช้ทรัพยากร) ที่ลดลง
- สีส้ม: มูลค่า (การใช้ทรัพยากร) ที่ได้รับ
- สีเทา: เป็นกลาง
มาดูรายละเอียดฟังก์ชันโดยใช้คำอธิบายกัน การคลิกที่แถบที่ต้องการซูมเข้าจะช่วยให้คุณเห็นรายละเอียดเพิ่มเติมภายในสแต็ก โปรดคลิกแถบ main.(*serverService).GetMatchCount นอกจากนี้ เมื่อวางเมาส์เหนือแถบ คุณจะเห็นรายละเอียดของการเปรียบเทียบ

โดยระบุว่าเวลา CPU ทั้งหมดลดลงจาก 5.26 วินาทีเป็น 2.88 วินาที (รวมเป็น 10 วินาที = หน้าต่างการสุ่มตัวอย่าง) นี่เป็นการปรับปรุงครั้งใหญ่
ตอนนี้คุณสามารถปรับปรุงประสิทธิภาพแอปพลิเคชันจากการวิเคราะห์ข้อมูลโปรไฟล์ได้แล้ว
สรุป
ในขั้นตอนนี้ คุณได้ทำการแก้ไขในบริการเซิร์ฟเวอร์และยืนยันการปรับปรุงในโหมดการเปรียบเทียบของ Cloud Profiler
ถัดไป
ในขั้นตอนถัดไป คุณจะอัปเดตซอร์สโค้ดของบริการเซิร์ฟเวอร์และยืนยันการเปลี่ยนแปลงจากเวอร์ชัน 1.0.0
7. ขั้นตอนเพิ่มเติม: ยืนยันการปรับปรุงใน Waterfall ของการติดตาม
ความแตกต่างระหว่างการติดตามแบบกระจายและการทำโปรไฟล์อย่างต่อเนื่อง
ในส่วนที่ 1 ของโค้ดแล็บ คุณได้ยืนยันว่าสามารถระบุบริการที่เป็นคอขวดในไมโครเซอร์วิสสำหรับเส้นทางการส่งคำขอ และไม่สามารถระบุสาเหตุที่แน่นอนของคอขวดในบริการที่เฉพาะเจาะจง ใน Codelab ส่วนที่ 2 นี้ คุณได้เรียนรู้ว่าการทำโปรไฟล์อย่างต่อเนื่องช่วยให้คุณระบุคอขวดภายในบริการเดียวจากสแต็กการเรียกได้
ในขั้นตอนนี้ เราจะมาดูกราฟน้ำตกจาก Distributed Trace (Cloud Trace) และดูความแตกต่างจากการทำโปรไฟล์อย่างต่อเนื่อง
กราฟน้ำตกนี้เป็นหนึ่งในร่องรอยที่มีคำค้นหา "love" โดยใช้เวลารวมประมาณ 6.7 วินาที (6700 มิลลิวินาที)

และนี่คือหลังจากปรับปรุงสำหรับคำค้นหาเดียวกัน ดังที่คุณทราบ ตอนนี้เวลาในการตอบสนองทั้งหมดคือ 1.5 วินาที (1,500 มิลลิวินาที) ซึ่งเป็นการปรับปรุงครั้งใหญ่จากการใช้งานก่อนหน้านี้

ประเด็นสำคัญที่นี่คือในแผนภูมิ Waterfall ของการติดตามแบบกระจาย ข้อมูลสแต็กการเรียกใช้จะใช้ไม่ได้เว้นแต่คุณจะใช้เครื่องมือกับช่วงทุกที่ นอกจากนี้ Distributed Tracing ยังมุ่งเน้นที่เวลาในการตอบสนองในบริการต่างๆ ในขณะที่การทำโปรไฟล์อย่างต่อเนื่องจะมุ่งเน้นที่ทรัพยากรคอมพิวเตอร์ (CPU, หน่วยความจำ, เธรดของระบบปฏิบัติการ) ของบริการเดียว
ในอีกด้านหนึ่ง การติดตามแบบกระจายคือฐานเหตุการณ์ ส่วนโปรไฟล์ต่อเนื่องคือสถิติ การติดตามแต่ละรายการมีกราฟเวลาในการตอบสนองที่แตกต่างกัน และคุณต้องใช้รูปแบบอื่น เช่น การกระจาย เพื่อดูแนวโน้มการเปลี่ยนแปลงของเวลาในการตอบสนอง
สรุป
ในขั้นตอนนี้ คุณได้ตรวจสอบความแตกต่างระหว่างการติดตามแบบกระจายและการทำโปรไฟล์อย่างต่อเนื่อง
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 และผู้ดูแลระบบ" > "การตั้งค่า" จากแผงเมนู แล้วคลิกปุ่ม "ปิด"

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