ปรับขนาดเป็น 5M RPM
![](https://post.nghiatu.com/assets/images/m/max/724/1*tsDdujggeiNmG2zf_YRMUQ.png)
ใน Trendyol เรามีหน้าที่รับผิดชอบในการให้บริการหน้าเนื้อหาและข้อมูล เรายังให้บริการข้อมูลเนื้อหาเป็นกลุ่มสำหรับรายการโปรด คอลเลกชัน หรือแม้แต่หน้าชำระเงิน ในไม่ช้า เราจะมีส่วนร่วมเมื่อใดก็ตามที่คุณเห็นหน้าจอด้านล่าง
![](https://post.nghiatu.com/assets/images/m/max/724/1*HQ4LyWILwUeUcbaFsUZiCw.png)
![](https://post.nghiatu.com/assets/images/m/max/724/1*tFhruZ8W0lcM4AE9ffvGAQ.png)
ความต้องการหรือภาระที่คาดหวังของเราคืออะไร?
ตามที่คาดไว้ เรามักจะได้รับการเข้าชมมากขึ้นในช่วงเทศกาลช้อปปิ้งหรือช่วงกิจกรรม/ส่วนลด ในขณะที่เราได้รับประมาณ 1M rpm (คำขอต่อนาที) ในวันปกติ โหลดจะเพิ่มเป็นประมาณ 3M rpm ในช่วงเวลาที่มีงานยุ่ง ในช่วงเวลานั้นเราไม่สามารถปฏิบัติตามข้อกำหนดได้อย่างแม่นยำ เวลาตอบสนองของเราเพิ่มขึ้นเป็นสองเท่าจากปกติ และเรายังมีระยะหมดเวลามากกว่าที่เราจะเพิกเฉยได้
เป้าหมายและความคาดหวังต่อไปของเราคือทำความเร็วให้ได้อย่างน้อย 8 ล้านรอบต่อนาทีด้วยทรัพยากรเท่าเดิม ปัญหาก็คือเราไม่สามารถปรับขนาดได้มากเท่าที่ต้องการ นับประสาอะไรกับสิ่งที่เราคาดหวังต่อไป
ใครชอบความท้าทายบ้าง? ใช่เราแน่นอน :)
![](https://post.nghiatu.com/assets/images/m/max/724/1*LHLZdQRpBoW5dQKh8VRchg.jpeg)
เราพบสาเหตุของปัญหาได้อย่างไร?
ดังนั้นเราจึงทำโปรไฟล์เพื่อทำความเข้าใจว่าโค้ดส่วนใดใช้เวลามากกว่าและใช้ทรัพยากรมากกว่ากัน อันดับแรก เราใช้ Java profiler เพื่อจำกัดส่วนที่จะติดตามให้แคบลง หลังจากนั้น เราได้เพิ่มร่องรอยของ New Relic แบบกำหนดเองในโค้ด เมื่อเราดูผลลัพธ์ เราพบว่าโค้ดบางส่วนใช้เวลาและทรัพยากรมากที่สุด
ส่วนนั้นเป็นตรรกะการแปลงเพื่อแปลงเอกสาร Couchbase เป็นข้อมูลที่เราต้องการเพื่อดำเนินตรรกะทางธุรกิจและให้บริการเป็นกลุ่ม มันทำงานสำหรับทุกคำขอและทุกเนื้อหา เราเริ่มคิดว่าเราจะทำตรรกะการแปลงนี้แบบอะซิงโครนัสได้หรือไม่ เราสามารถเรียกใช้ตรรกะนี้ครั้งเดียวสำหรับทุกเนื้อหา ส่วนใหญ่ คำตอบคือ ใช่!
แค่ทำให้ดีที่สุดเท่านั้นยังไม่พอ คุณต้องรู้ว่าต้องทำอะไรแล้วทำให้ดีที่สุด — W. Edwards Deming
![](https://post.nghiatu.com/assets/images/m/max/724/1*nnV0tWooRY_DQmyzEpwEyA.png)
เราสามารถจัดการข้อมูลแบบอะซิงโครนัสได้หรือไม่?
เรากำลังใช้ Couchbase เป็นแหล่งข้อมูล เมื่อเราดูว่าเราสามารถแปลงข้อมูล Couchbase แบบอะซิงโครนัสได้อย่างไร เราพบว่า Couchbase มีโปรโตคอลการเปลี่ยนแปลงฐานข้อมูล (DCP) DCP สามารถให้สตรีมสำหรับการกลายพันธุ์แก่เราได้ ดังนั้นเราจึงสามารถฟังจากแหล่งข้อมูลเก่า ทำการแปลง async และเขียนไปยังแหล่งข้อมูลใหม่ของเรา คุณสามารถตรวจสอบบทความของAhmet Hatipogluหากคุณสงสัยเกี่ยวกับรายละเอียด
ตอนนี้ ถึงเวลาที่จะพิจารณาว่าเราสามารถเพิ่มประสิทธิภาพข้อมูลได้หรือไม่
เราต้องการข้อมูลทั้งหมดหรือไม่?
เราใช้โมเดลข้อมูลเดียวกันสำหรับหน้าเนื้อหาและคำขอจำนวนมาก สำหรับคำขอจำนวนมาก ลูกค้าหลายรายต้องการข้อมูลที่แตกต่างกัน ดังนั้นเราจึงต้องการการวิเคราะห์เพื่อทำความเข้าใจว่าใครต้องการส่วนใดของข้อมูล เราทำการวิเคราะห์อย่างครอบคลุมกับลูกค้าของเราทั้งหมดด้วยกัน
หลังจากการวิเคราะห์ เราตระหนักว่าเราต้องการข้อมูลเพียงบางส่วน และลูกค้าของเราเกือบทั้งหมดต้องการข้อมูลส่วนเดียวกันเกือบทั้งหมด แต่เราไม่สามารถแตะต้องสคีมาได้เนื่องจากลูกค้าบางรายของเราใช้แหล่งข้อมูลเดียวกันโดยตรง เราผูกพันกันแน่นแฟ้น โดยสรุปแล้ว การแยกแหล่งข้อมูลอาจเป็นขั้นตอนหนึ่งในการแก้ปัญหา
ตอนนี้เรามีอะไรบ้าง?
บริการที่รับฟังการเปลี่ยนแปลงจากแหล่งข้อมูลเนื้อหาจะทำการแปลงจำนวนมากและเขียนไปยังแหล่งข้อมูลใหม่ และเรารู้จากการวิเคราะห์ว่าเราต้องการข้อมูลเพียงบางส่วนเท่านั้น ดังนั้นเราจึงสามารถละเว้นส่วนที่ไม่จำเป็นทั้งหมดในขณะที่ทำการแปลง
คุณพร้อมไหม? เราบันทึกข้อมูลได้ 77% (1.28TB) ค่อยยังชั่ว!
![](https://post.nghiatu.com/assets/images/m/max/724/1*tX9EQKhJ7wktFuWB3Q5Esg.png)
อะไรตอนนี้?
เราต้องการบางอย่างที่ใช้ข้อมูลที่เราเตรียมไว้ เราต้องการแยกความต้องการเนื้อหาจำนวนมากออกจากกัน และความต้องการหน้ารายละเอียดสินค้าเพียงเพราะลูกค้าของพวกเขา ความต้องการด้านขนาด และชุดกฎทางธุรกิจแตกต่างกัน ได้เวลาเขียนบริการใหม่แล้ว
ทำอะไรได้ไม่ต่างกัน?
บางทีเทคโนโลยีที่เราใช้ บริการเก่าใช้ Java 8 และ Spring boot เรามีประสบการณ์ที่มั่นคงกับQuarkus บางทีเราอาจลดการใช้ทรัพยากรและเวลาบูตลงเพื่อให้สามารถปรับขนาดได้มากขึ้น หรือเราใช้Fluxเพื่อรับเอกสารจาก Couchbase และบางทีเราอาจใช้ CompletableFuture เพื่อเปลี่ยนแปลง หลังจากระบุตัวเลือกของเราแล้ว เราได้พัฒนาแอปพลิเคชัน POC จำนวนมากและทำการทดสอบโหลดจำนวนมาก แต่ผลลัพธ์น่าจะดีกว่านี้ อย่างน้อยก็ไม่ใช่ความพยายามที่เราต้องการ การวิจัยควรดำเนินต่อไป
อย่างไรก็ตาม ฉันเป็นโกเฟอร์มาสี่ปีแล้ว ฉันเชื่อว่าเราสามารถรับเอกสารได้อย่างมีประสิทธิภาพด้วย goroutines ควบคู่กันไป ดังนั้นฉันจึงอยากลองทำ จากนั้น ฉันดู Couchbase Go SDK อย่างเป็นทางการ ซึ่งมีคุณสมบัติ "รับเอกสารจำนวนมาก" มันเยี่ยมมาก! ความต้องการเหมาะสมกับการใช้ Go และฉันต้องการลองทั้งสองตัวเลือก
ฉันรันการทดสอบโหลดทั้ง goroutines แบบขนานและคุณลักษณะแบบกลุ่ม เวลาตอบสนองและการใช้ทรัพยากรได้รับการปรับปรุงอย่างมีนัยสำคัญสำหรับทั้งคู่ คุณลักษณะแบบกลุ่มดีกว่าการใช้งานแบบธรรมดาของเรา แต่มีบางอย่างดับลง การใช้งานเครือข่ายเพิ่มขึ้นสี่เท่า เราสามารถกำหนดค่าให้กับการเชื่อมต่อ Couchbase ใน Java SDK ที่เปิดใช้งานการบีบอัด แต่ Go SDK ไม่มีการกำหนดค่าการบีบอัดในตัวเลือกการกำหนดค่าคลัสเตอร์ ดังนั้นฉันจึงพลาดการกำหนดค่าตามนั้น น่าเสียดายที่คุณลักษณะการบีบอัดไม่สามารถควบคุมได้ผ่าน Couchbase Go SDK ซึ่งแตกต่างจาก Couchbase Java SDK ดังนั้นฉันจึงตรวจสอบโค้ดของมัน ทำการดีบั๊กที่เจ็บปวด และค้นพบว่าการบีบอัดสามารถควบคุมได้ผ่านตัวแปรเคียวรีที่ส่วนท้ายของสตริงการเชื่อมต่อ
couchbase://{HOST_HERE}?compression=true
- เรามีการใช้ RAM เพิ่มขึ้นอย่างมาก และการใช้หน่วยความจำลดลงจาก800MBเป็น60MBต่อพ็อด
- เวลาตอบสนองหายไปครึ่งหนึ่ง 10msถึง5ms _ และมีความเสถียรมากกว่าเมื่อเทียบกับปริมาณงานสูง
- การใช้งาน CPU ลดลงอย่างมาก เพื่อให้ถึง 5M ด้วยบริการเก่า เราต้องการพ็อดเพิ่มเติม นี่จะเป็นการเปรียบเทียบการใช้งาน CPU ทั้งหมด ตอนนี้เป็น130 คอร์แทนที่จะเป็น300
- ขนาดเอกสารรวมตอนนี้น้อยกว่าหนึ่งในสี่ของเมื่อก่อน จาก1.67TBเหลือเพียง386GB
- โดยปกติแล้ว โหลดเครือข่ายจะต่ำกว่ามาก
- เวลาบูตตอนนี้คือ85 มิลลิวินาทีแทนที่จะเป็น12 วินาที !
![](https://post.nghiatu.com/assets/images/m/max/724/1*1tw-Qd2VIhKBdVFLp0TskA.png)
ขอบคุณEmre Odabasสำหรับการสนับสนุนและให้กำลังใจในการเขียนบทความนี้