Building Block ของแอปพลิเคชันแบบกระจาย การประมาณครั้งที่สอง

การประกาศ

เพื่อนร่วมงาน ในช่วงกลางฤดูร้อน ฉันวางแผนที่จะเผยแพร่บทความอีกชุดเกี่ยวกับการออกแบบระบบคิว: “การทดลอง VTrade” - ความพยายามในการเขียนกรอบการทำงานสำหรับระบบการซื้อขาย ซีรีส์นี้จะกล่าวถึงทฤษฎีและการปฏิบัติในการสร้างการแลกเปลี่ยน การประมูล และการจัดเก็บ ในตอนท้ายของบทความ ฉันขอเชิญคุณลงคะแนนในหัวข้อที่คุณสนใจมากที่สุด

Building Block ของแอปพลิเคชันแบบกระจาย การประมาณครั้งที่สอง

นี่เป็นบทความสุดท้ายในชุดเกี่ยวกับแอปพลิเคชันแบบโต้ตอบแบบกระจายใน Erlang/Elixir ใน บทความแรก คุณสามารถค้นหารากฐานทางทฤษฎีของสถาปัตยกรรมเชิงโต้ตอบได้ บทความที่สอง แสดงให้เห็นรูปแบบพื้นฐานและกลไกในการสร้างระบบดังกล่าว

วันนี้เราจะหยิบยกประเด็นการพัฒนาฐานโค้ดและโครงการโดยทั่วไป

องค์กรบริการ

ในชีวิตจริง เมื่อพัฒนาบริการ คุณมักจะต้องรวมรูปแบบการโต้ตอบหลายรูปแบบไว้ในคอนโทรลเลอร์ตัวเดียว ตัวอย่างเช่น บริการผู้ใช้ซึ่งแก้ปัญหาในการจัดการโปรไฟล์ผู้ใช้โครงการ จะต้องตอบสนองต่อคำขอ req-resp และรายงานการอัปเดตโปรไฟล์ผ่าน pub-sub กรณีนี้ค่อนข้างง่าย: เบื้องหลังการส่งข้อความจะมีตัวควบคุมหนึ่งตัวที่ใช้ตรรกะของบริการและเผยแพร่การอัปเดต

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

  1. ตอนนี้บริการควรประมวลผลคำขอบน 5 โหนดคลัสเตอร์
  2. สามารถทำงานประมวลผลเบื้องหลังได้
  3. และยังสามารถจัดการรายการสมัครสมาชิกสำหรับการอัพเดตโปรไฟล์แบบไดนามิกได้

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

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

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

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

เป็นผลให้การสลายตัวของปัญหาแสดงให้เห็นว่าเพื่อให้เป็นไปตามข้อกำหนด เราจำเป็นต้องเปิดตัวบริการ 5 อินสแตนซ์บนโหนดที่แตกต่างกัน และสร้างเอนทิตีเพิ่มเติม - ตัวควบคุม pub-sub ที่รับผิดชอบในการสมัครสมาชิก
หากต้องการเรียกใช้ตัวจัดการ 5 ตัว คุณไม่จำเป็นต้องเปลี่ยนรหัสบริการ การดำเนินการเพิ่มเติมเพียงอย่างเดียวคือการตั้งค่ากฎการปรับสมดุลที่จุดแลกเปลี่ยน ซึ่งเราจะพูดถึงในภายหลัง
นอกจากนี้ยังมีความซับซ้อนเพิ่มเติม: ตัวควบคุม pub-sub และตัวกำหนดเวลางานแบบกำหนดเองจะต้องทำงานในสำเนาเดียว ขอย้ำอีกครั้งว่าบริการส่งข้อความซึ่งเป็นบริการพื้นฐานจะต้องมีกลไกในการเลือกผู้นำ

การเลือกผู้นำ

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

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

หลังจากเริ่มต้นและเชื่อมต่อกับจุดแลกเปลี่ยนแล้ว บริการทั้งหมดจะได้รับข้อความระบบ #'$leader'{exchange = ?EXCHANGE, pid = LeaderPid, servers = Servers}. ถ้า LeaderPid เกิดขึ้นพร้อมกับ pid กระบวนการปัจจุบันก็ได้รับแต่งตั้งให้เป็นผู้นำและรายชื่อ Servers รวมโหนดทั้งหมดและพารามิเตอร์
ในขณะนี้ โหนดใหม่ปรากฏขึ้นและโหนดคลัสเตอร์ที่ทำงานถูกตัดการเชื่อมต่อ ตัวควบคุมบริการทั้งหมดจะได้รับ #'$slave_up'{exchange = ?EXCHANGE, pid = SlavePid, options = SlaveOpts} и #'$slave_down'{exchange = ?EXCHANGE, pid = SlavePid, options = SlaveOpts} ตามลำดับ

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

