ODOO 19 · POSTGRESQL 16 · DIGITALOCEAN SGP1

Odoo Load Test Study Result

เราอยากรู้ว่า Odoo 19 บนเครื่องขนาดเล็กรับงานได้จริงแค่ไหน จึงตั้งเครื่องทดสอบขึ้นมาเจ็ดรอบ แล้ววัดด้วยผู้ใช้เสมือนจนกว่าจะเจอขีดจำกัด ผลที่ได้ไม่ตรงกับที่เราเดาไว้ตั้งแต่ต้น ตัวที่ตันไม่ใช่ CPU และวิธีแก้ที่เราคิดว่าจะได้ผลกลับทำให้แย่ลง บันทึกนี้เล่าว่าเราวัดอะไร เจออะไร และยังไม่รู้อะไรบ้าง

400,000คำขอที่ใช้ในการทดสอบ รวมเจ็ดรอบ
0ครั้งที่ระบบตอบไม่สำเร็จ ตลอดทุกรอบ
81 msเวลาตอบสนอง p95 เมื่อมีผู้ใช้พร้อมกัน 60 คน
80ระดับผู้ใช้พร้อมกันที่พบความล่าช้ารุนแรง

01 ผลที่วัดได้จากการทดสอบ

เราตั้งเครื่องจริงบน DigitalOcean ใส่ข้อมูลจำลอง 20,304 ใบสั่งขาย แล้วปล่อย ผู้ใช้เสมือน (Virtual User หรือ VU) เข้าไปใช้งานพร้อมกัน เพิ่มทีละขั้นตั้งแต่ 10 VU จนถึง 60 VU โดยให้แต่ละ VU เว้นจังหวะกดแบบคนจริง ทั้งเปิดดู แก้ไข และสั่งพิมพ์รายงาน

ผู้ใช้พร้อมกัน
เวลาตอบสนอง (p95)
45 ms
CPU ที่ใช้
11.3%
คำขอที่ล้มเหลว
0.00%
สถานะ
ปกติ
ช่วงที่ประเมินไว้ ต่ำกว่า 10 คน ยังไม่เคยวัดในช่วงนี้ พบความล่าช้ารุนแรงที่ 80 คน 0 25 50 75 100 เวลาตอบสนอง p95 (มิลลิวินาที) 10 20 30 40 50 60 80 ผู้ใช้พร้อมกัน (คน)

ตั้งแต่ 10 คนถึง 60 คน เวลาตอบสนองเพิ่มจาก 37 เป็น 81 มิลลิวินาที ซึ่งยังเร็วกว่าเกณฑ์อ้างอิง 1 วินาที อยู่ราวสิบสองเท่า และ CPU เพิ่มขึ้นในสัดส่วนที่คงที่ ระดับที่ทดสอบสูงกว่าค่าประมาณการใช้งานราวหกเท่า และยังใช้ CPU ประมาณหนึ่งในสี่

ระดับที่ทดสอบสูงกว่าที่ระบบขนาดนี้มักเจอในงานจริงพอสมควร โดยทั่วไปจำนวนผู้ใช้ที่กดพร้อมกันจริง มักอยู่ราว 10 ถึง 25 เปอร์เซ็นต์ของบัญชีทั้งหมด ระบบที่มีผู้ใช้ราวสามสิบถึงสี่สิบบัญชีจึงมักมีผู้ใช้พร้อมกันไม่ถึง 10 VU ทั้งนี้ตัวเลขนี้ควรยืนยันจากการใช้งานจริงก่อนสรุปขนาดเครื่องเสมอ

อ่านตัวเลขชุดนี้อย่างไร

ผลทั้งหมดมาจากการทดสอบด้วยผู้ใช้เสมือนและข้อมูลจำลอง ไม่ใช่จากการใช้งานจริง ข้อจำกัดสองข้อที่มีผลต่อการตีความมากที่สุดคือ ข้อมูลที่ใช้ทดสอบมีประมาณ 8.5 เปอร์เซ็นต์ ของปริมาณเป้าหมาย และยังไม่มีตัวเลขผู้ใช้พร้อมกันจากการใช้งานจริงมายืนยัน รายละเอียดทั้งหมดอยู่ในหัวข้อที่ 07

