← กลับไปหน้าบทความ
เอเจนซี่

ลูกค้ารายใหญ่ยิงแคมเปญพร้อมกันจนคิวรวมอืด ลูกค้ารายเล็กใน Queue เดียวกันพลอยส่ง Event ช้าไปด้วย ออกแบบ Multi-tenant ให้ไม่แย่งกันเอง

ทีมบรรณาธิการ linli07 ก.ย. 07:43อัปเดต 07 ก.ย. 07:43อ่าน 3 นาที
ลูกค้ารายใหญ่ยิงแคมเปญพร้อมกันจนคิวรวมอืด ลูกค้ารายเล็กใน Queue เดียวกันพลอยส่ง Event ช้าไปด้วย ออกแบบ Multi-tenant ให้ไม่แย่งกันเอง
บทความนี้จัดทำเพื่อความรู้ ชื่อธุรกิจ ตัวเลข หรือบทสนทนาที่ไม่มีแหล่งอ้างอิงกำกับเป็นกรณีตัวอย่างเพื่ออธิบายแนวคิด ดูรายละเอียดที่ นโยบายกองบรรณาธิการ

สรุปสั้น ๆ

เมื่อเอเจนซี่ใช้โครงสร้างพื้นฐานเดียวกันดูแล CAPI ให้ลูกค้าหลายราย การใช้ queue รวมเดียวกันทุกลูกค้าทำให้ลูกค้ารายที่มี traffic สูงสามารถแย่งทรัพยากรจนลูกค้ารายเล็กได้รับผลกระทบไปด้วย ทั้งที่ไม่มีปัญหาอะไรกับระบบของตัวเองเลย การออกแบบ isolation ระดับ tenant ตั้งแต่ต้นคือทางแก้ที่ป้องกันปัญหานี้อย่างยั่งยืน

เอเจนซี่แห่งหนึ่งที่ผมช่วยดูระบบ ดูแล CAPI ให้ลูกค้าเก้ารายบนเซิร์ฟเวอร์และ queue เดียวกัน วันหนึ่งลูกค้ารายใหญ่ที่สุดยิงแคมเปญลดราคาประจำปีจนมี event เข้าคิวเป็นหลักหมื่นรายการภายในไม่กี่ชั่วโมง ผลคือลูกค้ารายเล็กอีกแปดรายที่ไม่ได้ทำแคมเปญอะไรพิเศษเลย เจอปัญหา event ของตัวเองส่งล่าช้าไปหลายสิบนาทีเช่นกัน เพราะทุก event ไม่ว่าจะเป็นของลูกค้ารายไหนก็เข้าคิวเดียวกันแล้วรอประมวลผลตามลำดับที่เข้ามาก่อนหลัง

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

ปัญหานี้เรียกว่า noisy neighbor effect ซึ่งเป็นปัญหาคลาสสิกของระบบที่ใช้ทรัพยากรร่วมกันโดยไม่มีการแบ่งแยกที่ชัดเจน บทความนี้จะเจาะแนวทางออกแบบ multi-tenant isolation ที่ทำให้ลูกค้าแต่ละรายของเอเจนซี่ไม่กระทบกันเอง โดยไม่จำเป็นต้องแยกโครงสร้างพื้นฐานทั้งหมดออกจากกันให้สิ้นเปลืองต้นทุนเกินจำเป็น

ทำไม queue รวมเดียวกันถึงเป็นจุดอ่อนของระบบ multi-client

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

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

ระดับของ isolation ที่เลือกใช้ได้ตามขนาดและงบประมาณของเอเจนซี่