คนกลาง

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

ตัวอย่างคลาสสิกของการเพิ่มประสิทธิภาพ pub-sub คือแอปพลิเคชันแบบกระจายที่มีแกนธุรกิจที่สร้างเหตุการณ์การอัปเดต เช่น การเปลี่ยนแปลงราคาในตลาด และเลเยอร์การเข้าถึง - เซิร์ฟเวอร์ N ที่ให้ websocket API สำหรับเว็บไคลเอ็นต์
หากคุณตัดสินใจโดยตรง การบริการลูกค้าจะเป็นดังนี้:

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

สมมติว่าเรามีสมาชิก 50000 รายในหัวข้อ "ข่าว" สมาชิกจะถูกกระจายอย่างเท่าเทียมกันใน 5 เซิร์ฟเวอร์ ด้วยเหตุนี้ การอัปเดตแต่ละครั้งที่มาถึงจุดแลกเปลี่ยน จะถูกจำลองแบบ 50000 ครั้ง: 10000 ครั้งในแต่ละเซิร์ฟเวอร์ ตามจำนวนสมาชิกในการอัปเดต ไม่ใช่แผนการที่มีประสิทธิภาพมากนักใช่ไหม?
เพื่อปรับปรุงสถานการณ์ ขอแนะนำพร็อกซีที่มีชื่อเดียวกับจุดแลกเปลี่ยน ผู้รับจดทะเบียนชื่อสากลจะต้องสามารถส่งคืนกระบวนการที่ใกล้เคียงที่สุดตามชื่อได้ ซึ่งเป็นสิ่งสำคัญ

มาเปิดใช้พร็อกซีนี้บนเซิร์ฟเวอร์เลเยอร์การเข้าถึง และกระบวนการทั้งหมดของเราที่ให้บริการ websocket api จะสมัครสมาชิก ไม่ใช่จุดแลกเปลี่ยน pub-sub ดั้งเดิมในเคอร์เนล พร็อกซีสมัครสมาชิกแกนหลักเฉพาะในกรณีของการสมัครสมาชิกที่ไม่ซ้ำกันและทำซ้ำข้อความขาเข้าไปยังสมาชิกทั้งหมด
ด้วยเหตุนี้ ข้อความ 5 ข้อความจะถูกส่งระหว่างเคอร์เนลและเซิร์ฟเวอร์การเข้าถึง แทนที่จะเป็น 50000 ข้อความ

การกำหนดเส้นทางและความสมดุล

ความต้องการ-Resp

ในการใช้งานการรับส่งข้อความในปัจจุบัน มี 7 กลยุทธ์ในการกระจายคำขอ:

  • default. คำขอจะถูกส่งไปยังผู้ควบคุมทั้งหมด
  • round-robin. คำขอจะถูกแจกแจงและกระจายตามรอบระหว่างตัวควบคุม
  • consensus. ผู้ควบคุมที่ให้บริการจะแบ่งออกเป็นผู้นำและทาส คำขอจะถูกส่งไปยังผู้นำเท่านั้น
  • consensus & round-robin. กลุ่มมีผู้นำ แต่มีการกระจายคำขอไปยังสมาชิกทุกคน
  • sticky. ฟังก์ชันแฮชได้รับการคำนวณและกำหนดให้กับตัวจัดการเฉพาะ คำขอครั้งต่อไปที่มีลายเซ็นนี้จะถูกส่งไปยังตัวจัดการคนเดียวกัน
  • sticky-fun. เมื่อเริ่มต้นจุดแลกเปลี่ยน ฟังก์ชันการคำนวณแฮชสำหรับ sticky สมดุล
  • fun. เช่นเดียวกับ Sticky-Fun มีเพียงคุณเท่านั้นที่สามารถเปลี่ยนเส้นทาง ปฏิเสธ หรือประมวลผลล่วงหน้าเพิ่มเติมได้