02 ระบบเริ่มช้าจนกระทบงานเมื่อใด

เราเพิ่มจำนวนผู้ใช้ต่อจนพบข้อจำกัด เพื่อระบุช่วงที่ประสิทธิภาพเริ่มลดลง ผลพบการเปลี่ยนแปลงชัดเจนระหว่าง 60 ถึง 80 คน โดยข้อจำกัดหลักไม่ได้อยู่ที่ CPU หรือหน่วยความจำ แต่อยู่ที่การรอแก้ไขข้อมูลสต็อกพร้อมกัน

ตอนที่ประสิทธิภาพลดลงค่าที่วัดได้แปลว่า
CPU59%ยังเหลือว่างอีกสี่สิบเปอร์เซ็นต์ ไม่ใช่ตัวที่ตัน
ฐานข้อมูล17 จาก 18 การเชื่อมต่อการเชื่อมต่อส่วนใหญ่อยู่ในสถานะรอ ไม่พบว่าฐานข้อมูลประมวลผลเต็ม
หน่วยความจำ150-170 MBต่อหนึ่ง worker จากเพดาน 352 MB ไม่ใกล้เต็ม
ยืนยันใบสั่งขาย11 วินาทีจากเดิม 1.5 วินาที และกินคิวงานจนหมด
การรอล็อกที่ stock_quant20-32 ครั้งต่อนาทีนี่คือข้อจำกัดที่พบจริง

สาเหตุอยู่ที่การจองสต็อก เมื่อยืนยันใบสั่งขาย Odoo ต้องควบคุมข้อมูลใน stock_quant เพื่อไม่ให้หลายรายการตัดสต็อกชุดเดียวกันพร้อมกัน เมื่อมีการยืนยันพร้อมกันมากขึ้น งานจึงต้องรอแก้ไขข้อมูลชุดเดียวกัน และทำให้รายการอื่นช้าตามไปด้วย

ข้อควรระวัง ระบบอาจช้าลงโดยไม่มีข้อความผิดพลาด

เมื่อเกิดการรอล็อก Odoo จะลองทำรายการใหม่ให้เอง ผู้ใช้จึงไม่เห็นข้อความผิดพลาด และระบบเฝ้าระวังที่ตรวจเฉพาะคำขอที่ล้มเหลวจะไม่แจ้งเตือน ตลอดการทดสอบอัตราคำขอที่ล้มเหลว อยู่ที่ 0.00 เปอร์เซ็นต์ ทั้งที่เวลาตอบสนองเพิ่มขึ้นราวยี่สิบเท่า อาการเดียวที่สังเกตได้คือระบบช้าลง ระบบเฝ้าระวังจึงต้องวัดเวลาตอบสนอง ไม่ใช่ดูเพียงว่าระบบยังตอบอยู่หรือไม่

03 การเพิ่ม worker ไม่ได้ทำให้งานเร็วขึ้น

เมื่อระบบเริ่มช้า ทางเลือกหนึ่งคือเพิ่ม worker เพื่อรับงานพร้อมกันได้มากขึ้น เราจึงทดสอบบนเครื่องเดิมและข้อมูลชุดเดิม โดยเพิ่ม worker จาก 9 เป็น 16 ผลออกมาตรงข้ามกับที่คาด

ที่ผู้ใช้ 60 คน9 workers16 workers
เวลายืนยันใบสั่งขาย1,900 ms2,700 ms
การรอล็อกต่อนาที~10~25
งานที่ทำได้ต่อวินาที41.941.4
CPU23.1%29.0%

การเพิ่ม worker ทำให้หลายงานพยายามแก้ไขข้อมูลสต็อกพร้อมกันมากขึ้น การรอล็อกจึงถี่ขึ้นสองเท่าครึ่ง ขณะที่ปริมาณงานที่ทำได้ต่อวินาทีแทบไม่เปลี่ยน ผลทดสอบชี้ว่าข้อจำกัดอยู่ที่วิธีที่ Odoo จัดลำดับการเขียนข้อมูล มากกว่าจำนวน core จึงยังไม่มีหลักฐานว่าการเพิ่ม core เพียงอย่างเดียวจะแก้ข้อจำกัดนี้ได้

