One-cloud - ระบบปฏิบัติการระดับศูนย์ข้อมูลใน Odnoklassniki

One-cloud - ระบบปฏิบัติการระดับศูนย์ข้อมูลใน Odnoklassniki

อะโลฮ่า ผู้คน! ฉันชื่อ Oleg Anastasyev ฉันทำงานที่ Odnoklassniki ในทีมแพลตฟอร์ม นอกจากฉันแล้ว ยังมีฮาร์ดแวร์อีกมากมายที่ทำงานใน Odnoklassniki เรามีศูนย์ข้อมูลสี่แห่งพร้อมชั้นวางประมาณ 500 ตู้พร้อมเซิร์ฟเวอร์มากกว่า 8 เครื่อง เมื่อถึงจุดหนึ่ง เราตระหนักว่าการเปิดตัวระบบการจัดการใหม่จะช่วยให้เราสามารถโหลดอุปกรณ์ได้อย่างมีประสิทธิภาพมากขึ้น อำนวยความสะดวกในการจัดการการเข้าถึง ทำให้การกระจายทรัพยากรคอมพิวเตอร์ (อีกครั้ง) เป็นแบบอัตโนมัติ เร่งความเร็วในการเปิดตัวบริการใหม่ และเร่งการตอบสนอง สู่อุบัติเหตุครั้งใหญ่

มันมาจากอะไร?

นอกจากฉันและฮาร์ดแวร์อีกจำนวนหนึ่งแล้ว ยังมีคนที่ทำงานกับฮาร์ดแวร์นี้อีกด้วย เช่น วิศวกรที่อยู่ในศูนย์ข้อมูลโดยตรง เครือข่ายที่ติดตั้งซอฟต์แวร์เครือข่าย ผู้ดูแลระบบหรือ SRE ที่ให้ความยืดหยุ่นของโครงสร้างพื้นฐาน และทีมพัฒนา แต่ละคนมีหน้าที่รับผิดชอบส่วนหนึ่งของฟังก์ชันของพอร์ทัล ซอฟต์แวร์ที่พวกเขาสร้างขึ้นทำงานในลักษณะนี้:

One-cloud - ระบบปฏิบัติการระดับศูนย์ข้อมูลใน Odnoklassniki

ได้รับคำขอของผู้ใช้ทั้งที่ด้านหน้าของพอร์ทัลหลัก www.ok.ruและในส่วนอื่นๆ เช่น ในส่วน API ของเพลง ในการประมวลผลตรรกะทางธุรกิจ พวกเขาจะเรียกแอปพลิเคชันเซิร์ฟเวอร์ ซึ่งเมื่อประมวลผลคำขอ จะเรียกไมโครเซอร์วิสพิเศษที่จำเป็น - กราฟเดียว (กราฟของการเชื่อมต่อทางสังคม) แคชผู้ใช้ (แคชของโปรไฟล์ผู้ใช้) เป็นต้น

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

ทำไมเป็นอย่างนั้น? วิธีนี้มีข้อดีหลายประการ:

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

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

แนวทางนี้ยังทำให้เราสามารถทำได้ การกำหนดค่าเหล็กพิเศษ สำหรับงานที่ทำงานบนเซิร์ฟเวอร์นี้ หากงานจัดเก็บข้อมูลจำนวนมาก เราจะใช้เซิร์ฟเวอร์ 4U พร้อมแชสซีที่มีดิสก์ 38 แผ่น หากงานนี้เป็นงานที่ใช้การคำนวณเพียงอย่างเดียว เราก็สามารถซื้อเซิร์ฟเวอร์ 1U ที่ราคาถูกกว่าได้ นี่คือประสิทธิภาพในการคำนวณ เหนือสิ่งอื่นใด วิธีการนี้ช่วยให้เราใช้เครื่องน้อยลงสี่เท่าและมีภาระเทียบเท่ากับโซเชียลเน็ตเวิร์กที่เป็นมิตรเพียงเครือข่ายเดียว

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

เมื่อตระหนักว่าเป็นกรณีนี้ เราจึงตัดสินใจคำนวณว่าเราใช้ชั้นวางได้อย่างมีประสิทธิภาพเพียงใด
เราเอาราคาของเซิร์ฟเวอร์ที่ทรงพลังที่สุดมาจากราคาที่สมเหตุสมผลในเชิงเศรษฐกิจ โดยคำนวณจำนวนเซิร์ฟเวอร์ดังกล่าวที่เราสามารถวางบนชั้นวางได้ จำนวนงานที่เราจะรันบนเซิร์ฟเวอร์เหล่านั้นโดยอิงจากรุ่นเก่า “หนึ่งเซิร์ฟเวอร์ = หนึ่งงาน” และจำนวนดังกล่าว งานสามารถใช้อุปกรณ์ได้ พวกเขานับแล้วน้ำตาไหล ปรากฎว่าประสิทธิภาพในการใช้ชั้นวางของเราอยู่ที่ประมาณ 11% ข้อสรุปที่ชัดเจนคือ เราจำเป็นต้องเพิ่มประสิทธิภาพการใช้ศูนย์ข้อมูล ดูเหมือนว่าวิธีแก้ปัญหาจะชัดเจน: คุณต้องรันงานหลายอย่างบนเซิร์ฟเวอร์เครื่องเดียวในคราวเดียว แต่นี่คือจุดเริ่มต้นของความยากลำบาก

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