กลยุทธ์การกระจายจะถูกตั้งค่าเมื่อมีการเตรียมใช้งานจุดแลกเปลี่ยน

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

  • แท็กการเชื่อมต่อ ช่วยให้คุณเข้าใจว่าเหตุการณ์เกิดขึ้นจากความเชื่อมโยงใด ใช้เมื่อกระบวนการควบคุมเชื่อมต่อกับจุดแลกเปลี่ยนเดียวกัน แต่มีคีย์เส้นทางต่างกัน
  • ป้ายบริการ ช่วยให้คุณสามารถรวมตัวจัดการเป็นกลุ่มสำหรับบริการเดียว และขยายความสามารถในการกำหนดเส้นทางและการปรับสมดุล สำหรับรูปแบบ req-resp การกำหนดเส้นทางเป็นแบบเส้นตรง เราส่งคำขอไปยังจุดแลกเปลี่ยน จากนั้นจะส่งต่อไปยังบริการ แต่ถ้าเราจำเป็นต้องแบ่งตัวจัดการออกเป็นกลุ่มเชิงตรรกะ การแยกจะเสร็จสิ้นโดยใช้แท็ก เมื่อระบุแท็ก คำขอจะถูกส่งไปยังกลุ่มคอนโทรลเลอร์เฉพาะ
  • ขอแท็ก. ช่วยให้คุณแยกแยะระหว่างคำตอบได้ เนื่องจากระบบของเราเป็นแบบอะซิงโครนัส เพื่อประมวลผลการตอบสนองของบริการ เราจึงต้องระบุ RequestTag เมื่อส่งคำขอได้ จากนั้นเราจะสามารถเข้าใจคำตอบที่คำขอมาถึงเรา

ผับย่อย

สำหรับ pub-sub ทุกอย่างจะง่ายกว่าเล็กน้อย เรามีจุดแลกเปลี่ยนในการเผยแพร่ข้อความ จุดแลกเปลี่ยนจะกระจายข้อความระหว่างสมาชิกที่สมัครรับรหัสเส้นทางที่พวกเขาต้องการ (เราสามารถพูดได้ว่าสิ่งนี้คล้ายคลึงกับหัวข้อ)

ความสามารถในการปรับขนาดและความทนทานต่อข้อผิดพลาด

ความสามารถในการปรับขนาดของระบบโดยรวมขึ้นอยู่กับระดับความสามารถในการปรับขนาดของเลเยอร์และส่วนประกอบของระบบ:

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

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

การจอง

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

ในโปรเจ็กต์ของฉัน ฉันใช้โหนดเพิ่มเติมที่รับภาระในกรณีที่เกิดการล้ม Erlang มีการใช้งานโหมดกระจายมาตรฐานสำหรับแอปพลิเคชัน OTP โหมดกระจายจะทำการกู้คืนในกรณีที่เกิดความล้มเหลวโดยการเปิดแอปพลิเคชันที่ล้มเหลวบนโหนดอื่นที่เปิดใช้งานก่อนหน้านี้ กระบวนการนี้โปร่งใส หลังจากเกิดความล้มเหลว แอปพลิเคชันจะย้ายไปยังโหนดที่เกิดข้อผิดพลาดโดยอัตโนมัติ คุณสามารถอ่านเพิ่มเติมเกี่ยวกับฟังก์ชันนี้ได้ ที่นี่.

การปฏิบัติ

อย่างน้อยเรามาลองเปรียบเทียบประสิทธิภาพของ rabbitmq กับข้อความที่เรากำหนดเองกันคร่าวๆ กัน
ฉันพบ ผลลัพธ์อย่างเป็นทางการ การทดสอบ rabbitmq จากทีมงาน openstack

ในย่อหน้าที่ 6.14.1.2.1.2.2 เอกสารต้นฉบับแสดงผลลัพธ์ของ RPC CAST:
Building Block ของแอปพลิเคชันแบบกระจาย การประมาณครั้งที่สอง

เราจะไม่ทำการตั้งค่าเพิ่มเติมใดๆ กับเคอร์เนล OS หรือ erlang VM ล่วงหน้า เงื่อนไขในการทดสอบ:

  • erl เลือก: +A1 +sbtu
  • การทดสอบภายในโหนด erlang เดียวจะดำเนินการบนแล็ปท็อปที่มี i7 รุ่นเก่าในเวอร์ชันมือถือ
  • การทดสอบคลัสเตอร์ดำเนินการบนเซิร์ฟเวอร์ที่มีเครือข่าย 10G
  • รหัสทำงานในคอนเทนเนอร์นักเทียบท่า เครือข่ายในโหมด NAT

