1. บทนำ
อัปเดตล่าสุด 14-07-2022
ความสามารถในการสังเกตของแอปพลิเคชัน
ความสามารถในการสังเกตและเครื่องมือสร้างโปรไฟล์อย่างต่อเนื่อง
การสังเกตเป็นคำที่ใช้เพื่ออธิบายแอตทริบิวต์ของระบบ ระบบที่มีการสังเกตการณ์ช่วยให้ทีมแก้ไขข้อบกพร่องของระบบได้อย่างต่อเนื่อง ในบริบทดังกล่าว เสาหลัก 3 ประการของความสามารถในการสังเกต บันทึก เมตริก และการติดตามเป็นเครื่องมือพื้นฐานสำหรับระบบเพื่อให้ได้ความสามารถในการสังเกต
นอกจากนี้ นอกเหนือจากเสาหลัก 3 ประการของความสามารถในการสังเกตการณ์แล้ว การสร้างโปรไฟล์อย่างต่อเนื่องยังเป็นองค์ประกอบหลักอีกอย่างหนึ่งของความสามารถในการสังเกตการณ์ และขยายฐานผู้ใช้ในอุตสาหกรรมด้วย Cloud Profiler คือหนึ่งในผู้ริเริ่มและให้อินเทอร์เฟซง่ายๆ ในการเจาะลึกเมตริกประสิทธิภาพในสแต็กการเรียกใช้แอปพลิเคชัน
Codelab นี้เป็นส่วนที่ 2 ของซีรีส์ และครอบคลุมการใช้เครื่องมือ Agent เครื่องมือสร้างโปรไฟล์แบบต่อเนื่อง ส่วนที่ 1 จะกล่าวถึงการติดตามแบบกระจายด้วย OpenTelemetry และ Cloud Trace และคุณจะได้เรียนรู้เพิ่มเติมเกี่ยวกับการระบุจุดคอขวดของไมโครเซอร์วิสได้ดียิ่งขึ้นด้วยส่วนที่ 1
สิ่งที่คุณจะสร้าง
ใน Codelab นี้ คุณจะใช้ Agent ตัวสร้างโปรไฟล์แบบต่อเนื่องในบริการเซิร์ฟเวอร์ของ "แอปพลิเคชัน Shakespeare" (หรือที่รู้จักในชื่อ Shakesapp) ที่เรียกใช้บนคลัสเตอร์ Google Kubernetes Engine สถาปัตยกรรมของ Shakesapp อธิบายไว้ด้านล่าง
- Loadgen ส่งสตริงการค้นหาไปยังไคลเอ็นต์ใน HTTP
- ไคลเอ็นต์ส่งผ่านการค้นหาจากตัวจัดสรรภาระงานไปยังเซิร์ฟเวอร์ใน gRPC
- เซิร์ฟเวอร์ยอมรับคำค้นหาจากไคลเอ็นต์ ดึงข้อมูลงานของ Shakespare ทั้งหมดในรูปแบบข้อความจาก Google Cloud Storage, ค้นหาบรรทัดที่มีคำค้นหา และแสดงผลจำนวนบรรทัดที่ตรงกับไคลเอ็นต์
ในส่วนที่ 1 คุณได้พบว่าปัญหาคอขวดเกิดขึ้นที่ใดที่หนึ่งในบริการเซิร์ฟเวอร์ แต่ไม่สามารถระบุสาเหตุที่แน่ชัดได้
สิ่งที่คุณจะได้เรียนรู้
- วิธีฝัง Agent เครื่องมือสร้างโปรไฟล์
- วิธีตรวจสอบจุดคอขวดบน Cloud Profiler
Codelab นี้อธิบายวิธีใช้งาน Agent เครื่องมือสร้างโปรไฟล์แบบต่อเนื่องในแอปพลิเคชันของคุณ
สิ่งที่ต้องมี
- ความรู้พื้นฐานเกี่ยวกับ Go
- ความรู้พื้นฐานเกี่ยวกับ Kubernetes
2. การตั้งค่าและข้อกำหนด
การตั้งค่าสภาพแวดล้อมตามเวลาที่สะดวก
หากยังไม่มีบัญชี Google (Gmail หรือ Google Apps) คุณต้องสร้างบัญชีก่อน ลงชื่อเข้าใช้คอนโซล Google Cloud Platform (console.cloud.google.com) และสร้างโปรเจ็กต์ใหม่
หากคุณมีโปรเจ็กต์อยู่แล้ว ให้คลิกเมนูแบบเลื่อนลงสำหรับการเลือกโปรเจ็กต์ที่ด้านซ้ายบนของคอนโซล
แล้วคลิก "โปรเจ็กต์ใหม่" ในกล่องโต้ตอบที่ปรากฏขึ้นเพื่อสร้างโปรเจ็กต์ใหม่ ดังนี้
หากคุณยังไม่มีโปรเจ็กต์ คุณจะเห็นกล่องโต้ตอบลักษณะนี้ให้สร้างโปรเจ็กต์แรก
กล่องโต้ตอบการสร้างโปรเจ็กต์ที่ตามมาจะให้คุณป้อนรายละเอียดของโปรเจ็กต์ใหม่:
โปรดจำรหัสโปรเจ็กต์ ซึ่งเป็นชื่อที่ไม่ซ้ำกันในโปรเจ็กต์ Google Cloud ทั้งหมด (ระบบใช้ชื่อด้านบนนี้ไปแล้ว และจะใช้ไม่ได้ ขออภัย) โดยจะเรียกใน Codelab ว่า 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 ซึ่งจะทำให้ Codelab นี้ไม่มีค่าใช้จ่ายทั้งหมด
การตั้งค่า Google Cloud Shell
แม้ว่า Google Cloud และ Google Cloud Trace จะทำงานจากระยะไกลจากแล็ปท็อปได้ แต่ในโค้ดแล็บนี้เราจะใช้ Google Cloud Shell ซึ่งเป็นสภาพแวดล้อมบรรทัดคำสั่งที่ทำงานในระบบคลาวด์
เครื่องเสมือนแบบ Debian นี้เต็มไปด้วยเครื่องมือการพัฒนาทั้งหมดที่คุณต้องการ โดยมีไดเรกทอรีหลักขนาด 5 GB ที่ทำงานอย่างต่อเนื่องใน Google Cloud ซึ่งจะช่วยเพิ่มประสิทธิภาพของเครือข่ายและการตรวจสอบสิทธิ์ได้อย่างมาก ซึ่งหมายความว่าสิ่งที่คุณต้องมีสำหรับ Codelab นี้คือเบราว์เซอร์ (ใช่แล้ว ทั้งหมดนี้ทำงานได้บน 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) กระบวนการของโค้ดแล็บนี้มีดังนี้
- ดาวน์โหลดโปรเจ็กต์พื้นฐานลงใน 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 คลิก "สร้างที่เก็บ" แล้วป้อนชื่อที่เก็บ
ใน Codelab นี้ ฉันตั้งชื่อที่เก็บใหม่เป็น trace-codelab
รูปแบบของอาร์ติแฟกต์คือ "Docker" และประเภทสถานที่ตั้งคือ "ภูมิภาค" เลือกภูมิภาคที่ใกล้เคียงกับภูมิภาคที่คุณตั้งค่าไว้สำหรับโซนเริ่มต้นของ Google Compute Engine เช่น ตัวอย่างนี้เลือก "us-central1-f" ด้านบน ดังนั้นตรงนี้เราจะเลือก "us-central1 (ไอโอวา)" จากนั้นคลิก "สร้าง"
ตอนนี้คุณจะเห็น "trace-codelab" ในเบราว์เซอร์ที่เก็บ
เราจะกลับมาที่นี่ในภายหลังเพื่อตรวจสอบเส้นทางรีจิสทรี
การตั้งค่า Skaf Fold
Skaf Fold เป็นเครื่องมือที่มีประโยชน์เมื่อคุณสร้าง Microservice ที่ทำงานบน 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 เพื่อใช้ Container Registry
- สร้างคลัสเตอร์ Kubernetes ที่ไมโครเซอร์วิสของ Codelab ทำงานอยู่
ถัดไป
ในขั้นตอนถัดไป คุณจะต้องใช้ Agent เครื่องมือสร้างโปรไฟล์แบบต่อเนื่องในบริการเซิร์ฟเวอร์
3. สร้าง พุช และติดตั้งใช้งาน Microservice
ดาวน์โหลดเนื้อหา 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 ในสภาพแวดล้อมของคุณและยืนยันว่าสเกฟโฟลด์ทำงานได้ตามที่คาดไว้
ถัดไป
ในขั้นตอนถัดไป คุณจะต้องแก้ไขซอร์สโค้ดของบริการ กำลังโหลดข้อมูลเพื่อใช้ข้อมูลการติดตาม
4. การใช้เครื่องมือของ Agent ของ Cloud Profiler
แนวคิดของการสร้างโปรไฟล์อย่างต่อเนื่อง
ก่อนที่จะอธิบายแนวคิดของการสร้างโปรไฟล์อย่างต่อเนื่อง เราต้องทำความเข้าใจเกี่ยวกับการสร้างโปรไฟล์ก่อน การทำโปรไฟล์เป็นวิธีหนึ่งในการวิเคราะห์แอปพลิเคชันแบบไดนามิก (การวิเคราะห์โปรแกรมแบบไดนามิก) และมักจะดำเนินการระหว่างการพัฒนาแอปพลิเคชันในกระบวนการทดสอบการโหลดและอื่นๆ ซึ่งเป็นกิจกรรมแบบครั้งเดียวเพื่อวัดเมตริกของระบบ เช่น การใช้งาน CPU และหน่วยความจำในช่วงระยะเวลาหนึ่งๆ หลังจากรวบรวมข้อมูลโปรไฟล์แล้ว นักพัฒนาแอปจะวิเคราะห์โปรไฟล์นอกโค้ด
การทำโปรไฟล์แบบต่อเนื่องเป็นวิธีการเพิ่มเติมที่ใช้ทำโปรไฟล์ปกติ นั่นคือจะเรียกใช้โปรไฟล์หน้าต่างสั้นๆ ในแอปพลิเคชันที่ใช้เวลานานเป็นระยะๆ และรวบรวมข้อมูลโปรไฟล์จำนวนมาก จากนั้นโมเดลจะสร้างการวิเคราะห์ทางสถิติโดยอัตโนมัติตามแอตทริบิวต์บางอย่างของแอปพลิเคชัน เช่น หมายเลขเวอร์ชัน โซนการทำให้ใช้งานได้ เวลาในการวัด และอื่นๆ ดูรายละเอียดเพิ่มเติมเกี่ยวกับแนวคิดได้ในเอกสารของเรา
เนื่องจากเป้าหมายเป็นแอปพลิเคชันที่ทํางานอยู่ จึงมีวิธีรวบรวมข้อมูลโปรไฟล์เป็นระยะๆ และส่งไปยังแบ็กเอนด์บางรายการที่ประมวลผลข้อมูลสถิติในภายหลัง นี่คือตัวแทน Cloud Profiler และคุณจะฝังลงในบริการเซิร์ฟเวอร์ในเร็วๆ นี้
ฝัง Agent Cloud Profiler
เปิด Cloud Shell Editor โดยกดปุ่มที่ด้านขวาบนของ Cloud Shell เปิด
step4/src/server/main.go
จากเครื่องมือสำรวจในแผงด้านซ้าย และค้นหาฟังก์ชันหลัก
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: ปิดใช้การทำโปรไฟล์โกรูทีน
- 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()
บล็อก คุณจึงต้องเรียกใช้ในโกโรทีนอื่น ตอนนี้คุณก็พร้อมที่จะสร้างแล้ว อย่าลืมเรียกใช้ go mod tidy
ก่อนการทําให้การเผยแพร่
go mod tidy
จากนั้นให้ทำให้คลัสเตอร์ใช้งานได้ด้วยบริการเซิร์ฟเวอร์ใหม่
skaffold dev
โดยปกติแล้วระบบจะใช้เวลา 2-3 นาทีจึงจะแสดงกราฟเปลวไฟใน Cloud Profiler พิมพ์ "profiler" ในช่องค้นหาที่ด้านบน และคลิกไอคอนเครื่องมือสร้างโปรไฟล์
จากนั้นคุณจะเห็นกราฟ Flame ต่อไปนี้
สรุป
ในขั้นตอนนี้ คุณได้ฝัง Agent ของ Cloud Profiler ไว้ในบริการเซิร์ฟเวอร์และยืนยันว่าสามารถสร้างกราฟเปลวไฟได้
ถัดไป
ในขั้นตอนถัดไป คุณจะตรวจสอบสาเหตุของจุดคอขวดในแอปพลิเคชันโดยใช้กราฟเปลวไฟ
5. วิเคราะห์กราฟ Flame ของ Cloud Profiler
กราฟเปลวไฟคืออะไร
กราฟ Flame Graph เป็นวิธีหนึ่งในการแสดงภาพข้อมูลโปรไฟล์ ดูคำอธิบายโดยละเอียดได้ในเอกสารของเรา แต่สรุปสั้นๆ คือ
- แต่ละแถบแสดงการเรียกเมธอด/ฟังก์ชันในแอปพลิเคชัน
- ทิศทางแนวตั้งคือการเรียกใช้สแต็ก สแต็กการเรียกใช้ขยายจากบนลงล่าง
- ทิศทางแนวนอนคือการใช้ทรัพยากร ยิ่งนาน ก็ยิ่งแย่
จากข้อมูลนี้ มาดูกราฟเปลวไฟที่ได้กัน
การวิเคราะห์กราฟเปลวไฟ
ในส่วนก่อนหน้านี้ คุณได้เรียนรู้ว่าแต่ละแถบในกราฟเปลวไฟแสดงการเรียกใช้ฟังก์ชัน/เมธอด และความยาวของแถบหมายถึงการใช้ทรัพยากรในฟังก์ชัน/เมธอด กราฟ 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-loop ที่ซ้อนกัน ดังนั้นการใช้ฟังก์ชันนี้อาจไม่ถูกต้อง มาดู GoDoc ของ regexp กัน
ตามเอกสารที่ระบุไว้ regexp.MatchString
ได้รวบรวมรูปแบบนิพจน์ทั่วไปในการเรียกทั้งหมด ดังนั้น การเกิดการใช้ทรัพยากรจำนวนมากจึงมีลักษณะดังนี้
สรุป
ในขั้นตอนนี้ คุณตั้งสมมติฐานเกี่ยวกับสาเหตุของการใช้ทรัพยากรโดยการวิเคราะห์กราฟ Flame
ถัดไป
ในขั้นตอนถัดไป คุณจะอัปเดตซอร์สโค้ดของบริการเซิร์ฟเวอร์และยืนยันการเปลี่ยนแปลงจากเวอร์ชัน 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 จาก regexp.MatchString
และจะถูกย้ายออกจากการวนซ้ำ for Loop
ก่อนที่จะทำให้โค้ดนี้ใช้งานได้ โปรดอัปเดตสตริงเวอร์ชันในฟังก์ชัน 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 (แถบนั้นสั้นลง)
นอกจากการดูกราฟ Flame ของเวอร์ชันเดียวแล้ว คุณยังเปรียบเทียบความแตกต่างระหว่าง 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 คุณยืนยันว่าสามารถหาบริการจุดคอขวดใน Microservice สำหรับเส้นทางคำขอได้ และคุณจะไม่ทราบสาเหตุที่แท้จริงของจุดคอขวดในบริการนั้นๆ ในโค้ดแล็บส่วนที่ 2 นี้ คุณได้เรียนรู้ว่าการจัดเก็บโปรไฟล์อย่างต่อเนื่องช่วยให้คุณระบุจุดคอขวดภายในบริการเดียวจากกองคิวการเรียกใช้ได้
ในขั้นตอนนี้ เราจะดูกราฟ Waterfall จากการติดตามแบบกระจาย (การติดตามในระบบคลาวด์) และดูความแตกต่างจากการสํารวจอย่างต่อเนื่อง
กราฟ Waterfall นี้คือหนึ่งในการติดตามที่มีคำค้นหา "love" ใช้เวลาประมาณ 6.7 วินาที (6,700 มิลลิวินาที)
และนี่เป็นหลังจากการปรับปรุงสำหรับคำค้นหาเดียวกัน อย่างที่บอกไป ตอนนี้เวลาในการตอบสนองรวมคือ 1.5 วินาที (1,500 มิลลิวินาที) ซึ่งถือว่าดีขึ้นจากการติดตั้งก่อนหน้ามาก
ประเด็นสําคัญคือในแผนภูมิ Waterfall การติดตามแบบกระจาย ข้อมูลสแต็กการเรียกใช้จะใช้งานไม่ได้ เว้นแต่ว่าคุณจะใช้เครื่องมือที่ครอบคลุมทุกที่ นอกจากนี้การติดตามแบบกระจายยังมุ่งเน้นไปที่เวลาในการตอบสนองในบริการต่างๆ ในขณะที่การทำโปรไฟล์อย่างต่อเนื่องจะมุ่งเน้นที่ทรัพยากรคอมพิวเตอร์ (CPU, หน่วยความจำ, เทรดระบบปฏิบัติการ) ของบริการเดียว
ในอีกแง่หนึ่ง การติดตามแบบกระจายคือฐานเหตุการณ์ ส่วนโปรไฟล์แบบต่อเนื่องคือทางสถิติ การติดตามแต่ละรายการจะมีกราฟเวลาในการตอบสนองต่างกัน และคุณต้องใช้รูปแบบที่แตกต่างกัน เช่น การกระจาย เพื่อรับแนวโน้มของการเปลี่ยนแปลงเวลาในการตอบสนอง
สรุป
ในขั้นตอนนี้ คุณได้ตรวจสอบความแตกต่างระหว่างการติดตามแบบกระจายและการสร้างโปรไฟล์อย่างต่อเนื่อง
8. ขอแสดงความยินดี
คุณสร้างการติดตามแบบกระจายด้วย OpenTelemery และยืนยันเวลาในการตอบสนองของคำขอสำหรับ Microservice บน Google Cloud Trace เรียบร้อยแล้ว
สำหรับการออกกำลังกายระยะยาว คุณลองทำตามหัวข้อต่อไปนี้ด้วยตนเองได้
- การนำไปใช้ในปัจจุบันจะส่งช่วงทั้งหมดที่สร้างโดยการตรวจสอบประสิทธิภาพการทำงาน (
grpc.health.v1.Health/Check
) คุณจะกรองระยะเวลาเหล่านั้นออกจาก Cloud Traces อย่างไร ดูคำแนะนำได้ที่นี่ - เชื่อมโยงบันทึกเหตุการณ์กับระยะเวลา แล้วดูว่าบันทึกนั้นทำงานอย่างไรใน Google Cloud Trace และ Google Cloud Logging ดูคำแนะนำได้ที่นี่
- แทนที่บางบริการด้วยบริการที่เป็นภาษาอื่น แล้วลองใช้ OpenTelemetry สำหรับภาษานั้น
นอกจากนี้ ถ้าคุณต้องการเรียนรู้เกี่ยวกับเครื่องมือสร้างโปรไฟล์หลังจากนี้ โปรดไปยังส่วนที่ 2 ในกรณีนี้ คุณสามารถข้ามส่วน "ล้างข้อมูล" ด้านล่างได้
ล้างข้อมูล
หลังจาก Codelab นี้ โปรดหยุดคลัสเตอร์ Kubernetes และตรวจสอบว่าได้ลบโปรเจ็กต์แล้ว เพื่อไม่ให้มีการเรียกเก็บเงินที่ไม่คาดคิดใน Google Kubernetes Engine, Google Cloud Trace, Google Artifact Registry
ก่อนอื่น ให้ลบคลัสเตอร์ หากคุณเรียกใช้คลัสเตอร์ด้วย skaffold dev
คุณเพียงแค่กด Ctrl-C หากคุณกำลังเรียกใช้คลัสเตอร์ด้วย skaffold run
ให้เรียกใช้คำสั่งต่อไปนี้
skaffold delete
เอาต์พุตจากคำสั่ง
Cleaning up... - deployment.apps "clientservice" deleted - service "clientservice" deleted - deployment.apps "loadgen" deleted - deployment.apps "serverservice" deleted - service "serverservice" deleted
หลังจากลบคลัสเตอร์แล้ว ให้เลือก "IAM & จากแผงเมนู ผู้ดูแลระบบ" "การตั้งค่า" แล้วคลิก "ปิด"
จากนั้นป้อนรหัสโปรเจ็กต์ (ไม่ใช่ชื่อโปรเจ็กต์) ในแบบฟอร์มในกล่องโต้ตอบและยืนยันการปิดเครื่อง