แต่สิ่งสำคัญคือไม่มีการแยกระหว่างงานที่ทำงานบนเครื่องเดียวกัน ตัวอย่างเช่น นี่คือกราฟของเวลาตอบสนองโดยเฉลี่ยของงานเซิร์ฟเวอร์ก่อนและหลังการเปิดตัวแอปพลิเคชันการคำนวณอื่นบนเซิร์ฟเวอร์เดียวกัน โดยไม่เกี่ยวข้องกับแอปพลิเคชันแรกเลย - เวลาตอบสนองของงานหลักเพิ่มขึ้นอย่างมีนัยสำคัญ

One-cloud - ระบบปฏิบัติการระดับศูนย์ข้อมูลใน Odnoklassniki

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

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

นอกจากนี้ รีจีสทรีสำเร็จรูปและการแท็กรูปภาพใน Docker ยังช่วยให้เรามีพื้นฐานสำเร็จรูปสำหรับการกำหนดเวอร์ชันและการส่งโค้ดไปยังการใช้งานจริง

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

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

การกระจายคอนเทนเนอร์ด้วยตนเองไม่ใช่ตัวเลือกเมื่อคุณมีเซิร์ฟเวอร์ 8 ตัวและคอนเทนเนอร์ 8-16 ตัว

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

แน่นอนว่าเราต้องการเลเยอร์ควบคุมที่จะทำสิ่งนี้โดยอัตโนมัติ

ดังนั้นเราจึงได้ภาพที่เรียบง่ายและเข้าใจได้ซึ่งสถาปนิกทุกคนชื่นชอบ: สี่เหลี่ยมสามช่อง

One-cloud - ระบบปฏิบัติการระดับศูนย์ข้อมูลใน Odnoklassniki

one-cloud masters คือคลัสเตอร์เฟลโอเวอร์ที่รับผิดชอบในการจัดการระบบคลาวด์ นักพัฒนาส่งรายการไปยังต้นแบบซึ่งมีข้อมูลทั้งหมดที่จำเป็นในการโฮสต์บริการ ตามนั้น ต้นแบบจะออกคำสั่งให้กับมินเนี่ยนที่เลือก (เครื่องจักรที่ออกแบบมาเพื่อใช้งานคอนเทนเนอร์) มินเนี่ยนมีตัวแทนของเราซึ่งรับคำสั่ง ออกคำสั่งไปยัง Docker และ Docker กำหนดค่าเคอร์เนล linux เพื่อเรียกใช้คอนเทนเนอร์ที่เกี่ยวข้อง นอกเหนือจากการดำเนินการคำสั่งแล้ว เอเจนต์ยังรายงานต่อต้นแบบอย่างต่อเนื่องเกี่ยวกับการเปลี่ยนแปลงในสถานะของทั้งเครื่องมินเนี่ยนและคอนเทนเนอร์ที่ทำงานอยู่บนนั้น

การจัดสรรทรัพยากร

ตอนนี้เรามาดูปัญหาของการจัดสรรทรัพยากรที่ซับซ้อนมากขึ้นสำหรับมินเนี่ยนจำนวนมาก

ทรัพยากรการประมวลผลในระบบคลาวด์เดียวคือ:

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

จากนั้นสำหรับบริการบางอย่าง เช่น สำหรับแคชผู้ใช้ เราสามารถบันทึกทรัพยากรที่ใช้ในลักษณะนี้: คอร์โปรเซสเซอร์ 400 ตัว, หน่วยความจำ 2,5 TB, การรับส่งข้อมูล 50 Gbit/s ทั้งสองทิศทาง, พื้นที่ HDD 6 TB ที่อยู่บน 100 สปินเดิล หรือในรูปแบบที่คุ้นเคยกว่านี้:

alloc:
    cpu: 400
    mem: 2500
    lan_in: 50g
    lan_out: 50g
    hdd:100x6T

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

กลับไปที่ไดอะแกรมที่เรียบง่ายอย่างมากของการโต้ตอบของส่วนประกอบแล้ววาดใหม่พร้อมรายละเอียดเพิ่มเติม - เช่นนี้

One-cloud - ระบบปฏิบัติการระดับศูนย์ข้อมูลใน Odnoklassniki

สิ่งที่ดึงดูดสายตาของคุณ:

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

มาวาดภาพใหม่อีกครั้ง:

One-cloud - ระบบปฏิบัติการระดับศูนย์ข้อมูลใน Odnoklassniki