ระดับ isolationวิธีทำเหมาะกับ
Priority weight ในคิวเดียวกันกำหนดน้ำหนักหรือโควตาต่อ tenant ในคิวเดียวกัน ไม่ให้ tenant ใด tenant หนึ่งใช้ throughput เกินสัดส่วนที่กำหนดเอเจนซี่ขนาดกลางที่ยังไม่พร้อมลงทุนแยกโครงสร้างพื้นฐาน
Queue แยกต่อ tenant บน infrastructure เดียวกันสร้างคิวแยกสำหรับลูกค้าแต่ละราย แต่ยังรันบนเซิร์ฟเวอร์ชุดเดียวกันเอเจนซี่ที่มีลูกค้าหลากหลายขนาด ต้องการความชัดเจนในการแยกปัญหาต่อราย
แยก infrastructure เต็มรูปแบบต่อลูกค้าแต่ละลูกค้ามีเซิร์ฟเวอร์ ฐานข้อมูล และ queue เป็นของตัวเองทั้งหมดลูกค้ารายใหญ่ที่มีข้อกำหนดเฉพาะด้าน security หรือ compliance สูง

แนวทางเริ่มต้นที่คุ้มค่าที่สุด: แยก queue ต่อ tenant โดยไม่ต้องแยก infrastructure ทั้งหมด

สำหรับเอเจนซี่ส่วนใหญ่ที่ยังไม่มีงบประมาณพอจะแยก infrastructure เต็มรูปแบบต่อลูกค้าทุกราย การแยก queue ต่อ tenant บนโครงสร้างพื้นฐานเดียวกันเป็นจุดสมดุลที่คุ้มค่าที่สุด เพราะแก้ปัญหา noisy neighbor ได้เกือบทั้งหมดโดยไม่ต้องเพิ่มต้นทุนมากเท่าการแยกเซิร์ฟเวอร์ทั้งชุด

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

อะไรบ้างที่ยังคง ‘แชร์กัน’ แม้จะแยก queue แล้ว และต้องระวังยังไง

การแยก queue ต่อ tenant ช่วยแก้ปัญหาการแย่งลำดับคิวได้ แต่ทรัพยากรระดับล่าง เช่น CPU และ network bandwidth ของเซิร์ฟเวอร์ยังคงถูกใช้ร่วมกันอยู่ดี ถ้าลูกค้ารายใหญ่มี worker ที่ประมวลผลหนักมากจนใช้ CPU เกือบเต็มเครื่อง ลูกค้ารายอื่นก็ยังได้รับผลกระทบทางอ้อมอยู่ดี แม้จะไม่ได้ติดขัดที่ระดับคิวก็ตาม

จุดนี้ต้องอาศัยการตั้ง resource limit ให้แต่ละ tenant ในระดับ infrastructure ด้วย เช่น จำกัดจำนวน worker พร้อมกันสูงสุดต่อ tenant หรือใช้ container ที่กำหนดโควตา CPU และหน่วยความจำแยกตาม tenant ไม่ใช่พึ่งแค่การแยก queue อย่างเดียวแล้วคิดว่าปัญหาหมดไปแล้วทั้งหมด

ทำ dashboard แยกตาม tenant เพื่อตอบลูกค้าได้เร็วเมื่อมีปัญหา

  • แยกกราฟ latency และ error rate ของแต่ละ tenant ไม่ใช่ดูภาพรวมของทั้งระบบรวมกันเป็นเส้นเดียว
  • ตั้งค่าแจ้งเตือนแยกตาม tenant เมื่อ queue ของรายใดรายหนึ่งค้างเกินเกณฑ์ที่กำหนด แทนที่จะรอให้ทุก tenant ค้างพร้อมกันถึงจะแจ้งเตือน
  • เก็บสถิติปริมาณ event ต่อ tenant รายวัน เพื่อคาดการณ์ล่วงหน้าได้ว่าลูกค้ารายไหนมีแนวโน้ม traffic เพิ่มขึ้นจนอาจต้องปรับ resource limit ก่อนถึงวันแคมเปญจริง
  • ทำรายงานสรุปที่อธิบายให้ลูกค้าแต่ละรายเข้าใจได้ว่า ‘ปัญหาของวันนี้เกิดจากอะไร’ อย่างโปร่งใส แทนที่จะตอบกว้าง ๆ ว่าระบบมีปัญหาโดยไม่รู้สาเหตุจริง

รับลูกค้ารายใหม่เข้าระบบ ต้องเผื่อพื้นที่ isolation ไว้ตั้งแต่วันแรกไหม