ข้อนี้ยังหักล้างการคาดการณ์ของเราเองด้วย ก่อนหน้านี้เราคำนวณว่า 16 workers น่าจะดันเพดานไปถึง 130 ถึง 180 คน การคำนวณนั้นตั้งอยู่บนสมมติฐานว่า CPU คือตัวที่ตัน ซึ่งผิด

การเทียบครั้งนั้นยังมีช่องโหว่อยู่ข้อหนึ่ง คือมีแต่ผลของ 16 workers เท่านั้น ที่ถูกดันเกิน 60 คน จึงไม่มีผลของ 9 workers ที่ระดับเดียวกันมาเทียบ เราจึงย้อนกลับไปทดสอบ บนเครื่องเดิม ด้วยรูปแบบการเพิ่มผู้ใช้แบบเดียวกัน

จุดที่เริ่มมีปัญหา16 workers9 workers
ขั้นสูงสุดที่ผ่านได้60 คน80 คน
เริ่มมีปัญหาที่80 คน80-100 คน
CPU ตอนที่มีปัญหา59%29%

เครื่องที่มี worker น้อยกว่ากลับรับผู้ใช้ได้มากกว่า และใช้ CPU เพียงครึ่งเดียว worker ที่เพิ่มเข้ามาแต่ละตัวคืองานอีกหนึ่งงานที่พยายามแก้ไขข้อมูลสต็อกชุดเดียวกันในจังหวะเดียวกัน สำหรับงานลักษณะนี้ worker จึงไม่ใช่กำลังการผลิต แต่เป็นการแย่งคิวกันเอง

04 ตัวเชื่อมมาร์เก็ตเพลสที่ยืนยันใบสั่งขาย

การทดสอบชุดแรกใช้ตัวเชื่อมที่สร้างใบสั่งขายแล้วหยุด ไม่เคยยืนยันใบสั่ง จึงไม่เคยสร้างใบส่งของและไม่เคยแตะการจองสต็อก ซึ่งเป็นเส้นทางเดียวกับที่ทำให้ระบบช้าลงในหัวข้อที่ 02 แต่ตัวเชื่อมที่ใช้งานจริงยืนยันใบสั่ง เราจึงแก้ให้ทำงานเต็มกระบวนการแล้วทดสอบใหม่

ตัวเชื่อมทำงานลำพังสร้างอย่างเดียวสร้างและยืนยัน
CPU ที่ใช้4.3%11.4%
เวลาเขียน (p95)180 ms410 ms
ใบสั่งขายต่อนาที200196
การรอล็อก stock_quant ใน 20 นาทีไม่พบ8 ครั้ง

ต้นทุนจริงของตัวเชื่อมสูงกว่าที่วัดไว้เดิม 2.7 เท่า ที่สำคัญกว่าตัวเลข CPU คือการรอล็อก แม้ไม่มีผู้ใช้คนอื่นอยู่บนเครื่องเลย ตัวเชื่อมก็เดินไปถึงการจองสต็อกได้ด้วยตัวเอง ซึ่งการทดสอบชุดเดิมไปไม่ถึง เพราะเราออกแบบให้ไม่ยืนยันใบสั่ง

จากนั้นเราใส่ผู้ใช้กลับเข้าไปพร้อมกับตัวเชื่อม ด้วยรูปแบบเดียวกับการทดสอบเดิม ต่างกันเพียงตัวเชื่อมที่ทำงานจนจบกระบวนการ

ที่ผู้ใช้ 60 คน + ตัวเชื่อมสร้างอย่างเดียวสร้างและยืนยัน
เวลาตอบสนอง (p95)350 ms830 ms
งานที่ทำได้ต่อวินาที41.234.7
ใบสั่งขายจากตัวเชื่อม13,7979,964
ใบสั่งขายจากผู้ใช้4,1103,634
การรอล็อกตลอดการทดสอบ518791
CPU ที่ใช้28.5%25.5%
คำขอที่ล้มเหลว00