บ้า! ใช่ เราเห็นลำดับชั้น! ซึ่งหมายความว่าคุณสามารถกระจายทรัพยากรเป็นชิ้นใหญ่ได้: มอบหมายนักพัฒนาที่รับผิดชอบให้กับโหนดของลำดับชั้นนี้ที่สอดคล้องกับระบบย่อยการทำงาน (เช่น "เพลง" ในภาพ) และแนบโควต้าในระดับเดียวกันของลำดับชั้น ลำดับชั้นนี้ยังช่วยให้เราจัดระเบียบบริการได้อย่างยืดหยุ่นมากขึ้นเพื่อความสะดวกในการจัดการ ตัวอย่างเช่น เราแบ่งเว็บทั้งหมด เนื่องจากนี่เป็นกลุ่มเซิร์ฟเวอร์ที่ใหญ่มาก ออกเป็นหลายกลุ่มเล็กๆ ดังที่แสดงในภาพเป็น group1, group2

ด้วยการลบบรรทัดพิเศษออก เราสามารถเขียนแต่ละโหนดของรูปภาพของเราให้อยู่ในรูปแบบที่เรียบยิ่งขึ้น: group1.web.front, api.music.front, ผู้ใช้ cache.cache.

นี่คือวิธีที่เรามาถึงแนวคิดของ "คิวแบบลำดับชั้น" มีชื่อเหมือน "group1.web.front" มีการกำหนดโควต้าสำหรับทรัพยากรและสิทธิ์ผู้ใช้ เราจะให้สิทธิ์แก่บุคคลจาก DevOps ในการส่งบริการไปยังคิว และพนักงานดังกล่าวสามารถเปิดบางสิ่งในคิวได้ และบุคคลจาก OpsDev จะมีสิทธิ์ของผู้ดูแลระบบ และตอนนี้เขาสามารถจัดการคิว มอบหมายผู้คนที่นั่นได้ ให้สิทธิ์แก่บุคคลเหล่านี้ ฯลฯ บริการที่ทำงานบนคิวนี้จะทำงานภายในโควต้าของคิว หากโควต้าการประมวลผลของคิวไม่เพียงพอที่จะดำเนินการบริการทั้งหมดในคราวเดียว พวกเขาจะถูกดำเนินการตามลำดับ ดังนั้นจึงสร้างคิวขึ้นมาเอง

มาดูบริการกันดีกว่า บริการมีชื่อที่มีคุณสมบัติครบถ้วน ซึ่งจะรวมชื่อของคิวไว้ด้วยเสมอ จากนั้นเว็บเซอร์วิสส่วนหน้าก็จะมีชื่อ ตกลง-web.group1.web.front. และบริการแอปพลิเคชันเซิร์ฟเวอร์ที่เข้าถึงจะถูกเรียก ตกลง-app.group1.web.front. แต่ละบริการจะมีรายการซึ่งระบุข้อมูลที่จำเป็นทั้งหมดสำหรับการวางตำแหน่งบนเครื่องเฉพาะ เช่น จำนวนทรัพยากรที่งานนี้ใช้ การกำหนดค่าใดที่จำเป็นสำหรับงานนี้ จำนวนแบบจำลองที่ควรมี คุณสมบัติในการจัดการความล้มเหลวของบริการนี้ และหลังจากวางบริการบนเครื่องโดยตรงแล้ว อินสแตนซ์ก็จะปรากฏขึ้น นอกจากนี้ยังมีการตั้งชื่ออย่างไม่คลุมเครือ - เป็นหมายเลขอินสแตนซ์และชื่อบริการ: 1.ok-web.group1.web.front, 2.ok-web.group1.web.front, …

สะดวกมาก: เมื่อดูเฉพาะชื่อคอนเทนเนอร์ที่ทำงานอยู่เราก็สามารถค้นพบอะไรมากมายได้ทันที

ตอนนี้เรามาดูกันว่าอินสแตนซ์เหล่านี้ทำงานอย่างไรจริงๆ: งาน

ชั้นเรียนแยกงาน

งานทั้งหมดใน OK (และอาจทุกที่) สามารถแบ่งออกเป็นกลุ่มได้:

  • งานหน่วงเวลาสั้น - prod. สำหรับงานและบริการดังกล่าว ความล่าช้าในการตอบสนอง (เวลาแฝง) มีความสำคัญมาก โดยระบบจะประมวลผลคำขอแต่ละรายการได้เร็วเพียงใด ตัวอย่างของงาน: ส่วนหน้าของเว็บ แคช แอปพลิเคชันเซิร์ฟเวอร์ ที่เก็บข้อมูล OLTP ฯลฯ
  • ปัญหาการคำนวณ - แบทช์. ในที่นี้ ความเร็วในการประมวลผลของแต่ละคำขอนั้นไม่สำคัญ สำหรับพวกเขา สิ่งสำคัญคือจำนวนการคำนวณที่งานนี้จะทำในช่วงเวลาหนึ่ง (ยาวนาน) (ปริมาณงาน) สิ่งเหล่านี้จะเป็นงานใดๆ ของ MapReduce, Hadoop, การเรียนรู้ของเครื่อง, สถิติ
  • งานเบื้องหลัง - ไม่ได้ใช้งาน. สำหรับงานดังกล่าว เวลาแฝงหรือปริมาณงานไม่สำคัญมาก ซึ่งรวมถึงการทดสอบต่างๆ การโยกย้าย การคำนวณใหม่ และการแปลงข้อมูลจากรูปแบบหนึ่งไปยังอีกรูปแบบหนึ่ง ในอีกด้านหนึ่ง มันคล้ายกับการคำนวณ ในทางกลับกัน มันไม่สำคัญสำหรับเราว่ามันจะเสร็จเร็วแค่ไหน

