เกี่ยวกับ Codelab นี้
1 ภาพรวม
แม้ว่านักพัฒนาแอปไคลเอ็นต์และเว็บฟรอนท์เอนด์มักจะใช้เครื่องมืออย่างเครื่องมือสร้างโปรไฟล์ CPU ของ Android Studio หรือเครื่องมือทำโปรไฟล์ที่รวมอยู่ใน Chrome เพื่อปรับปรุงประสิทธิภาพของโค้ด แต่ผู้ที่ทำงานบนบริการแบ็กเอนด์ยังไม่มีเทคนิคที่เทียบเท่ากัน Cloud Profiler นำความสามารถเดียวกันนี้มาสู่นักพัฒนาซอฟต์แวร์บริการ โดยไม่คำนึงว่าโค้ดของพวกเขาจะทำงานบน Google Cloud Platform หรือที่อื่นๆ
เครื่องมือจะรวบรวมข้อมูลการใช้งาน CPU และการจัดสรรหน่วยความจำจากแอปพลิเคชันเวอร์ชันที่ใช้งานจริง โดยจะระบุแหล่งที่มาของข้อมูลดังกล่าวเป็นซอร์สโค้ดของแอปพลิเคชัน ซึ่งจะช่วยให้คุณระบุส่วนต่างๆ ของแอปพลิเคชันที่ใช้ทรัพยากรมากที่สุด และทำให้ประสิทธิภาพการทำงานของโค้ดโดดเด่นยิ่งขึ้น โอเวอร์เฮดน้อยของเทคนิคการรวบรวมข้อมูลที่เครื่องมือใช้ทำให้เหมาะสำหรับการใช้งานอย่างต่อเนื่องในสภาพแวดล้อมการผลิต
ใน Codelab นี้ คุณจะได้ดูวิธีตั้งค่า Cloud Profiler สำหรับโปรแกรม Go และจะได้ทำความคุ้นเคยกับข้อมูลเชิงลึกเกี่ยวกับประสิทธิภาพของแอปพลิเคชันที่เครื่องมือสามารถนำเสนอได้
สิ่งที่คุณจะได้เรียนรู้
- วิธีกำหนดค่าโปรแกรม Go สำหรับการทำโปรไฟล์ด้วย Cloud Profiler
- วิธีรวบรวม ดู และวิเคราะห์ข้อมูลประสิทธิภาพด้วย Cloud Profiler
สิ่งที่คุณต้องมี
- โปรเจ็กต์ Google Cloud Platform
- เบราว์เซอร์ เช่น Chrome หรือ Firefox
- คุ้นเคยกับเครื่องมือแก้ไขข้อความมาตรฐานของ Linux เช่น Vim, EMACs หรือ Nano
คุณจะใช้บทแนะนำนี้อย่างไร
คุณจะให้คะแนนประสบการณ์การใช้งาน Google Cloud Platform อย่างไร
2 การตั้งค่าและข้อกำหนด
การตั้งค่าสภาพแวดล้อมตามเวลาที่สะดวก
- ลงชื่อเข้าใช้ Cloud Console และสร้างโปรเจ็กต์ใหม่หรือใช้โปรเจ็กต์ที่มีอยู่ซ้ำ หากยังไม่มีบัญชี Gmail หรือ Google Workspace คุณต้องสร้างบัญชี
โปรดจดจำรหัสโปรเจ็กต์ ซึ่งเป็นชื่อที่ไม่ซ้ำกันในโปรเจ็กต์ Google Cloud ทั้งหมด (ชื่อด้านบนมีคนใช้แล้ว และจะใช้ไม่ได้ ขออภัย) และจะมีการอ้างอิงใน Codelab ว่า PROJECT_ID
ในภายหลัง
- ถัดไป คุณจะต้องเปิดใช้การเรียกเก็บเงินใน Cloud Console เพื่อใช้ทรัพยากร Google Cloud
การใช้งาน Codelab นี้น่าจะไม่มีค่าใช้จ่ายใดๆ หากมี ตรวจสอบว่าคุณได้ทำตามวิธีการใน "การล้างข้อมูล" ซึ่งจะแนะนำคุณเกี่ยวกับวิธีปิดทรัพยากรเพื่อไม่ให้มีการเรียกเก็บเงินนอกเหนือจากบทแนะนำนี้ ผู้ใช้ใหม่ของ Google Cloud จะมีสิทธิ์เข้าร่วมโปรแกรมทดลองใช้ฟรี$300 USD
Google Cloud Shell
แม้ว่าคุณจะดำเนินการ Google Cloud จากระยะไกลได้จากแล็ปท็อป แต่เราจะใช้ Google Cloud Shell ซึ่งเป็นสภาพแวดล้อมบรรทัดคำสั่งที่ทำงานในระบบคลาวด์เพื่อให้การตั้งค่าง่ายขึ้นใน Codelab
เปิดใช้งาน Cloud Shell
- คลิกเปิดใช้งาน Cloud Shell
จาก Cloud Console
หากคุณไม่เคยเริ่มต้นใช้งาน Cloud Shell มาก่อน คุณจะเห็นหน้าจอตรงกลาง (ครึ่งหน้าล่าง) ซึ่งอธิบายว่านี่คืออะไร หากเป็นเช่นนั้น ให้คลิกดำเนินการต่อ (คุณจะไม่เห็นการดำเนินการนี้อีก) หน้าจอแบบครั้งเดียวมีลักษณะดังนี้
การจัดสรรและเชื่อมต่อกับ Cloud Shell ใช้เวลาเพียงไม่กี่นาที
เครื่องเสมือนนี้เต็มไปด้วยเครื่องมือการพัฒนาทั้งหมดที่คุณต้องการ โดยมีไดเรกทอรีหลักขนาด 5 GB ที่ทำงานอย่างต่อเนื่องใน Google Cloud ซึ่งจะช่วยเพิ่มประสิทธิภาพของเครือข่ายและการตรวจสอบสิทธิ์ได้อย่างมาก งานส่วนใหญ่ใน Codelab นี้สามารถทำได้โดยใช้เบราว์เซอร์หรือ Chromebook เท่านั้น
เมื่อเชื่อมต่อกับ Cloud Shell คุณควรเห็นว่าได้รับการตรวจสอบสิทธิ์แล้ว และโปรเจ็กต์ได้รับการตั้งค่าเป็นรหัสโปรเจ็กต์แล้ว
- เรียกใช้คำสั่งต่อไปนี้ใน Cloud Shell เพื่อยืนยันว่าคุณได้รับการตรวจสอบสิทธิ์แล้ว
gcloud auth list
เอาต์พุตจากคำสั่ง
Credentialed Accounts ACTIVE ACCOUNT * <my_account>@<my_domain.com> To set the active account, run: $ gcloud config set account `ACCOUNT`
- เรียกใช้คำสั่งต่อไปนี้ใน Cloud Shell เพื่อยืนยันว่าคำสั่ง gcloud รู้เกี่ยวกับโปรเจ็กต์ของคุณ
gcloud config list project
เอาต์พุตจากคำสั่ง
[core] project = <PROJECT_ID>
หากไม่ใช่ ให้ตั้งคำสั่งด้วยคำสั่งนี้
gcloud config set project <PROJECT_ID>
เอาต์พุตจากคำสั่ง
Updated property [core/project].
3 ไปที่ Cloud Profiler
ใน Cloud Console ให้ไปที่ UI เครื่องมือสร้างโปรไฟล์โดยคลิก "Profiler" ในแถบนำทางด้านซ้าย
หรือจะใช้แถบค้นหา Cloud Console เพื่อไปยัง UI ของเครื่องมือสร้างโปรไฟล์ เพียงพิมพ์ "Cloud Profiler" แล้วเลือกรายการที่พบ ไม่ว่าคุณจะเลือกแบบใด คุณควรเห็น UI เครื่องมือสร้างโปรไฟล์พร้อมข้อความ "ไม่มีข้อมูลที่จะแสดง" ดังตัวอย่างด้านล่าง โปรเจ็กต์นี้เป็นโปรเจ็กต์ใหม่ จึงยังไม่มีการเก็บข้อมูลการทำโปรไฟล์ไว้
ได้เวลาสร้างโปรไฟล์แล้ว
4 สร้างโปรไฟล์การเปรียบเทียบ
เราจะใช้แอปพลิเคชัน Go สังเคราะห์อย่างง่ายที่มีอยู่ใน GitHub ในเทอร์มินัล Cloud Shell ที่คุณยังเปิดอยู่ (และในขณะที่ข้อความ "ไม่มีข้อมูลที่จะแสดง" ยังคงแสดงอยู่ใน UI เครื่องมือสร้างโปรไฟล์) ให้เรียกใช้คำสั่งต่อไปนี้
$ go get -u github.com/GoogleCloudPlatform/golang-samples/profiler/...
จากนั้นสลับไปที่ไดเรกทอรีแอปพลิเคชัน
$ cd ~/gopath/src/github.com/GoogleCloudPlatform/golang-samples/profiler/hotapp
ไดเรกทอรีมีบรรทัด "main.go" ซึ่งเป็นแอปสังเคราะห์ที่เปิดใช้ Agent การสร้างโปรไฟล์
main.go
...
import (
...
"cloud.google.com/go/profiler"
)
...
func main() {
err := profiler.Start(profiler.Config{
Service: "hotapp-service",
DebugLogging: true,
MutexProfiling: true,
})
if err != nil {
log.Fatalf("failed to start the profiler: %v", err)
}
...
}
Agent การสร้างโปรไฟล์จะรวบรวมโปรไฟล์ CPU, ฮีป และเทรดโดยค่าเริ่มต้น โค้ดในที่นี้จะเปิดใช้การรวบรวมโปรไฟล์ Mutex (หรือที่เรียกว่า "contention")
เรียกใช้โปรแกรมเลย ดังนี้
$ go run main.go
ขณะที่โปรแกรมทำงาน Agent การสร้างโปรไฟล์จะรวบรวมโปรไฟล์ของทั้ง 5 ประเภทที่กำหนดค่าไว้เป็นระยะๆ การเก็บรวบรวมข้อมูลจะเป็นแบบสุ่มเมื่อเวลาผ่านไป (ด้วยอัตราเฉลี่ยของ 1 โปรไฟล์ต่อนาทีสำหรับแต่ละประเภท) ดังนั้นอาจใช้เวลานานถึง 3 นาทีในการรวบรวมข้อมูลแต่ละประเภท โปรแกรมจะแจ้งให้คุณทราบเมื่อสร้างโปรไฟล์ ข้อความเปิดใช้โดยแฟล็ก DebugLogging
ในการกำหนดค่าข้างต้น มิฉะนั้น ตัวแทนจะทำงานโดยไม่มีการแจ้งเตือน:
$ go run main.go 2018/03/28 15:10:24 profiler has started 2018/03/28 15:10:57 successfully created profile THREADS 2018/03/28 15:10:57 start uploading profile 2018/03/28 15:11:19 successfully created profile CONTENTION 2018/03/28 15:11:30 start uploading profile 2018/03/28 15:11:40 successfully created profile CPU 2018/03/28 15:11:51 start uploading profile 2018/03/28 15:11:53 successfully created profile CONTENTION 2018/03/28 15:12:03 start uploading profile 2018/03/28 15:12:04 successfully created profile HEAP 2018/03/28 15:12:04 start uploading profile 2018/03/28 15:12:04 successfully created profile THREADS 2018/03/28 15:12:04 start uploading profile 2018/03/28 15:12:25 successfully created profile HEAP 2018/03/28 15:12:25 start uploading profile 2018/03/28 15:12:37 successfully created profile CPU ...
UI จะอัปเดตเองในไม่ช้าหลังจากที่มีการรวบรวมโปรไฟล์แรก และจะไม่อัปเดตอัตโนมัติหลังจากนั้น ดังนั้นหากต้องการดูข้อมูลใหม่ คุณจะต้องรีเฟรช UI เครื่องมือสร้างโปรไฟล์ด้วยตนเอง ในการดำเนินการนี้ ให้คลิกปุ่ม "ตอนนี้" ในเครื่องมือเลือกช่วงเวลา 2 ครั้ง
หลังจากรีเฟรช UI คุณจะเห็นดังนี้
ตัวเลือกประเภทโปรไฟล์แสดงโปรไฟล์ 5 ประเภทที่ใช้ได้ ดังนี้
มาดูโปรไฟล์แต่ละประเภทและความสามารถด้าน UI ที่สำคัญบางอย่าง จากนั้นจึงทำการทดสอบ ในขั้นตอนนี้ คุณไม่จำเป็นต้องใช้เทอร์มินัล Cloud Shell อีกต่อไป คุณสามารถออกโดยการกด Ctrl-C และพิมพ์ "exit"
5 วิเคราะห์ข้อมูลเครื่องมือสร้างโปรไฟล์
เมื่อเรารวบรวมข้อมูลบางส่วนไปแล้ว เรามาดูรายละเอียดกัน เราใช้แอปสังเคราะห์ (แหล่งที่มานี้มีให้ใช้งานใน GitHub) ซึ่งจำลองพฤติกรรมทั่วไปของปัญหาด้านประสิทธิภาพประเภทต่างๆ ในเวอร์ชันที่ใช้งานจริง
โค้ดแบบ CPU
เลือกประเภทโปรไฟล์ CPU หลังจาก UI โหลดแล้ว คุณจะเห็นบล็อก 4 แฉกของฟังก์ชัน load
ในกราฟ Flame ซึ่งพิจารณาการใช้ CPU ทั้งหมดรวมกัน ดังนี้
ฟังก์ชันนี้เขียนขึ้นเพื่อให้ใช้รอบ CPU สูงโดยเฉพาะด้วยการเรียกใช้ลูปจำกัด:
main.go
func load() {
for i := 0; i < (1 << 20); i++ {
}
}
ระบบจะเรียกฟังก์ชันนี้โดยอ้อมจาก busyloop
() ผ่านทางเส้นทางการเรียก 4 เส้นทาง ได้แก่ busyloop
→ {foo1
, foo2
} → {bar
, baz
} → load
ความกว้างของกล่องฟังก์ชันแสดงถึงต้นทุนสัมพัทธ์ของเส้นทางการเรียกใช้ที่เฉพาะเจาะจง ในกรณีนี้ทั้ง 4 เส้นทางมีค่าใช้จ่ายเท่ากัน ในโปรแกรมจริง คุณต้องการเน้นการเพิ่มประสิทธิภาพเส้นทางการโทรที่มีความสำคัญมากที่สุดในแง่ของประสิทธิภาพ กราฟเปลวไฟซึ่งเน้นเส้นทางที่มีราคาแพงกว่าพร้อมด้วยกล่องที่ใหญ่กว่า ทำให้ระบุเส้นทางเหล่านี้ได้ง่าย
คุณสามารถใช้ตัวกรองข้อมูลโปรไฟล์เพื่อปรับแต่งการแสดงผลเพิ่มเติมได้ ตัวอย่างเช่น ลองเพิ่ม "แสดงกองรูปภาพ" ตัวกรองที่ระบุ "baz" เป็นสตริงตัวกรอง คุณควรจะเห็นบางอย่างเหมือนภาพหน้าจอด้านล่าง ซึ่งแสดงเส้นทางการโทรไปยัง load()
เพียง 2 จาก 4 เส้นทางเท่านั้น เส้นทางทั้งสองนี้เป็นเพียงเส้นทางเดียวที่ไปยังฟังก์ชันที่มีสตริง "baz" ในชื่อ การกรองดังกล่าวมีประโยชน์เมื่อคุณต้องการโฟกัสที่ส่วนย่อยๆ ของโปรแกรมที่ใหญ่กว่า (เช่น เนื่องจากคุณเป็นเจ้าของเฉพาะบางส่วนของโปรแกรม)
โค้ดที่ใช้หน่วยความจำมาก
เปลี่ยนเป็น "ฮีป" ประเภทโปรไฟล์ อย่าลืมนำตัวกรองที่คุณสร้างไว้ในการทดสอบก่อนหน้าออก ตอนนี้คุณจะเห็นกราฟเปลวไฟที่ allocImpl
ซึ่งเรียกใช้โดย alloc
แสดงเป็นผู้บริโภคหลักของหน่วยความจำในแอป
ตารางสรุปเหนือกราฟ Flame Fit ระบุว่าจำนวนหน่วยความจำที่ใช้ทั้งหมดในแอปโดยเฉลี่ยอยู่ที่ประมาณ 57.4 MiB หน่วยความจำส่วนใหญ่จัดสรรตามฟังก์ชัน allocImpl
ซึ่งไม่น่าประหลาดใจเนื่องจากการใช้งานฟังก์ชันนี้:
main.go
func allocImpl() {
// Allocate 64 MiB in 64 KiB chunks
for i := 0; i < 64*16; i++ {
mem = append(mem, make([]byte, 64*1024))
}
}
ฟังก์ชันนี้จะทำงานครั้งเดียว โดยจัดสรร 64 MiB เป็นส่วนย่อยที่เล็กลง จากนั้นจัดเก็บตัวชี้ไปยังชิ้นส่วนเหล่านั้นในตัวแปรร่วมเพื่อป้องกันการเก็บข้อมูลขยะ โปรดทราบว่าจำนวนหน่วยความจำที่เครื่องมือสร้างโปรไฟล์ใช้อยู่จะแตกต่างจาก 64 MiB เล็กน้อย เครื่องมือสร้างโปรไฟล์ฮีปของ Go เป็นเครื่องมือทางสถิติ การวัดจึงมีค่าใช้จ่ายแบบโอเวอร์เฮดต่ำ แต่ไม่แม่นยำเป็นไบต์ โปรดอย่าแปลกใจเมื่อเห็นความแตกต่าง ~10% เช่นนี้
โค้ดที่เน้น IO
หากคุณเลือก "ชุดข้อความ" ในตัวเลือกประเภทโปรไฟล์ การแสดงผลจะสลับเป็นกราฟเปลวไฟ ซึ่งฟังก์ชัน wait
และ waitImpl
จะใช้ความกว้างส่วนใหญ่
ในสรุปกราฟเปลวไฟด้านบน จะเห็นว่ามีโกรูทีน 100 ตัวที่เพิ่มจำนวนการเรียกจากฟังก์ชัน wait
โค้ดนี้ถูกต้องทุกประการเนื่องจากโค้ดที่เริ่มการรอเหล่านี้จะมีลักษณะดังนี้
main.go
func main() {
...
// Simulate some waiting goroutines.
for i := 0; i < 100; i++ {
go wait()
}
โปรไฟล์ประเภทนี้มีประโยชน์ในการทำความเข้าใจว่าโปรแกรมใช้เวลารอแบบไม่คาดคิดหรือไม่ (เช่น I/O) โดยปกติแล้ว สแต็กการเรียกใช้ดังกล่าวจะไม่สุ่มตัวอย่างโดยเครื่องมือสร้างโปรไฟล์ CPU เนื่องจากไม่ได้ใช้เวลา CPU อย่างมาก คุณมักต้องการใช้ "ซ่อนกอง" ตัวกรองที่มีโปรไฟล์ "ชุดข้อความ" เช่น เพื่อซ่อนสแต็กทั้งหมดที่ลงท้ายด้วยการเรียกไปยัง gopark,
เนื่องจากแท็กเหล่านั้นมักจะเป็นโกรูทีนที่ไม่มีความเคลื่อนไหวและน่าสนใจน้อยกว่าสแต็กที่รออยู่ใน I/O
ประเภทโปรไฟล์ของเทรดยังช่วยระบุจุดในโปรแกรมที่เทรดกำลังรอ Mutex ที่เป็นของส่วนอื่นของโปรแกรมมาเป็นเวลานาน แต่โปรไฟล์ประเภทต่อไปนี้จะมีประโยชน์มากกว่า
โค้ดที่มีการแข่งขันกันอย่างดุเดือด
ประเภทโปรไฟล์การโต้แย้งจะระบุรายการที่ "ต้องการ" มากที่สุด ล็อกในโปรแกรม โปรไฟล์ประเภทนี้ใช้ได้กับโปรแกรม Go แต่ต้องเปิดใช้อย่างชัดเจนโดยระบุ "MutexProfiling: true
" ในรหัสการกำหนดค่า Agent การเก็บรวบรวมนี้ทำงานโดยการบันทึก (ภายใต้เมตริก "การช่วงชิง") จำนวนครั้งที่ล็อกตัวใดตัวหนึ่ง เมื่อถูกโกรูทีน A ปลดล็อก ตัวโกรูทีน B อีกตัวหนึ่งตัวขณะที่รอการปลดล็อก นอกจากนี้ยังบันทึก (ในเมตริก "ถ่วงเวลา") เวลาที่โกโรทีนที่ถูกบล็อกรอการล็อกด้วย ในตัวอย่างนี้ มีสแต็กเดี่ยวๆ และเวลารอรวมของการล็อกคือ 10.5 วินาที
โค้ดที่สร้างโปรไฟล์นี้ประกอบไปด้วยโกโรทีน 4 ตัวที่กำลังต่อสู้กันเหนือ Mutex ดังนี้
main.go
func contention(d time.Duration) {
contentionImpl(d)
}
func contentionImpl(d time.Duration) {
for {
mu.Lock()
time.Sleep(d)
mu.Unlock()
}
}
...
func main() {
...
for i := 0; i < 4; i++ {
go contention(time.Duration(i) * 50 * time.Millisecond)
}
}
6 สรุป
ในห้องทดลองนี้ คุณได้เรียนรู้วิธีกำหนดค่าโปรแกรม Go ให้ใช้ร่วมกับ Cloud Profiler แล้ว และคุณยังได้เรียนรู้วิธีรวบรวม ดู และวิเคราะห์ข้อมูลประสิทธิภาพด้วยเครื่องมือนี้อีกด้วย ตอนนี้คุณใช้ทักษะใหม่กับบริการจริงที่ใช้ใน Google Cloud Platform ได้แล้ว
7 ยินดีด้วย
คุณได้เรียนรู้วิธีกำหนดค่าและใช้ Cloud Profiler แล้ว
ดูข้อมูลเพิ่มเติม
- Cloud Profiler: https://cloud.google.com/profiler/
- แพ็กเกจรันไทม์/pprof ที่ Cloud Profiler ใช้: https://golang.org/pkg/runtime/pprof/
ใบอนุญาต
ผลงานนี้ได้รับอนุญาตภายใต้ใบอนุญาตทั่วไปครีเอทีฟคอมมอนส์แบบระบุแหล่งที่มา 2.0