ปัญหาที่พบเจอกับระบบงานง่าย ๆ ที่พัฒนาด้วยภาษา Go เป็นดังนี้
- ระบบทำการดึงข้อมูลจาก MySQL database
- เป็นการดึงข้อมูลมาจาก 2 table และแยก query กัน (table แรกได้ id, table สองได้ detail)
- มีการใช้งาน connection pool
ปัญหาคือ เมื่อมี load จำนวนมากเกินกว่า max connection ใน connectio pool
จึงทำให้เกิด timeout ในการดึงข้อมูลขึ้นมา
จะแก้ไขอย่างไรดี ?
แนวทางการแก้ไขมีหลายวิธีการ
ยกตัวอย่างเช่น
- เพิ่ม max connection ใน connection pool ไปสิ (ทำได้ง่ายสุด ๆ แต่มีข้อจำกัดที่ database)
- แทนที่จะดึงแยกกัน 2 query หรือ 2 ครั้ง ทำไมไม่ใน query เดียวไปเลย ใช้การ join นั่นเอง
- ในกรณีนี้ ถ้าทำ pre-join data ไว้ก่อนก็ทำได้นะ เนื่องจากเป็นการดึง detail ของผู้ใช้งานในแต่ละ comment นั่นเอง
- ถ้ายังจะใช้ 2 query เหมือนเดิม ดังนั้นก็ต้องเข้าไป review code กันหน่อย
- ถ้าข้อมูลไม่ค่อยเปลี่ยนแปลง ก็ทำ caching ซะ น่าจะดีกว่า
จากที่แก้ไขมา ทุกแนวทางใช้ได้หมดเลย
นั่นหมายความว่า หนึ่งปัญหามันมีหลายวิธีในการแก้ไขนั่นเอง
แต่จากการ review code แล้วพบสิ่งที่น่าสนใจ
มาดูกันว่าเป็นอย่างไร
เริ่มจาก code เดิม ก็ทำการ load test ง่าย ๆ ก่อน
[gist id="1da6037e0fa4959c4631cd83debe722e" file="1.txt"]จะเห็นได้ว่าเกิด timeout ทั้งหมดเลย
เนื่องจากจำนวน concurrent user 50 ซึ่งมากกว่า max connection ใน connection pool นั่นเอง
แก้ไขด้วยการเพิ่ม max connection ก็เสร็จ แต่มันไม่ใช่ root cause !!
ดังนั้นไป review code กันหน่อย
สิ่งที่เจอคือ
ปัญหาคืออะไร ?
- สิ่งที่เจอคือ เป็นการวน loop ของข้อมูล rows.Next()
- ยังไม่พอ ใน loop มีการดึงข้อมูล user ของแต่ละคนอีก
ส่งผลให้ไม่ทำการคืน connection กลับไปยัง pool สักที
ดังนั้นเมื่อนักพัฒนาทดสอบคนเดียว ไม่มีทางเจอ
แต่เมื่อทำ load test ในจำนวนคนใช้งานมากขึ้น
จึงทำให้เกิดปัญหา
ดังนั้นการแก้ไขที่จุดเกิดเหตุคือ เปลี่ยน flow ของ code ซะ
ให้ทำการดึงข้อมูล list comment เสร็จแล้ว และคืน conenction ไปที่ connection pool
จากนั้นจึงทำการดึงข้อมูลของ user อีกที ดังนี้
ก็เร็วขึ้นอยู่นะ
มีหลายวิธีการให้แก้ไข สนุกดีนะครับ