มาดูกันว่างานดังกล่าวใช้ทรัพยากรอย่างไร เช่น โปรเซสเซอร์กลาง

งานล่าช้าระยะสั้น งานดังกล่าวจะมีรูปแบบการใช้ CPU คล้ายกับสิ่งนี้:

One-cloud - ระบบปฏิบัติการระดับศูนย์ข้อมูลใน Odnoklassniki

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

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

alloc: cpu = 4 (max)

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

งานการคำนวณ รูปแบบจะแตกต่างออกไปเล็กน้อย:

One-cloud - ระบบปฏิบัติการระดับศูนย์ข้อมูลใน Odnoklassniki

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

alloc: cpu = [1,*)

“กรุณาวางมันลงบนมินเนี่ยนที่มีแกนว่างอย่างน้อยหนึ่งแกน และมากเท่าที่มี มันจะกลืนกินทุกสิ่ง”

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

One-cloud - ระบบปฏิบัติการระดับศูนย์ข้อมูลใน Odnoklassniki

แต่จะทำอย่างไร?

ก่อนอื่น มาดู prod และการจัดสรรของมันกันก่อน: cpu = 4 เราต้องจองสี่คอร์ไว้ ในการรัน Docker สามารถทำได้สองวิธี:

  • การใช้ตัวเลือก --cpuset=1-4กล่าวคือจัดสรรคอร์เฉพาะสี่คอร์บนเครื่องให้กับงาน
  • ที่จะใช้ --cpuquota=400_000 --cpuperiod=100_000กำหนดโควต้าสำหรับเวลาประมวลผล เช่น ระบุว่าทุก ๆ 100 มิลลิวินาทีของเวลาจริงงานใช้เวลาประมวลผลไม่เกิน 400 มิลลิวินาที ได้รับสี่คอร์เดียวกัน

แต่วิธีการใดต่อไปนี้เหมาะสม?

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

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

เราตกลงกันว่าหากแบตช์ต้องมีการรับประกันอย่างน้อยหนึ่งคอร์ เราก็จะต้องระบุ --cpushares=1024และหากมีอย่างน้อยสองคอร์ เราก็จะระบุ --cpushares=2048. การแบ่งใช้ CPU จะไม่รบกวนการกระจายเวลาของโปรเซสเซอร์ แต่อย่างใดตราบเท่าที่มีเวลาเพียงพอ ดังนั้น หากปัจจุบัน prod ไม่ได้ใช้คอร์ทั้งสี่คอร์ ก็ไม่มีอะไรจำกัดงานแบบแบตช์ และพวกเขาสามารถใช้เวลาประมวลผลเพิ่มเติมได้ แต่ในสถานการณ์ที่โปรเซสเซอร์ขาดแคลน หากผลิตภัณฑ์ใช้คอร์ทั้งสี่คอร์และถึงโควต้าแล้ว เวลาโปรเซสเซอร์ที่เหลือจะถูกแบ่งตามสัดส่วนของ cpushares เช่น ในสถานการณ์ที่มีคอร์ว่างสามคอร์ หนึ่งจะเป็น มอบให้กับงานที่มี cpushares 1024 ตัว และอีกสองอันที่เหลือจะถูกมอบให้กับงานที่มี cpushares 2048 ตัว

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

  • กำหนดการ_OTHER
    ตามค่าเริ่มต้น กระบวนการของผู้ใช้ปกติทั้งหมดบนเครื่อง Linux จะได้รับ
  • กำหนด_ชุด
    ออกแบบมาสำหรับกระบวนการที่ใช้ทรัพยากรมาก เมื่อวางงานบนตัวประมวลผล จะมีการแนะนำสิ่งที่เรียกว่าการลงโทษในการเปิดใช้งาน: งานดังกล่าวมีโอกาสน้อยที่จะได้รับทรัพยากรของตัวประมวลผล หากงานนั้นถูกใช้งานโดย SCHED_OTHER ในปัจจุบัน
  • กำหนดการ_IDLE
    กระบวนการเบื้องหลังที่มีลำดับความสำคัญต่ำมาก แม้จะต่ำกว่า nice -19 ก็ตาม เราใช้ไลบรารีโอเพ่นซอร์สของเรา หนึ่ง-นีโอเพื่อกำหนดนโยบายที่จำเป็นเมื่อเริ่มคอนเทนเนอร์โดยการเรียก

one.nio.os.Proc.sched_setscheduler( pid, Proc.SCHED_IDLE )

แต่แม้ว่าคุณจะไม่ได้เขียนโปรแกรมใน Java คุณก็สามารถทำได้โดยใช้คำสั่ง chrt:

chrt -i 0 $pid

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

ชั้นฉนวน
ตัวอย่างการจัดสรร
ตัวเลือกการเรียกใช้นักเทียบท่า
sched_setscheduler chrt*