ให้อ่านสองแถวล่างพร้อมกัน เครื่องพยายามทำงานมากขึ้น ตอบสนองช้าลงกว่าสองเท่า ทำใบสั่งขายจากตัวเชื่อมได้น้อยลง 28 เปอร์เซ็นต์ และใช้ CPU น้อยลงสามจุด เพราะ worker นั่งรอคิวแก้ไขข้อมูลสต็อกชุดเดียวกัน worker ที่รออยู่ถูกจองไว้แล้วแต่ไม่ได้ทำงาน

ตัวเชื่อมตามงานของตัวเองไม่ทัน เมื่ออยู่ลำพังทำได้ 196 ใบต่อนาที เมื่อมีผู้ใช้อยู่ด้วยทำได้ 142 ใบต่อนาที ไม่มีอะไรล้มเหลว ไม่มี error รายงานออกมา เพียงแต่ทั้งสองฝ่ายทำงานได้น้อยลง

นี่คือผลที่มีน้ำหนักที่สุดต่อการวางระบบ เพราะปัญหามองไม่เห็นจากสองทางพร้อมกัน error อยู่ที่ศูนย์ เพราะ Odoo ลองใหม่ให้เองอย่างเงียบ ๆ ส่วนกราฟ CPU กลับลดลง ผู้ดูแลที่ตรวจสองอย่างนี้จะเห็นว่าระบบปกติดี ในจังหวะที่เวลาตอบสนองเพิ่มขึ้นกว่าสองเท่า

05 สิ่งที่ผลทดสอบบอกเราเรื่องการวางระบบ

สิ่งที่เราได้จากการทดสอบชุดนี้ไม่ใช่คำตอบว่าเครื่องต้องใหญ่แค่ไหน แต่เป็นรายการสิ่งที่ควรออกแบบไว้ตั้งแต่แรก เพราะแก้ทีหลังยากกว่ามาก ทุกข้อด้านล่างมาจากสิ่งที่เราเห็นระหว่างทดสอบ ไม่ใช่จากตำรา

06 โครงสร้างที่ใช้ทดสอบ

DIGITALOCEAN · SGP1 NO PUBLIC INBOUND ผู้ใช้งาน งานสำนักงาน Cloudflare ตรวจสิทธิ์ผ่าน Access เชื่อมต่อผ่าน Tunnel Droplet Odoo 19 Community ไม่อัปเดตเวอร์ชันเอง Block Storage ไฟล์แนบของ Odoo Managed PostgreSQL ผู้ให้บริการดูแล · กู้คืนย้อนหลังได้ Spaces ทุกคืน 02:00 น. Offsite Copy คนละบัญชีผู้ใช้ HTTPS Cloudflare Tunnel mount PostgreSQL pg_dump filestore weekly copy
การทดสอบทั้งหมดใช้โครงสร้างนี้ โดยแยก Odoo และ PostgreSQL ออกจากกัน ตัวเลขทุกตัวในหน้านี้จึงมาจากโครงสร้างเดียวกัน ไม่ได้ผสมผลจากเครื่องคนละแบบ ส่วนการสำรองข้อมูลและเส้นทางเข้าระบบ ใส่ไว้ให้เห็นภาพรวม ไม่ได้เป็นตัวแปรในการวัดความเร็ว

07 ค่าโครงสร้างพื้นฐานที่คาดไว้

ตัวเลขในตารางแรกเป็นดอลลาร์ต่อเดือน คิดจากเครื่องที่เปิดทิ้งไว้ตลอดเดือนโดยไม่ผูกสัญญาล่วงหน้า ทุกรายการอ้างอิงโซนสิงคโปร์ และเทียบกันด้วยสเปกชุดเดียวกับที่ใช้ทดสอบจริง ราคาของ GCP รวมส่วนลดการใช้งานต่อเนื่องที่ระบบให้อัตโนมัติแล้ว ส่วน Azure ไม่มีส่วนลดลักษณะนี้ ค่าไอพีและปริมาณข้อมูลขาออกของ DigitalOcean เป็นศูนย์เพราะรวมอยู่ในค่าเครื่องแล้ว