รหัสทดสอบ:

req_resp_bench(_) ->
  W = perftest:comprehensive(10000,
    fun() ->
      messaging:request(?EXCHANGE, default, ping, self()),
      receive
        #'$msg'{message = pong} -> ok
      after 5000 ->
        throw(timeout)
      end
    end
  ),
  true = lists:any(fun(E) -> E >= 30000 end, W),
  ok.

สถานการณ์ที่ 1: การทดสอบดำเนินการบนแล็ปท็อปที่ใช้ i7 เวอร์ชันมือถือรุ่นเก่า การทดสอบ การส่งข้อความ และการบริการจะดำเนินการบนโหนดเดียวในคอนเทนเนอร์ Docker เดียว:

Sequential 10000 cycles in ~0 seconds (26987 cycles/s)
Sequential 20000 cycles in ~1 seconds (26915 cycles/s)
Sequential 100000 cycles in ~4 seconds (26957 cycles/s)
Parallel 2 100000 cycles in ~2 seconds (44240 cycles/s)
Parallel 4 100000 cycles in ~2 seconds (53459 cycles/s)
Parallel 10 100000 cycles in ~2 seconds (52283 cycles/s)
Parallel 100 100000 cycles in ~3 seconds (49317 cycles/s)

สถานการณ์ 2: 3 โหนดที่ทำงานบนเครื่องที่แตกต่างกันภายใต้นักเทียบท่า (NAT)

Sequential 10000 cycles in ~1 seconds (8684 cycles/s)
Sequential 20000 cycles in ~2 seconds (8424 cycles/s)
Sequential 100000 cycles in ~12 seconds (8655 cycles/s)
Parallel 2 100000 cycles in ~7 seconds (15160 cycles/s)
Parallel 4 100000 cycles in ~5 seconds (19133 cycles/s)
Parallel 10 100000 cycles in ~4 seconds (24399 cycles/s)
Parallel 100 100000 cycles in ~3 seconds (34517 cycles/s)

ในทุกกรณี การใช้งาน CPU จะต้องไม่เกิน 250%

ผลของการ

ฉันหวังว่าวงจรนี้จะไม่ดูเหมือนเป็นการทิ้งความคิด และประสบการณ์ของฉันจะเป็นประโยชน์อย่างแท้จริงต่อทั้งนักวิจัยของระบบแบบกระจายและผู้ปฏิบัติงานที่อยู่ในช่วงเริ่มต้นของการสร้างสถาปัตยกรรมแบบกระจายสำหรับระบบธุรกิจของพวกเขา และกำลังมองหา Erlang/Elixir ด้วยความสนใจ แต่มีข้อสงสัยว่าคุ้มมั้ย...

Фото @chuttersnap

เฉพาะผู้ใช้ที่ลงทะเบียนเท่านั้นที่สามารถเข้าร่วมในการสำรวจได้ เข้าสู่ระบบ, โปรด.

ฉันควรกล่าวถึงหัวข้อใดโดยละเอียดมากขึ้นโดยเป็นส่วนหนึ่งของชุดการทดลอง VTrade

  • ทฤษฎี: ตลาด คำสั่งซื้อ และเวลา: DAY, GTD, GTC, IOC, FOK, MOO, MOC, LOO, LOC

  • หนังสือสั่งการ. ทฤษฎีและการปฏิบัติในการจัดทำหนังสือแบบแบ่งกลุ่ม

  • การแสดงภาพการซื้อขาย: เห็บ แท่ง ความละเอียด วิธีจัดเก็บและวิธีติดกาว

  • แบ็คออฟฟิศ การวางแผนและพัฒนา การติดตามพนักงานและการสอบสวนเหตุการณ์

  • เอพีไอ มาดูกันว่าอินเทอร์เฟซใดที่จำเป็นและจะใช้งานอย่างไร

  • การจัดเก็บข้อมูล: PostgreSQL, Timescale, Tarantool ในระบบการซื้อขาย

  • ปฏิกิริยาในระบบการซื้อขาย

  • อื่น. ฉันจะเขียนในความคิดเห็น

ผู้ใช้ 6 คนโหวต ผู้ใช้ 4 รายงดออกเสียง

ที่มา: will.com

เพิ่มความคิดเห็น