แยง
ซีพียู = 4
--cpuquota=400000 --cpuperiod=100000
กำหนดการ_OTHER

ชุด
ซีพียู = [1, *)
--cpushares=1024
กำหนด_ชุด

Idle
ซีพียู= [2, *)
--cpushares=2048
กำหนดการ_IDLE

*หากคุณทำ chrt จากภายในคอนเทนเนอร์ คุณอาจต้องใช้ความสามารถ sys_nice เนื่องจากโดยค่าเริ่มต้น Docker จะลบความสามารถนี้ออกเมื่อเริ่มต้นคอนเทนเนอร์

แต่งานไม่เพียงใช้ตัวประมวลผลเท่านั้น แต่ยังรวมถึงการรับส่งข้อมูลซึ่งส่งผลต่อเวลาแฝงของงานเครือข่ายมากกว่าการจัดสรรทรัพยากรตัวประมวลผลที่ไม่ถูกต้อง ดังนั้นเราจึงต้องการได้ภาพการจราจรที่เหมือนกันทุกประการ นั่นคือ เมื่องาน prod ส่งแพ็กเก็ตบางส่วนไปยังเครือข่าย เราจะจำกัดความเร็วสูงสุด (formula จัดสรร: lan=[*,500mbps) ) โดยผลิตภัณฑ์ใดที่สามารถทำได้ และสำหรับแบทช์ เรารับประกันเฉพาะปริมาณงานขั้นต่ำ แต่ไม่จำกัดปริมาณสูงสุด (สูตร จัดสรร: lan=[10Mbps,*) ) ในกรณีนี้ ปริมาณการใช้ผลิตภัณฑ์ควรได้รับลำดับความสำคัญมากกว่างานแบบแบตช์
ที่นี่ Docker ไม่มีพื้นฐานใด ๆ ที่เราสามารถใช้ได้ แต่มันมาเพื่อช่วยเหลือเรา การควบคุมการรับส่งข้อมูลลินุกซ์. เราสามารถบรรลุผลตามที่ต้องการได้ด้วยความช่วยเหลือของวินัย เส้นบริการยุติธรรมแบบลำดับชั้น. ด้วยความช่วยเหลือนี้ เราจึงสามารถแยกแยะการรับส่งข้อมูลได้สองประเภท: ผลิตภัณฑ์ที่มีลำดับความสำคัญสูง และแบทช์/ไม่ได้ใช้งานที่มีลำดับความสำคัญต่ำ ด้วยเหตุนี้ การกำหนดค่าสำหรับการรับส่งข้อมูลขาออกจึงเป็นดังนี้:

One-cloud - ระบบปฏิบัติการระดับศูนย์ข้อมูลใน Odnoklassniki

ที่นี่ 1:0 คือ "root qdisc" ของระเบียบวินัย hsfc 1:1 - คลาสย่อย hsfc ที่มีขีดจำกัดแบนด์วิดท์รวม 8 Gbit/s ซึ่งคลาสย่อยของคอนเทนเนอร์ทั้งหมดจะถูกวางไว้ใต้นั้น 1:2 - คลาสย่อย hsfc เป็นเรื่องปกติสำหรับงานแบทช์และงานที่ไม่ได้ใช้งานทั้งหมดที่มีขีดจำกัด "ไดนามิก" ซึ่งจะกล่าวถึงด้านล่าง คลาสย่อย hsfc ที่เหลือเป็นคลาสเฉพาะสำหรับการรันคอนเทนเนอร์ที่ใช้งานอยู่ในปัจจุบัน โดยมีขีดจำกัดที่สอดคล้องกับไฟล์ Manifest - 450 และ 400 Mbit/s แต่ละคลาส hsfc ถูกกำหนดคิว qdisc fq หรือ fq_codel ขึ้นอยู่กับเวอร์ชันเคอร์เนล Linux เพื่อหลีกเลี่ยงการสูญเสียแพ็กเก็ตระหว่างการรับส่งข้อมูลที่ระเบิด

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

One-cloud - ระบบปฏิบัติการระดับศูนย์ข้อมูลใน Odnoklassniki

ในระหว่างการทดลอง เราพบว่า hsfc แสดงผลลัพธ์ที่ดีที่สุดเมื่อคลาส 1:2 ของการรับส่งข้อมูลแบบแบตช์/ไม่ได้ใช้งานแบบไม่มีลำดับความสำคัญถูกจำกัดบนเครื่องมินเนี่ยนให้ไม่เกินเลนว่างบางเลน มิฉะนั้น การรับส่งข้อมูลที่ไม่มีความสำคัญจะมีผลกระทบมากเกินไปต่อเวลาแฝงของงานที่ใช้งานจริง miniond จะกำหนดจำนวนแบนด์วิธที่ว่างในปัจจุบันทุกๆ วินาที โดยวัดปริมาณการใช้ข้อมูลโดยเฉลี่ยของงานผลิตภัณฑ์ทั้งหมดของ minion ที่กำหนด One-cloud - ระบบปฏิบัติการระดับศูนย์ข้อมูลใน Odnoklassniki และลบออกจากแบนด์วิธอินเทอร์เฟซเครือข่าย One-cloud - ระบบปฏิบัติการระดับศูนย์ข้อมูลใน Odnoklassniki โดยมีระยะขอบเล็กน้อยเช่น