คำถามที่เอเจนซี่มักเจอเมื่อรับลูกค้ารายใหม่เข้าระบบคือ ควรสร้าง queue และ resource limit แยกให้ตั้งแต่วันแรกเลยหรือรอดูขนาด traffic จริงก่อนแล้วค่อยจัดสรร ในทางปฏิบัติการเผื่อพื้นที่ isolation ไว้ตั้งแต่ต้นทำได้ง่ายกว่าการย้อนกลับไปแยกทีหลังเมื่อลูกค้ารายนั้นเติบโตจนกระทบลูกค้ารายอื่นแล้ว เพราะการย้ายข้อมูลและ configuration ของ tenant ที่ใช้งานอยู่แล้วมีความเสี่ยงมากกว่าการตั้งค่าตั้งแต่ยังไม่มี traffic

แนวทางที่สมดุลคือกำหนด resource limit เริ่มต้นตามระดับมาตรฐานสำหรับลูกค้าใหม่ทุกราย โดยอ้างอิงจากขนาดธุรกิจและแผนแคมเปญที่แจ้งไว้ตอนเริ่มสัญญา แล้วปรับเพิ่มลดตามข้อมูล traffic จริงเมื่อผ่านไปสักระยะ วิธีนี้ทำให้ลูกค้าใหม่ไม่กระทบลูกค้าเดิมตั้งแต่วันแรก โดยไม่ต้องเดาขนาด resource ที่แม่นยำเป๊ะตั้งแต่ก่อนเริ่มใช้งานจริง

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

เมื่อลูกค้ายกเลิกสัญญา ต้องคืนทรัพยากรที่เคยจัดสรรไว้ให้เรียบร้อยด้วย

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

การมีขั้นตอน offboarding ที่ชัดเจนคู่กับขั้นตอน onboarding จึงช่วยให้การบริหารจัดการ resource ของเอเจนซี่มีความเป็นระเบียบในระยะยาว ทั้งในแง่ต้นทุนโครงสร้างพื้นฐานที่ไม่บวมขึ้นโดยไม่จำเป็น และในแง่ความปลอดภัยที่ credential หรือสิทธิ์การเข้าถึงของลูกค้าที่ยกเลิกไปแล้วจะไม่ถูกทิ้งค้างไว้ให้เป็นความเสี่ยง ควรกำหนดเป็นรายการตรวจสอบมาตรฐานที่ทีมต้องทำให้ครบทุกครั้งเมื่อปิดบัญชีลูกค้ารายใดรายหนึ่ง แทนที่จะพึ่งความจำของคนใดคนหนึ่งว่าต้องคืน resource อะไรบ้าง

สรุป

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

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

  • queue รวมเดียวกันทำให้ลูกค้ารายใหญ่ที่มี traffic สูงแย่งลำดับคิวจากลูกค้ารายเล็กได้ แม้ระบบของลูกค้ารายเล็กจะไม่มีปัญหาอะไรเลย
  • แยก queue ต่อ tenant บน infrastructure เดียวกันคือจุดสมดุลที่คุ้มค่าที่สุดสำหรับเอเจนซี่ส่วนใหญ่
  • ต้องมี monitoring และ resource limit แยกตาม tenant ด้วย ไม่ใช่แค่แยก queue อย่างเดียวแล้วคิดว่าปัญหาหมดไปทั้งหมด

คำถามที่พบบ่อย

เอเจนซี่ที่มีลูกค้าแค่สองสามรายและขนาดใกล้เคียงกัน ยังต้องกังวลเรื่องนี้ไหม

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

การแยก queue ต่อ tenant ทำให้ต้นทุน infrastructure เพิ่มขึ้นมากไหม

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

ลูกค้ารายไหนควรถูกแยก infrastructure เต็มรูปแบบ ไม่ใช่แค่แยก queue

มักเป็นลูกค้าที่มีข้อกำหนดเฉพาะด้านความปลอดภัยหรือการแยกข้อมูลที่เข้มงวดกว่าปกติ เช่น องค์กรขนาดใหญ่ที่มีนโยบาย procurement หรือ security review ของตัวเอง หรือลูกค้าที่มี traffic สูงมากจนกระทบลูกค้ารายอื่นแม้จะแยก queue แล้วก็ตาม

