1. บทนำ
อัปเดตล่าสุด 14-07-2022
ความสามารถในการสังเกตของแอปพลิเคชัน
ความสามารถในการสังเกตและเครื่องมือสร้างโปรไฟล์อย่างต่อเนื่อง
การสังเกตเป็นคำที่ใช้เพื่ออธิบายแอตทริบิวต์ของระบบ ระบบที่มีความสามารถในการสังเกตช่วยให้ทีมแก้ไขข้อบกพร่องของระบบของตนได้ในเชิงรุก ในบริบทดังกล่าว เสาหลัก 3 ประการของความสามารถในการสังเกต บันทึก เมตริก และการติดตามเป็นเครื่องมือพื้นฐานสำหรับระบบเพื่อให้ได้ความสามารถในการสังเกต
นอกจากเสาหลัก 3 ประการสำหรับความสามารถในการสังเกตแล้ว การทำโปรไฟล์อย่างต่อเนื่องก็เป็นองค์ประกอบหลักอีกอย่างหนึ่งของความสามารถในการสังเกต ทั้งยังเป็นการขยายฐานผู้ใช้ในอุตสาหกรรมอีกด้วย Cloud Profiler คือหนึ่งในผู้ริเริ่มและให้อินเทอร์เฟซง่ายๆ ในการเจาะลึกเมตริกประสิทธิภาพในสแต็กการเรียกใช้แอปพลิเคชัน
Codelab นี้เป็นส่วนที่ 2 ของซีรีส์ และครอบคลุมการใช้เครื่องมือ Agent เครื่องมือสร้างโปรไฟล์แบบต่อเนื่อง ส่วนที่ 1 จะครอบคลุมการติดตามแบบกระจายด้วย OpenTelemetry และ Cloud Trace และคุณจะได้เรียนรู้เพิ่มเติมเกี่ยวกับการระบุจุดคอขวดของ Microservice ให้ดียิ่งขึ้นในตอนที่ 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 ในภายหลัง
ขั้นตอนถัดไป คุณจะต้องเปิดใช้การเรียกเก็บเงินใน Developers Console เพื่อใช้ทรัพยากรของ Google Cloud และเปิดใช้ Cloud Trace API หากยังไม่ได้ดำเนินการ
การใช้งาน Codelab นี้น่าจะมีค่าใช้จ่ายไม่เกิน 2-3 ดอลลาร์ แต่อาจมากกว่านี้หากคุณตัดสินใจใช้ทรัพยากรเพิ่มหรือปล่อยให้ทำงาน (ดูส่วน "ล้างข้อมูล" ในตอนท้ายของเอกสารนี้) ราคาของ 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 ซึ่งเป็นสภาพแวดล้อมของบรรทัดคำสั่งที่ทำงานในระบบคลาวด์ใน Codelab
เครื่องเสมือนแบบ 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
คุณเลือกโซนต่างๆ ได้หลากหลาย ดูข้อมูลเพิ่มเติมได้ที่ภูมิภาคและ โซน
ตั้งค่าภาษา Go
ใน Codelab นี้ เราใช้ Go สำหรับซอร์สโค้ดทั้งหมด เรียกใช้คำสั่งต่อไปนี้บน Cloud Shell และยืนยันว่าเวอร์ชันของ Go คือ 1.17 ขึ้นไป
go version
เอาต์พุตจากคำสั่ง
go version go1.18.3 linux/amd64
ตั้งค่าคลัสเตอร์ Google Kubernetes
ใน Codelab นี้ คุณจะได้เรียกใช้คลัสเตอร์ของ Microservice บน Google Kubernetes Engine (GKE) กระบวนการของ Codelab มีดังนี้
- ดาวน์โหลดโปรเจ็กต์พื้นฐานลงใน 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
Skaffold เป็นเครื่องมือที่มีประโยชน์เมื่อคุณสร้าง Microservice ที่ทำงานบน Kubernetes โดยจะจัดการกระบวนการสร้าง พุช และติดตั้งใช้งานคอนเทนเนอร์ของแอปพลิเคชันด้วยคำสั่งสั้นๆ โดยค่าเริ่มต้น Skaffold จะใช้ Docker Registry เป็นรีจิสทรีคอนเทนเนอร์ คุณจึงต้องกำหนดค่า Skaffold ให้จดจำ 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 สำหรับคอนเทนเนอร์รีจิสทรี
- ตั้งค่า Skaffold เพื่อใช้ Container Registry
- สร้างคลัสเตอร์ Kubernetes ที่ Codelab Microservice ทำงาน
ถัดไป
ในขั้นตอนถัดไป คุณจะต้องใช้ Agent เครื่องมือสร้างโปรไฟล์แบบต่อเนื่องในบริการเซิร์ฟเวอร์
3. สร้าง พุช และติดตั้งใช้งาน Microservice
ดาวน์โหลดเนื้อหา Codelab
ในขั้นตอนก่อนหน้า เราได้กำหนดข้อกำหนดเบื้องต้นทั้งหมดสำหรับ Codelab แล้ว ตอนนี้คุณพร้อมที่จะเรียกใช้ Microservice ทั้งระบบแล้ว เนื้อหา Codelab จะโฮสต์อยู่บน GitHub ดังนั้นให้ดาวน์โหลดเนื้อหาดังกล่าวไปยังสภาพแวดล้อม Cloud Shell ด้วยคำสั่ง git ต่อไปนี้
cd ~ git clone https://github.com/ymotongpoo/opentelemetry-trace-codelab-go.git cd opentelemetry-trace-codelab-go
โครงสร้างไดเรกทอรีของโครงการมีดังต่อไปนี้
. ├── README.md ├── step0 │ ├── manifests │ ├── proto │ ├── skaffold.yaml │ └── src ├── step1 │ ├── manifests │ ├── proto │ ├── skaffold.yaml │ └── src ├── step2 │ ├── manifests │ ├── proto │ ├── skaffold.yaml │ └── src ├── step3 │ ├── manifests │ ├── proto │ ├── skaffold.yaml │ └── src ├── step4 │ ├── manifests │ ├── proto │ ├── skaffold.yaml │ └── src ├── step5 │ ├── manifests │ ├── proto │ ├── skaffold.yaml │ └── src └── step6 ├── manifests ├── proto ├── skaffold.yaml └── src
- ไฟล์ Manifest: ไฟล์ Manifest ของ Kubernetes
- Proto: คำจำกัดความของ Proto สำหรับการสื่อสารระหว่างไคลเอ็นต์กับเซิร์ฟเวอร์
- src: ไดเรกทอรีสำหรับซอร์สโค้ดของแต่ละบริการ
- skaffold.yaml: ไฟล์การกำหนดค่าสำหรับ skaffold
ใน Codelab นี้ คุณจะอัปเดตซอร์สโค้ดที่อยู่ภายใต้โฟลเดอร์ 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 และหน่วยความจำในช่วงระยะเวลาหนึ่งๆ หลังจากรวบรวมข้อมูลโปรไฟล์แล้ว นักพัฒนาแอปจะวิเคราะห์โปรไฟล์นอกโค้ด
การทำโปรไฟล์แบบต่อเนื่องเป็นวิธีการเพิ่มเติมที่ใช้ทำโปรไฟล์ปกติ นั่นคือจะเรียกใช้โปรไฟล์หน้าต่างสั้นๆ ในแอปพลิเคชันที่ใช้เวลานานเป็นระยะๆ และรวบรวมข้อมูลโปรไฟล์จำนวนมาก จากนั้นโมเดลจะสร้างการวิเคราะห์ทางสถิติโดยอัตโนมัติตามแอตทริบิวต์บางอย่างของแอปพลิเคชัน เช่น หมายเลขเวอร์ชัน โซนการทำให้ใช้งานได้ เวลาในการวัด และอื่นๆ ดูรายละเอียดเพิ่มเติมเกี่ยวกับแนวคิดได้ในเอกสารของเรา
เนื่องจากเป้าหมายเป็นแอปพลิเคชันที่ทำงานอยู่ จึงมีวิธีรวบรวมข้อมูลโปรไฟล์เป็นระยะๆ และส่งข้อมูลดังกล่าวไปยังแบ็กเอนด์ที่ประมวลผลข้อมูลทางสถิติหลังประมวลผลข้อมูลแล้ว นั่นคือ Agent Cloud Profiler และคุณกำลังจะฝัง Agent นี้กับบริการเซิร์ฟเวอร์เร็วๆ นี้
ฝัง 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 ตอนนี้คุณจะเพิ่มการใช้เครื่องมือสำหรับ Agent ของ 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 นาทีจึงจะเห็นกราฟ Flame ใน Cloud Profiler พิมพ์ "profiler" ในช่องค้นหาที่ด้านบน และคลิกไอคอนเครื่องมือสร้างโปรไฟล์
จากนั้นคุณจะเห็นกราฟ Flame ต่อไปนี้
สรุป
ในขั้นตอนนี้ คุณได้ฝัง Agent ของ Cloud Profiler ไว้ในบริการเซิร์ฟเวอร์และยืนยันว่าสามารถสร้างกราฟเปลวไฟได้
ถัดไป
ในขั้นตอนถัดไป คุณจะตรวจสอบสาเหตุของจุดคอขวดในแอปพลิเคชันโดยใช้กราฟเปลวไฟ
5. วิเคราะห์กราฟ Flame ของ Cloud Profiler
กราฟเปลวไฟคืออะไร
กราฟ Flame Graph เป็นวิธีหนึ่งในการแสดงภาพข้อมูลโปรไฟล์ โปรดอ่านคำอธิบายโดยละเอียดในเอกสารของเรา แต่ข้อมูลสรุปสั้นๆ มีดังนี้
- แต่ละแถบแสดงการเรียกใช้เมธอด/ฟังก์ชันในแอปพลิเคชัน
- ทิศทางแนวตั้งคือการเรียกใช้สแต็ก สแต็กการเรียกใช้ขยายจากบนลงล่าง
- ทิศทางแนวนอนคือการใช้ทรัพยากร ยิ่งนาน ก็ยิ่งแย่
ดังนั้น เรามาดูกราฟเปลวไฟที่ได้รับกัน
การวิเคราะห์กราฟเปลวไฟ
ในส่วนก่อนหน้านี้ คุณได้ทราบว่าแต่ละแท่งในกราฟ 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-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 สำหรับเส้นทางคำขอได้ และคุณจะไม่ทราบสาเหตุที่แท้จริงของจุดคอขวดในบริการนั้นๆ ใน Codelab ส่วนที่ 2 นี้ คุณได้เรียนรู้ว่าการทำโปรไฟล์อย่างต่อเนื่องจะช่วยให้คุณระบุจุดคอขวดภายในบริการเดียวจากสแต็กการเรียกใช้ได้
ในขั้นตอนนี้ เราจะมาดูกราฟ Waterfall จากการติดตามแบบกระจาย (Cloud Trace) และดูความแตกต่างจากการสร้างโปรไฟล์แบบต่อเนื่อง
กราฟ Waterfall นี้คือหนึ่งในการติดตามที่มีคำค้นหา "love" ใช้เวลาประมาณ 6.7 วินาที (6,700 มิลลิวินาที)
และนี่เป็นหลังจากการปรับปรุงสำหรับคำค้นหาเดียวกัน อย่างที่บอกไป ตอนนี้เวลาในการตอบสนองรวมคือ 1.5 วินาที (1,500 มิลลิวินาที) ซึ่งนับว่าดีขึ้นมากจากการใช้งานก่อนหน้านี้
ประเด็นสําคัญคือในแผนภูมิการติดตามแบบกระจาย ข้อมูลสแต็กการเรียกใช้ไม่พร้อมใช้งาน เว้นแต่ว่าคุณจะใช้เครื่องมือที่ครอบคลุมทุกที่ นอกจากนี้การติดตามแบบกระจายยังมุ่งเน้นไปที่เวลาในการตอบสนองในบริการต่างๆ ในขณะที่การทำโปรไฟล์อย่างต่อเนื่องจะมุ่งเน้นที่ทรัพยากรคอมพิวเตอร์ (CPU, หน่วยความจำ, เทรดระบบปฏิบัติการ) ของบริการเดียว
ในอีกแง่หนึ่ง การติดตามแบบกระจายคือฐานเหตุการณ์ ส่วนโปรไฟล์แบบต่อเนื่องคือทางสถิติ การติดตามแต่ละรายการจะมีกราฟเวลาในการตอบสนองต่างกัน และคุณต้องใช้รูปแบบที่แตกต่างกัน เช่น การกระจาย เพื่อรับแนวโน้มของการเปลี่ยนแปลงเวลาในการตอบสนอง
สรุป
ในขั้นตอนนี้ คุณได้ตรวจสอบความแตกต่างระหว่างการติดตามแบบกระจายและการสร้างโปรไฟล์อย่างต่อเนื่อง
8. ขอแสดงความยินดี
คุณสร้างการติดตามแบบกระจายด้วย OpenTelemery และยืนยันเวลาในการตอบสนองของคำขอสำหรับ Microservice บน Google Cloud Trace เรียบร้อยแล้ว
สำหรับการออกกำลังกายระยะยาว คุณลองทำตามหัวข้อต่อไปนี้ด้วยตนเองได้
- การใช้งานปัจจุบันจะส่ง Span ทั้งหมดที่สร้างโดยการตรวจสอบประสิทธิภาพการทำงาน (
grpc.health.v1.Health/Check
) คุณจะกรองระยะเวลาเหล่านั้นออกจาก Cloud Traces อย่างไร คำแนะนำอยู่ที่นี่ - เชื่อมโยงบันทึกเหตุการณ์กับระยะเวลา แล้วดูว่าบันทึกนั้นทำงานอย่างไรใน Google Cloud Trace และ Google Cloud Logging คำแนะนำอยู่ที่นี่
- แทนที่บางบริการด้วยบริการที่เป็นภาษาอื่น แล้วลองใช้ OpenTelemetry สำหรับภาษานั้น
นอกจากนี้ ถ้าคุณต้องการทราบเกี่ยวกับเครื่องมือสร้างโปรไฟล์หลังจากนี้ โปรดไปยังส่วนที่ 2 ในกรณีนี้ คุณสามารถข้ามส่วน "ล้างข้อมูล" ด้านล่างได้
ล้างข้อมูล
หลังจาก Codelab นี้ โปรดหยุดคลัสเตอร์ Kubernetes และตรวจสอบว่าได้ลบโปรเจ็กต์แล้ว เพื่อไม่ให้มีการเรียกเก็บเงินที่ไม่คาดคิดใน Google Kubernetes Engine, Google Cloud Trace, Google Artifact Registry
ขั้นแรก ให้ลบคลัสเตอร์ หากคุณเรียกใช้คลัสเตอร์ด้วย skaffold dev
คุณเพียงแค่กด Ctrl-C หากคุณกำลังเรียกใช้คลัสเตอร์ด้วย skaffold run
ให้เรียกใช้คำสั่งต่อไปนี้
skaffold delete
เอาต์พุตจากคำสั่ง
Cleaning up... - deployment.apps "clientservice" deleted - service "clientservice" deleted - deployment.apps "loadgen" deleted - deployment.apps "serverservice" deleted - service "serverservice" deleted
หลังจากลบคลัสเตอร์แล้ว ให้เลือก "IAM & จากแผงเมนู ผู้ดูแลระบบ" "การตั้งค่า" แล้วคลิก "ปิด"
จากนั้นป้อนรหัสโปรเจ็กต์ (ไม่ใช่ชื่อโปรเจ็กต์) ในแบบฟอร์มในกล่องโต้ตอบและยืนยันการปิดเครื่อง