One-cloud - ระบบปฏิบัติการระดับศูนย์ข้อมูลใน Odnoklassniki

แบนด์ถูกกำหนดอย่างเป็นอิสระสำหรับการรับส่งข้อมูลขาเข้าและขาออก และตามค่าใหม่ มิเนียนจะกำหนดค่าขีดจำกัดคลาสที่ไม่มีลำดับความสำคัญใหม่เป็น 1:2

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

One-cloud - ระบบปฏิบัติการระดับศูนย์ข้อมูลใน Odnoklassniki

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

เมื่อลบบรรทัดพิเศษออกอีกครั้ง เราสามารถเขียนชื่อบริการของเราให้สวยงามขึ้นได้โดยการเพิ่มคลาสการแยกงานต่อท้ายชื่อบริการแบบเต็ม: เว็บ.front.prod, แค็ตตาล็อก.music.batch, หม้อแปลงไฟฟ้าเพลงไม่ได้ใช้งาน.

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

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

สิ่งที่เราจัดการเพื่อให้บรรลุผลสำเร็จ: หากแบทช์ใช้ปริมาณมาก เท่านั้น ทรัพยากรของ CPU ดังนั้นตัวกำหนดเวลา CPU ของ Linux ในตัวจึงทำงานได้ดีมากและแทบไม่มีผลกระทบต่องานจริงเลย แต่ถ้างานแบตช์นี้เริ่มทำงานกับหน่วยความจำอย่างแข็งขันก็แสดงว่าอิทธิพลซึ่งกันและกันก็ปรากฏขึ้นแล้ว สิ่งนี้เกิดขึ้นเนื่องจากงานผลิตภัณฑ์ถูก "ล้าง" ออกจากแคชหน่วยความจำของโปรเซสเซอร์ ส่งผลให้แคชพลาดเพิ่มขึ้น และโปรเซสเซอร์ประมวลผลงานผลิตภัณฑ์ช้าลง งานแบบกลุ่มดังกล่าวสามารถเพิ่มเวลาแฝงของคอนเทนเนอร์ผลิตภัณฑ์ทั่วไปของเราได้ 10%

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

นอกจากนี้ เรายังจัดการได้เพียงแก้ปัญหาการจัดลำดับความสำคัญของการรับส่งข้อมูล TCP เท่านั้น: วิธี hsfc ใช้ไม่ได้กับ UDP และแม้แต่ในกรณีของการรับส่งข้อมูล TCP หากงานแบตช์สร้างการรับส่งข้อมูลจำนวนมาก ก็จะทำให้งานล่าช้าเพิ่มขึ้นประมาณ 10%

ความอดทนต่อความผิดพลาด

เป้าหมายประการหนึ่งเมื่อพัฒนาระบบคลาวด์เดียวคือการปรับปรุงความทนทานต่อความเสียหายของ Odnoklassniki ดังนั้น ต่อไปฉันอยากจะพิจารณารายละเอียดเพิ่มเติมเกี่ยวกับสถานการณ์ที่เป็นไปได้ของความล้มเหลวและอุบัติเหตุ เริ่มจากสถานการณ์ง่ายๆ - คอนเทนเนอร์ล้มเหลว

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

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

คุณจะทำอย่างไรถ้ามินเนี่ยนทั้งตัวไม่พร้อมใช้งาน?

แน่นอนว่ารันคอนเทนเนอร์บนเครื่องอื่น ส่วนที่น่าสนใจคือสิ่งที่เกิดขึ้นกับที่อยู่ IP ที่กำหนดให้กับคอนเทนเนอร์

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

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

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

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

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

ดังนั้นการแมปชื่อบริการกับรายการที่อยู่ IP จึงเปลี่ยนแปลงน้อยมาก หากคุณดูชื่อของอินสแตนซ์บริการที่เรากล่าวถึงในตอนต้นของบทความอีกครั้ง (1.ok-web.group1.web.front.prod, 2.ok-web.group1.web.front.prod, …) เราจะสังเกตเห็นว่ามีลักษณะคล้ายกับ FQDN ที่ใช้ใน DNS ถูกต้องแล้ว ในการแมปชื่อของอินสแตนซ์บริการกับที่อยู่ IP เราใช้โปรโตคอล DNS นอกจากนี้ DNS นี้ยังส่งคืนที่อยู่ IP ที่สงวนไว้ทั้งหมดของคอนเทนเนอร์ทั้งหมด - ทั้งที่ทำงานอยู่และหยุดทำงานแล้ว (สมมติว่ามีการใช้แบบจำลองสามรายการ และเรามีที่อยู่ห้ารายการที่สงวนไว้ที่นั่น - ทั้งห้ารายการจะถูกส่งคืน) เมื่อลูกค้าได้รับข้อมูลนี้แล้ว จะพยายามสร้างการเชื่อมต่อกับแบบจำลองทั้งห้า - และกำหนดแบบจำลองที่ใช้งานได้ ตัวเลือกในการระบุความพร้อมใช้งานนี้มีความน่าเชื่อถือมากกว่ามาก โดยไม่เกี่ยวข้องกับ DNS หรือ Service Discovery ซึ่งหมายความว่าไม่มีปัญหาที่ยากในการแก้ไขเพื่อให้มั่นใจถึงความเกี่ยวข้องของข้อมูลและความทนทานต่อข้อบกพร่องของระบบเหล่านี้ ยิ่งไปกว่านั้น ในบริการที่สำคัญซึ่งขึ้นอยู่กับการทำงานของพอร์ทัลทั้งหมด เราไม่สามารถใช้ DNS ได้เลย แต่เพียงป้อนที่อยู่ IP ลงในการกำหนดค่า