ถ้าไม่มีเวลาสร้างระบบ isolation ตอนนี้ ควรทำอะไรก่อนเป็นอันดับแรก

เริ่มจากการมี monitoring แยกตาม tenant ก่อนเป็นอันดับแรก แม้ยังไม่ได้แยก queue จริง เพราะอย่างน้อยจะช่วยให้ทีมรู้เร็วขึ้นว่าปัญหาความล่าช้ามาจาก tenant ไหน ซึ่งช่วยลดเวลาในการวิเคราะห์ปัญหาได้มากแม้จะยังไม่ได้แก้ไขสถาปัตยกรรมหลัก

priority weight กับการแยก queue เต็มรูปแบบ อันไหนควรเลือกก่อน

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

การแยก tenant กระทบกับการดูแล credential ของแต่ละลูกค้าด้วยไหม

เป็นคนละเรื่องกันในทางเทคนิคแต่เกี่ยวข้องกันในทางปฏิบัติ เพราะเอเจนซี่ที่แยก tenant ดีมักมีระบบดูแล credential แยกตามลูกค้าไปพร้อมกันด้วย ซึ่งเป็นหัวข้อที่ควรออกแบบควบคู่กันตั้งแต่ต้น

พิสูจน์ผลงานแอดเข้า LINE ให้ลูกค้าเห็นถึงยอดขาย

ดูแลลูกค้าหลายราย แต่ละรายมี LINE OA ของตัวเอง — linli แยกโปรเจกต์ แยก Tracking และส่ง Conversion กลับแพลตฟอร์มของแต่ละลูกค้า เริ่มฟรี 14 วัน

ทดลองใช้ฟรี 14 วัน

บทความที่เกี่ยวข้อง

โทเคนของลูกค้ารายหนึ่งหมดอายุกลางดึก แล้ว Event ของลูกค้าทุกคนในระบบเดียวกันหยุดส่งพร้อมกันหมด วาง Credential Rotation ให้พังแยกราย ไม่ใช่พังยกล็อต

โทเคนของลูกค้ารายหนึ่งหมดอายุกลางดึก แล้ว Event ของลูกค้าทุกคนในระบบเดียวกันหยุดส่งพร้อมกันหมด วาง Credential Rotation ให้พังแยกราย ไม่ใช่พังยกล็อต

หลาย codebase ของเอเจนซี่เก็บ credential ของลูกค้าไว้ในไฟล์ตั้งค่ากลางที่โหลดพร้อมกันตอนเริ่มระบบ ถ้า token ของลูกค้ารายหนึ่งหมดอายุหรือผิดพลาด ระบบทั้งชุดอาจล่มตามไปด้วย บทความนี้เจาะการออกแบบ credential lifecycle ที่พังแยกราย
เอเจนซี่ดูแลลูกค้า 8 เจ้า แต่ละเจ้าอยากได้โมเดล attribution คนละแบบ จะวางมาตรฐานให้เทียบผลงานกันได้ยังไง

เอเจนซี่ดูแลลูกค้า 8 เจ้า แต่ละเจ้าอยากได้โมเดล attribution คนละแบบ จะวางมาตรฐานให้เทียบผลงานกันได้ยังไง

ลูกค้าคลินิกอยากดู Last-Click ลูกค้าอสังหาฯ อยากดู Time-Decay ลูกค้าอีคอมเมิร์ซอยากดู Linear เอเจนซี่ที่ดูแลหลายบัญชีพร้อมกันจะวางมาตรฐานการรายงานยังไงให้ทั้งตอบโจทย์ลูกค้าแต่ละเจ้าและเปรียบเทียบผลงานทีมได้เอง
เอเจนซี่ที่ดูแลหลายแบรนด์พร้อมกัน จะจัดการข้อมูลลูกค้าแต่ละเจ้าใน LINE ให้แยกกันชัดเจนได้อย่างไร

เอเจนซี่ที่ดูแลหลายแบรนด์พร้อมกัน จะจัดการข้อมูลลูกค้าแต่ละเจ้าใน LINE ให้แยกกันชัดเจนได้อย่างไร

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