รายการสเปกDigitalOceanGCPAzure
เครื่อง Odoo4 vCPU / 8 GB4884147
ฐานข้อมูลแบบจัดการให้2 vCPU / 4 GB รวมพื้นที่ 100 GB6013790
พื้นที่ดิสก์100 GB101114
พื้นที่เก็บไฟล์สำรอง250 GB555
Cloudflareไม่เกิน 50 บัญชี ใช้ได้ฟรี000
ไอพีและข้อมูลขาออกประมาณ 100 GB ต่อเดือน0154
อีเมลออกตามปริมาณที่ส่ง111
รวมเฉพาะระบบจริง124253261
เครื่องทดสอบแยก2 vCPU / 4 GB ไว้ซ้อมก่อนแตะระบบจริง244074
รวมทั้งหมด148293335

ตารางถัดไปเรียงจากถูกไปแพง เพื่อให้เห็นว่าทางเลือกไหนอยู่ตรงไหน รายการที่เขียนว่าติดตั้งฐานข้อมูลบนเครื่องเอง หมายถึงไม่ใช้บริการฐานข้อมูลแบบจัดการให้ แต่ลง PostgreSQL บนเครื่องอีกตัวหนึ่งแทน

ทางเลือกบาทต่อปีเงื่อนไข
AWS แบบจ่ายล่วงหน้า 1 ปี48,000ผูกพันสัญญา 12 เดือน
โครงสร้างที่ทดสอบ เฉพาะระบบจริง52,000ไม่ผูกพัน
GCP ติดตั้งฐานข้อมูลบนเครื่องเอง จ่ายล่วงหน้า 1 ปี58,000ผูกพันสัญญา 12 เดือน
AWS แบบจ่ายตามใช้65,000ไม่ผูกพัน
GCP ติดตั้งฐานข้อมูลบนเครื่องเอง71,000ไม่ผูกพัน
Azure ติดตั้งฐานข้อมูลบนเครื่องเอง จ่ายล่วงหน้า 1 ปี72,000ผูกพันสัญญา 12 เดือน
GCP ใช้ฐานข้อมูลแบบจัดการให้106,000ไม่ผูกพัน
Azure ใช้ฐานข้อมูลแบบจัดการให้110,000ไม่ผูกพัน
Azure ติดตั้งฐานข้อมูลบนเครื่องเอง113,000ไม่ผูกพัน

สิ่งที่ทำให้ราคาต่างกันมากที่สุดคือฐานข้อมูลแบบจัดการให้ ถ้าเลือกลง PostgreSQL บนเครื่องเอง ค่าใช้จ่ายของ GCP และ Azure จะลดลงประมาณหนึ่งในสาม แลกกับงานดูแลที่ต้องทำเอง ผู้ให้บริการรายใหญ่ทั้งสองเจ้าไม่ได้ถูกกว่าโครงสร้างที่ทดสอบ ถ้าจะเลือกใช้ เหตุผลควรมาจากเรื่องสิทธิ์ในการควบคุมระบบ การสำรองและกู้คืนข้อมูล และการเชื่อมต่อกับระบบอื่น ไม่ใช่เรื่องราคา

คำนวณที่ 35 บาทต่อดอลลาร์ ตัวเลขชุดนี้เป็นค่าโครงสร้างพื้นฐานของเครื่องที่ใช้ทดสอบเท่านั้น ไม่ใช่ราคาทั้งโครงการ เพราะยังไม่รวมค่าติดตั้ง ค่าย้ายข้อมูล ค่าพัฒนาเพิ่มเติม และค่าดูแลระบบ การทดสอบทั้งหมดใช้ Odoo Community จึงไม่มีค่าลิขสิทธิ์ Odoo Enterprise อยู่ในตัวเลขนี้ ราคาผู้ให้บริการอ้างอิงจากราคาประกาศ ณ ช่วงที่ทดสอบ

08 สิ่งที่การทดสอบนี้ยังไม่ได้ตอบ

ข้อจำกัดต่อไปนี้มีผลต่อการตีความผลทดสอบ และต่อขนาดเครื่องที่ควรเลือก