การใช้การถ่ายโอน IP ดังกล่าวหลังคอนเทนเนอร์อาจไม่ใช่เรื่องเล็กน้อย และเราจะดูวิธีการทำงานด้วยตัวอย่างต่อไปนี้:

One-cloud - ระบบปฏิบัติการระดับศูนย์ข้อมูลใน Odnoklassniki

สมมติว่าต้นแบบคลาวด์เดียวออกคำสั่งให้มินเนี่ยน M1 วิ่ง 1.ok-web.group1.web.front.prod พร้อมที่อยู่ 1.1.1.1 ใช้งานได้กับมินเนี่ยน นกซึ่งโฆษณาที่อยู่นี้ไปยังเซิร์ฟเวอร์พิเศษ ตัวสะท้อนแสงเส้นทาง. อย่างหลังมีเซสชัน BGP กับฮาร์ดแวร์เครือข่าย ซึ่งมีการแปลเส้นทางของที่อยู่ 1.1.1.1 บน M1 M1 กำหนดเส้นทางแพ็กเก็ตภายในคอนเทนเนอร์โดยใช้ Linux มีเซิร์ฟเวอร์ตัวสะท้อนเส้นทางสามเซิร์ฟเวอร์ เนื่องจากนี่เป็นส่วนที่สำคัญมากของโครงสร้างพื้นฐานระบบคลาวด์เดียว หากไม่มีเซิร์ฟเวอร์เหล่านี้ เครือข่ายในระบบคลาวด์เดียวจะไม่ทำงาน เราวางพวกมันไว้ในชั้นวางที่แตกต่างกัน หากเป็นไปได้ โดยตั้งอยู่ในห้องต่างๆ ของศูนย์ข้อมูล เพื่อลดโอกาสที่ทั้งสามจะล้มเหลวในเวลาเดียวกัน

ตอนนี้ สมมติว่าการเชื่อมต่อระหว่าง one-cloud master และ M1 minion ขาดหายไป ต้นแบบคลาวด์เดียวจะดำเนินการตามสมมติฐานที่ว่า M1 ล้มเหลวโดยสิ้นเชิง นั่นคือมันจะออกคำสั่งให้สมุน M2 เปิดตัว web.group1.web.front.prod โดยมีที่อยู่เดียวกัน 1.1.1.1. ตอนนี้เรามีสองเส้นทางที่ขัดแย้งกันบนเครือข่ายสำหรับ 1.1.1.1: บน M1 และบน M2 เพื่อแก้ไขข้อขัดแย้งดังกล่าว เราใช้ Multi Exit Discriminator ซึ่งระบุไว้ในประกาศ BGP เป็นตัวเลขที่แสดงน้ำหนักของเส้นทางที่โฆษณา ในบรรดาเส้นทางที่ขัดแย้งกัน เส้นทางที่มีค่า MED ต่ำกว่าจะถูกเลือก ต้นแบบคลาวด์เดียวรองรับ MED เป็นส่วนสำคัญของที่อยู่ IP ของคอนเทนเนอร์ เป็นครั้งแรกที่มีการเขียนที่อยู่ด้วย MED ที่มีขนาดใหญ่เพียงพอ = 1 ในสถานการณ์ของการถ่ายโอนตู้คอนเทนเนอร์ฉุกเฉินดังกล่าว ต้นแบบจะลด MED และ M000 จะได้รับคำสั่งให้โฆษณาที่อยู่ 000 ด้วย MED = 2 อินสแตนซ์ที่ทำงานบน M1.1.1.1 จะยังคงอยู่ในกรณีนี้ไม่มีการเชื่อมต่อ และชะตากรรมต่อไปของเขาจะไม่สนใจเราเพียงเล็กน้อยจนกว่าการเชื่อมต่อกับปรมาจารย์จะกลับมาอีกครั้ง เมื่อเขาจะถูกหยุดเหมือนครั้งเก่า

อุบัติเหตุ

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

มาดูวิธีที่เราจัดการกับเหตุฉุกเฉิน เช่น ไฟฟ้าขัดข้องในห้องศูนย์ข้อมูลตั้งแต่หนึ่งห้องขึ้นไป

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

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

คุณสามารถทำอะไรเกี่ยวกับเรื่องทั้งหมดนี้?

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

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

One-cloud - ระบบปฏิบัติการระดับศูนย์ข้อมูลใน Odnoklassniki

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

ในการผลิตเรากำหนดลำดับความสำคัญที่สูงกว่า 0; ในแบทช์ - ต่ำกว่าเล็กน้อย 100; เมื่อไม่ได้ใช้งาน - ต่ำกว่า 200 ลำดับความสำคัญจะถูกนำไปใช้ตามลำดับชั้น งานทั้งหมดที่ต่ำกว่าในลำดับชั้นจะมีลำดับความสำคัญที่สอดคล้องกัน หากเราต้องการให้แคชภายในผลิตภัณฑ์เปิดใช้งานก่อนส่วนหน้า เราจะกำหนดลำดับความสำคัญให้กับแคช = 0 และคิวย่อยส่วนหน้า = 1 ตัวอย่างเช่น หากเราต้องการให้พอร์ทัลหลักเปิดใช้งานจากส่วนหน้าก่อน และให้เฉพาะส่วนหน้าของเพลงเท่านั้น จากนั้นเราสามารถกำหนดลำดับความสำคัญที่ต่ำกว่าให้กับอันหลัง - 10

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

One-cloud - ระบบปฏิบัติการระดับศูนย์ข้อมูลใน Odnoklassniki

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

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

อุบัติเหตุ DC ทั้งหมด

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

และนี่คือสิ่งที่เราทำเพื่อป้องกันไม่ให้ใครทวีต #alive

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

วิธีการนี้ไม่เพียงแต่ป้องกันความล้มเหลวทางกายภาพเท่านั้น แต่ยังสามารถป้องกันข้อผิดพลาดของผู้ปฏิบัติงานได้อีกด้วย

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

One-cloud - ระบบปฏิบัติการระดับศูนย์ข้อมูลใน Odnoklassniki

ผลของการ

คุณสมบัติที่โดดเด่นของคลาวด์เดียว:

  • รูปแบบการตั้งชื่อแบบลำดับชั้นและภาพสำหรับบริการและคอนเทนเนอร์ซึ่งช่วยให้คุณค้นหาได้อย่างรวดเร็วว่างานคืออะไร เกี่ยวข้องกับอะไร ทำงานอย่างไร และใครเป็นผู้รับผิดชอบ
  • เราใช้ของเรา เทคนิคการรวมผลิตภัณฑ์และแบทช์งานกับมินเนี่ยนเพื่อปรับปรุงประสิทธิภาพของการแบ่งปันเครื่อง แทนที่จะใช้ cpuset เราใช้โควต้า CPU, การแชร์, นโยบายตัวกำหนดเวลา CPU และ Linux QoS
  • ไม่สามารถแยกคอนเทนเนอร์ที่ทำงานบนเครื่องเดียวกันได้อย่างสมบูรณ์ แต่อิทธิพลซึ่งกันและกันยังคงอยู่ภายใน 20%
  • การจัดบริการเป็นลำดับชั้นช่วยในการกู้คืนความเสียหายโดยอัตโนมัติ ลำดับความสำคัญของตำแหน่งและใบจอง.

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

ทำไมเราไม่ใช้วิธีแก้ปัญหาสำเร็จรูป?

  • การแยกภารกิจในแต่ละคลาสต้องใช้ตรรกะที่แตกต่างกันเมื่อวางไว้บนมินเนี่ยน หากสามารถวางงาน prod ได้โดยเพียงแค่จองทรัพยากร ก็จะต้องวางงานแบบแบตช์และงานว่างเพื่อติดตามการใช้งานจริงของทรัพยากรบนเครื่อง minion
  • ความจำเป็นในการคำนึงถึงทรัพยากรที่ใช้โดยงาน เช่น:
    • แบนด์วิธเครือข่าย
    • ประเภทและ "สปินเดิล" ของดิสก์
  • ความจำเป็นในการระบุลำดับความสำคัญของบริการระหว่างการตอบสนองฉุกเฉิน สิทธิ์และโควต้าคำสั่งสำหรับทรัพยากร ซึ่งแก้ไขได้โดยใช้คิวแบบลำดับชั้นในระบบคลาวด์เดียว
  • ความจำเป็นในการตั้งชื่อคอนเทนเนอร์โดยมนุษย์เพื่อลดเวลาตอบสนองต่ออุบัติเหตุและเหตุการณ์ต่างๆ
  • ความเป็นไปไม่ได้ของการนำ Service Discovery ไปใช้อย่างแพร่หลายเพียงครั้งเดียว ความจำเป็นในการอยู่ร่วมกันเป็นเวลานานกับงานที่โฮสต์บนโฮสต์ฮาร์ดแวร์ - สิ่งที่แก้ไขได้ด้วยที่อยู่ IP "คงที่" ที่อยู่ถัดจากคอนเทนเนอร์ และด้วยเหตุนี้ ความจำเป็นในการบูรณาการที่เป็นเอกลักษณ์กับโครงสร้างพื้นฐานเครือข่ายขนาดใหญ่

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

สำหรับผู้ที่อ่านบรรทัดสุดท้าย ขอขอบคุณสำหรับความอดทนและความสนใจของคุณ!

ที่มา: will.com

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