คำถามที่พบบ่อยเกี่ยวกับสถาปัตยกรรมและการทำงานของ VKontakte

ประวัติความเป็นมาของการสร้าง VKontakte อยู่ใน Wikipedia โดยพาเวลเล่าเอง ดูเหมือนว่าทุกคนจะรู้จักเธอแล้ว เกี่ยวกับภายใน สถาปัตยกรรม และโครงสร้างของไซต์บน HighLoad++ Pavel บอกฉันย้อนกลับไปในปี 2010. ตั้งแต่นั้นมา เซิร์ฟเวอร์จำนวนมากรั่วไหล ดังนั้นเราจะอัปเดตข้อมูล: เราจะผ่ามัน นำอวัยวะภายในออก ชั่งน้ำหนัก และดูอุปกรณ์ VK จากมุมมองทางเทคนิค

คำถามที่พบบ่อยเกี่ยวกับสถาปัตยกรรมและการทำงานของ VKontakte

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



เป็นเวลากว่าสี่ปีแล้วที่ฉันจัดการกับงานทุกประเภทที่เกี่ยวข้องกับแบ็กเอนด์

  • การอัปโหลด จัดเก็บ ประมวลผล เผยแพร่สื่อ: วิดีโอ การสตรีมสด เสียง รูปภาพ เอกสาร
  • โครงสร้างพื้นฐาน, แพลตฟอร์ม, การตรวจสอบนักพัฒนา, บันทึก, แคชระดับภูมิภาค, CDN, โปรโตคอล RPC ที่เป็นกรรมสิทธิ์
  • การบูรณาการกับบริการภายนอก: การแจ้งเตือนแบบพุช, การแยกวิเคราะห์ลิงก์ภายนอก, ฟีด RSS
  • ช่วยเหลือเพื่อนร่วมงานด้วยคำถามต่างๆ คำตอบที่ต้องอาศัยโค้ดที่ไม่รู้จัก

ในช่วงเวลานี้ ฉันมีส่วนช่วยในหลายองค์ประกอบของไซต์ ฉันต้องการแบ่งปันประสบการณ์นี้

สถาปัตยกรรมทั่วไป

ตามปกติทุกอย่างจะเริ่มต้นด้วยเซิร์ฟเวอร์หรือกลุ่มเซิร์ฟเวอร์ที่ยอมรับคำขอ

เซิร์ฟเวอร์ด้านหน้า

เซิร์ฟเวอร์ด้านหน้ายอมรับคำขอผ่าน HTTPS, RTMP และ WSS

HTTPS - นี่คือคำขอสำหรับเว็บไซต์เวอร์ชันหลักและเว็บบนมือถือ: vk.com และ m.vk.com และไคลเอนต์ที่เป็นทางการและไม่เป็นทางการอื่น ๆ ของ API ของเรา: ไคลเอนต์มือถือ, ผู้ส่งสาร เรามีแผนกต้อนรับ RTMP- การรับส่งข้อมูลสำหรับการถ่ายทอดสดพร้อมเซิร์ฟเวอร์ด้านหน้าแยกต่างหากและ WSS- การเชื่อมต่อสำหรับ Streaming API

สำหรับ HTTPS และ WSS บนเซิร์ฟเวอร์ถือว่าคุ้มค่า Nginx. สำหรับการออกอากาศ RTMP เราเพิ่งเปลี่ยนมาใช้โซลูชันของเราเอง คิฟแต่อยู่นอกเหนือขอบเขตของรายงาน สำหรับการยอมรับข้อผิดพลาด เซิร์ฟเวอร์เหล่านี้โฆษณาที่อยู่ IP ทั่วไปและดำเนินการเป็นกลุ่ม ดังนั้นหากเกิดปัญหาบนเซิร์ฟเวอร์ใดเซิร์ฟเวอร์หนึ่ง คำขอของผู้ใช้จะไม่สูญหาย สำหรับ HTTPS และ WSS เซิร์ฟเวอร์เดียวกันนี้จะเข้ารหัสการรับส่งข้อมูลเพื่อเป็นส่วนหนึ่งของภาระงานของ CPU

เราจะไม่พูดถึง WSS และ RTMP เพิ่มเติม แต่จะพูดถึงคำขอ HTTPS มาตรฐานเท่านั้น ซึ่งมักจะเกี่ยวข้องกับโครงการเว็บ

แบ็กเอนด์

ด้านหลังด้านหน้ามักจะมีเซิร์ฟเวอร์แบ็กเอนด์ พวกเขาประมวลผลคำขอที่เซิร์ฟเวอร์ด้านหน้าได้รับจากไคลเอนต์

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

โหลดการกระจาย

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

การรวบรวมและการปรับสมดุลเมตริก

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

เรามีเซิร์ฟเวอร์ดังกล่าวหลายพันรายการ ฟิสิคัลเซิร์ฟเวอร์แต่ละตัวจะรันกลุ่ม kPHP เพื่อรีไซเคิลคอร์ทั้งหมด (เนื่องจาก kPHP เป็นแบบเธรดเดียว)

เซิร์ฟเวอร์เนื้อหา

CS หรือ Content Server เป็นที่เก็บข้อมูล. CS คือเซิร์ฟเวอร์ที่จัดเก็บไฟล์และประมวลผลไฟล์ที่อัปโหลดและงานซิงโครนัสในพื้นหลังทุกประเภทที่ส่วนหน้าของเว็บหลักกำหนดไว้

เรามีเซิร์ฟเวอร์ทางกายภาพนับหมื่นเครื่องที่เก็บไฟล์ ผู้ใช้ชอบอัปโหลดไฟล์ และเราชอบที่จะจัดเก็บและแบ่งปันไฟล์เหล่านั้น เซิร์ฟเวอร์เหล่านี้บางส่วนถูกปิดโดยเซิร์ฟเวอร์ pu/pp พิเศษ

ปู/พีพี

หากคุณเปิดแท็บเครือข่ายใน VK คุณจะเห็น pu/pp

คำถามที่พบบ่อยเกี่ยวกับสถาปัตยกรรมและการทำงานของ VKontakte

pu/pp คืออะไร? หากเราปิดเซิร์ฟเวอร์หนึ่งแล้วเซิร์ฟเวอร์อื่น มีสองตัวเลือกในการอัพโหลดและดาวน์โหลดไฟล์ไปยังเซิร์ฟเวอร์ที่ถูกปิด: โดยตรง ตลอด http://cs100500.userapi.com/path หรือ ผ่านเซิร์ฟเวอร์ระดับกลาง - http://pu.vk.com/c100500/path.

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

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

เนื่องจากเครื่องอื่นๆ ของเราปิดเครื่องไว้ เราจึงไม่สามารถให้ IP ภายนอก "สีขาว" แก่เครื่องเหล่านั้นได้ และ ให้ "สีเทา". ด้วยวิธีนี้เราจึงบันทึกบนพูล IP และรับประกันว่าจะปกป้องเครื่องจากการเข้าถึงจากภายนอก - ไม่มี IP ที่จะเข้าไปได้

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

ประเด็นที่ถกเถียงกันอยู่ก็คือในกรณีนี้ ลูกค้าเก็บการเชื่อมต่อน้อยลง. หากมี IP เดียวกันสำหรับเครื่องหลายเครื่อง - ด้วยโฮสต์เดียวกัน: pu.vk.com หรือ pp.vk.com เบราว์เซอร์ไคลเอนต์จะมีการจำกัดจำนวนคำขอพร้อมกันไปยังโฮสต์เดียว แต่ในช่วงเวลาที่มี HTTP/2 แพร่หลาย ฉันเชื่อว่าสิ่งนี้ไม่เกี่ยวข้องอีกต่อไป

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

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

ดวงอาทิตย์

ในเดือนกันยายน 2017 Oracle ซึ่งเคยซื้อ Sun มาก่อน ไล่พนักงานซันออกจำนวนมาก. เราสามารถพูดได้ว่าขณะนี้บริษัทหยุดอยู่ เมื่อเลือกชื่อสำหรับระบบใหม่ ผู้ดูแลระบบของเราตัดสินใจที่จะยกย่องความทรงจำของบริษัทนี้ และตั้งชื่อระบบใหม่ว่า Sun ในหมู่พวกเราเอง เราเรียกเธอว่า "ดวงอาทิตย์"

คำถามที่พบบ่อยเกี่ยวกับสถาปัตยกรรมและการทำงานของ VKontakte

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

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

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

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

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

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

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

แสงอาทิตย์จากภายใน

ย้อนกลับพร็อกซีบน nginx แคชใน RAM หรือบนดิสก์ Optane/NVMe ที่รวดเร็ว ตัวอย่าง: http://sun4-2.userapi.com/c100500/path — ลิงค์ไปยัง “ดวงอาทิตย์” ซึ่งตั้งอยู่ในภูมิภาคที่สี่ กลุ่มเซิร์ฟเวอร์ที่สอง โดยจะปิดไฟล์เส้นทางซึ่งจริงๆ แล้วอยู่บนเซิร์ฟเวอร์ 100500

แคช

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

คำถามที่พบบ่อยเกี่ยวกับสถาปัตยกรรมและการทำงานของ VKontakte

ด้านล่างนี้เป็นแผนผังเค้าโครง แคชระดับภูมิภาคมีประมาณ 20 คน เหล่านี้เป็นสถานที่ที่มีแคชและ "ดวงอาทิตย์" ซึ่งสามารถแคชการรับส่งข้อมูลผ่านตัวมันเองได้

คำถามที่พบบ่อยเกี่ยวกับสถาปัตยกรรมและการทำงานของ VKontakte

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

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

มันทำงานอย่างไร

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

ในเวลาเดียวกันปีศาจ - บริการในภูมิภาค - มาที่ API เป็นครั้งคราวและพูดว่า: "ฉันเป็นแคชเช่นนี้ขอรายชื่อไฟล์ยอดนิยมในภูมิภาคของฉันที่ยังไม่มีให้ฉัน ” API จัดส่งไฟล์จำนวนมากโดยจัดเรียงตามการให้คะแนน daemon จะดาวน์โหลดไฟล์ พาพวกเขาไปยังภูมิภาค และส่งไฟล์จากที่นั่น นี่คือความแตกต่างพื้นฐานระหว่าง pu/pp และ Sun จากแคช โดยให้ไฟล์ผ่านตัวเองทันที แม้ว่าไฟล์นี้จะไม่ได้อยู่ในแคช และแคชจะดาวน์โหลดไฟล์ไปที่ตัวมันเองก่อน จากนั้นจึงเริ่มส่งคืน

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

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

เราดูสถาปัตยกรรมทั่วไป

  • เซิร์ฟเวอร์ด้านหน้าที่ยอมรับคำขอ
  • แบ็กเอนด์ที่ประมวลผลคำขอ
  • พื้นที่เก็บข้อมูลที่ถูกปิดโดยผู้รับมอบฉันทะสองประเภท
  • แคชระดับภูมิภาค

มีอะไรหายไปจากแผนภาพนี้? แน่นอนว่าฐานข้อมูลที่เราเก็บข้อมูล

ฐานข้อมูลหรือเครื่องยนต์

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

คำถามที่พบบ่อยเกี่ยวกับสถาปัตยกรรมและการทำงานของ VKontakte

นี่เป็นมาตรการที่จำเป็น. สิ่งนี้เกิดขึ้นเพราะในปี 2008-2009 เมื่อ VK ได้รับความนิยมเพิ่มขึ้นอย่างมาก โปรเจ็กต์นี้ทำงานได้บน MySQL และ Memcache ทั้งหมดและมีปัญหาเกิดขึ้น MySQL ชอบที่จะทำให้ไฟล์เสียหายและเสียหาย หลังจากนั้นจะไม่สามารถกู้คืนได้ และ Memcache ก็ค่อยๆ ลดประสิทธิภาพลงและต้องเริ่มต้นใหม่

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

การแก้ปัญหาประสบความสำเร็จ. มีโอกาสที่จะทำเช่นนี้ เช่นเดียวกับความจำเป็นอย่างยิ่ง เนื่องจากในขณะนั้นยังไม่มีวิธีการปรับขนาดแบบอื่น ฐานข้อมูลมีไม่มากนัก NoSQL ยังไม่มี มีเพียง MySQL, Memcache, PostrgreSQL เท่านั้นเอง

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

ประเภทของเครื่องยนต์

ทีมงานได้เขียนเครื่องยนต์จำนวนไม่น้อย นี่เป็นเพียงบางส่วนเท่านั้น: เพื่อน, คำใบ้, รูปภาพ, ipdb, ตัวอักษร, รายการ, บันทึก, memcached, meowdb, ข่าว, nostradamus, รูปภาพ, เพลย์ลิสต์, pmemcached, แซนด์บ็อกซ์, ค้นหา, ที่เก็บข้อมูล, ไลค์, งาน, ...

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

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

กลุ่ม

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

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

เพื่อให้สิ่งนี้ทำงานได้ คุณต้องเพิ่มเอนทิตีอีกหนึ่งรายการที่อยู่ระหว่างโค้ดและเอ็นจิ้น - หนังสือมอบฉันทะ.

พร็อกซี RPC

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

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

คำถามที่พบบ่อยเกี่ยวกับสถาปัตยกรรมและการทำงานของ VKontakte

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

การใช้งานเฉพาะ

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

สำหรับ MySQL ซึ่งเรายังมีที่นี่และที่นั่น เราใช้ db-proxy และสำหรับ ClickHouse - บ้านลูกแมว.

มันทำงานโดยทั่วไปเช่นนี้ มีเซิร์ฟเวอร์บางตัว มันรัน kPHP, Go, Python โดยทั่วไปคือโค้ดใดๆ ที่สามารถใช้โปรโตคอล RPC ของเราได้ รหัสทำงานภายในเครื่องบนพร็อกซี RPC - แต่ละเซิร์ฟเวอร์ที่มีรหัสอยู่จะเรียกใช้พร็อกซีในเครื่องของตัวเอง เมื่อมีการร้องขอ พร็อกซีจะเข้าใจว่าจะต้องไปที่ไหน

คำถามที่พบบ่อยเกี่ยวกับสถาปัตยกรรมและการทำงานของ VKontakte

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

ตัวอย่างของ TL-scheme ตามที่เครื่องยนต์ทั้งหมดทำงาน

memcache.not_found                                = memcache.Value;
memcache.strvalue	value:string flags:int = memcache.Value;
memcache.addOrIncr key:string flags:int delay:int value:long = memcache.Value;

tasks.task
    fields_mask:#
    flags:int
    tag:%(Vector int)
    data:string
    id:fields_mask.0?long
    retries:fields_mask.1?int
    scheduled_time:fields_mask.2?int
    deadline:fields_mask.3?int
    = tasks.Task;
 
tasks.addTask type_name:string queue_id:%(Vector int) task:%tasks.Task = Long;

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

RPC ผ่าน TL ผ่าน TCP/UDP… UDP?

เรามีโปรโตคอล RPC สำหรับดำเนินการคำขอกลไกที่ทำงานบนแผน TL ทั้งหมดนี้ทำงานผ่านการเชื่อมต่อ TCP/UDP TCP เป็นสิ่งที่เข้าใจได้ แต่ทำไมเราถึงต้องการ UDP บ่อยครั้ง

UDP ช่วยได้ หลีกเลี่ยงปัญหาการเชื่อมต่อจำนวนมากระหว่างเซิร์ฟเวอร์. หากแต่ละเซิร์ฟเวอร์มีพร็อกซี RPC และโดยทั่วไปสามารถไปที่กลไกใดก็ได้ แสดงว่ามีการเชื่อมต่อ TCP นับหมื่นต่อเซิร์ฟเวอร์ มีภาระแต่ก็ไม่มีประโยชน์ ในกรณีของ UDP ปัญหานี้ไม่มีอยู่

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

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

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

การจัดเก็บข้อมูลอย่างต่อเนื่อง

เครื่องยนต์เขียน binlogs. binlog คือไฟล์ที่ส่วนท้ายของเหตุการณ์สำหรับการเปลี่ยนแปลงสถานะหรือข้อมูลที่ถูกเพิ่มเข้าไป ในโซลูชันต่าง ๆ มันถูกเรียกแตกต่างกัน: บันทึกไบนารี WAL, อฟแต่หลักการก็เหมือนกัน

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

ฉันจะอธิบายหลักการทำงานอย่างรวดเร็ว มีเซิร์ฟเวอร์ที่เครื่องยนต์ทำงาน เขาเปิด Binlog เปล่าอันใหม่เพื่อเขียนและเขียนกิจกรรมเพื่อเปลี่ยนแปลง

คำถามที่พบบ่อยเกี่ยวกับสถาปัตยกรรมและการทำงานของ VKontakte

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

คำถามที่พบบ่อยเกี่ยวกับสถาปัตยกรรมและการทำงานของ VKontakte

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

คำถามที่พบบ่อยเกี่ยวกับสถาปัตยกรรมและการทำงานของ VKontakte

อ่านตำแหน่งที่อยู่ในขณะที่สร้างสแน็ปช็อตและขนาดของ binlog

คำถามที่พบบ่อยเกี่ยวกับสถาปัตยกรรมและการทำงานของ VKontakte

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

การจำลองข้อมูล

ส่งผลให้มีการจำลองข้อมูลในตัวเรา ตามคำสั่ง — เราเขียนใน binlog ว่าไม่มีการเปลี่ยนแปลงหน้าใดๆ แต่กล่าวคือ เปลี่ยนแปลงคำขอ. คล้ายกันมากกับสิ่งที่มาจากเครือข่าย ปรับเปลี่ยนเพียงเล็กน้อยเท่านั้น

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

คำถามที่พบบ่อยเกี่ยวกับสถาปัตยกรรมและการทำงานของ VKontakte

หากมีความจำเป็น การจำลองการอ่านเพื่อลดภาระการอ่าน CPU เอ็นจิ้นการอ่านจะถูกเปิดใช้งาน ซึ่งจะอ่านจุดสิ้นสุดของ binlog และดำเนินการคำสั่งเหล่านี้ในเครื่อง

ความล่าช้าที่นี่มีน้อยมาก และเป็นไปได้ที่จะทราบว่าแบบจำลองล่าช้ากว่าต้นแบบมากน้อยเพียงใด

การแบ่งส่วนข้อมูลในพร็อกซี RPC

การแบ่งส่วนทำงานอย่างไร พร็อกซีเข้าใจได้อย่างไรว่าคลัสเตอร์คลัสเตอร์ใดที่จะส่งไป รหัสไม่ได้บอกว่า: “ส่ง 15 ชิ้นส่วน!” - ไม่ สิ่งนี้จะกระทำโดยผู้รับมอบฉันทะ

รูปแบบที่ง่ายที่สุดคืออันดับแรก — หมายเลขแรกในคำขอ

get(photo100_500) => 100 % N.

นี่คือตัวอย่างสำหรับโปรโตคอลข้อความ memcached แบบธรรมดา แต่แน่นอนว่า การสืบค้นอาจซับซ้อนและมีโครงสร้างได้ ตัวอย่างใช้ตัวเลขแรกในแบบสอบถามและส่วนที่เหลือเมื่อหารด้วยขนาดคลัสเตอร์

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

หากเราไม่สนใจว่าคำขอจะกระจายไปทั่วทั้งคลัสเตอร์อย่างไร ก็ยังมีอีกทางเลือกหนึ่ง - แฮชทั้งส่วน.

hash(photo100_500) => 3539886280 % N

เรายังได้รับแฮช ส่วนที่เหลือของการหาร และหมายเลขชาร์ดอีกด้วย

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

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

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

คำถามที่พบบ่อยเกี่ยวกับสถาปัตยกรรมและการทำงานของ VKontakte

บันทึก

เราเขียนบันทึกได้หลายวิธี สิ่งที่ชัดเจนและเรียบง่ายที่สุดคือ เขียนบันทึกลงใน memcache.

ring-buffer: prefix.idx = line

มีคำนำหน้าคีย์ - ชื่อของบันทึก บรรทัด และขนาดของบันทึกนี้ - จำนวนบรรทัด เราใช้ตัวเลขสุ่มตั้งแต่ 0 ถึงจำนวนบรรทัดลบ 1 คีย์ใน memcache คือคำนำหน้าที่ต่อกับตัวเลขสุ่มนี้ เราบันทึกบรรทัดบันทึกและเวลาปัจจุบันเป็นค่า

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

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

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

การรวบรวมบันทึกใน ClickHouse

แผนภาพนี้แสดงวิธีที่เราเดินเข้าไปในเครื่องยนต์ของเรา

คำถามที่พบบ่อยเกี่ยวกับสถาปัตยกรรมและการทำงานของ VKontakte

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

  • แทนที่เครื่องยนต์ด้วย ClickHouse
  • แทนที่พร็อกซี RPC ซึ่งไม่สามารถเข้าถึง ClickHouse ด้วยวิธีแก้ปัญหาบางอย่างที่สามารถทำได้และผ่าน RPC

เอ็นจิ้นนั้นเรียบง่าย - เราแทนที่มันด้วยเซิร์ฟเวอร์หรือคลัสเตอร์ของเซิร์ฟเวอร์ด้วย ClickHouse

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

คำถามที่พบบ่อยเกี่ยวกับสถาปัตยกรรมและการทำงานของ VKontakte

บางครั้งเราไม่ต้องการใช้แผน RPC ในโซลูชันที่ไม่ได้มาตรฐาน เช่น ใน nginx ดังนั้น KittyHouse จึงมีความสามารถในการรับบันทึกผ่าน UDP

คำถามที่พบบ่อยเกี่ยวกับสถาปัตยกรรมและการทำงานของ VKontakte

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

การตรวจสอบ

เรามีบันทึกสองประเภท: บันทึกที่รวบรวมโดยผู้ดูแลระบบบนเซิร์ฟเวอร์และบันทึกที่เขียนโดยนักพัฒนาจากโค้ด ซึ่งสอดคล้องกับเมตริก XNUMX ประเภท: ระบบและผลิตภัณฑ์.

ตัวชี้วัดของระบบ

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

ตัวชี้วัดผลิตภัณฑ์

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

statlogsCountEvent   ( ‘stat_name’,            $key1, $key2, …)
statlogsUniqueCount ( ‘stat_name’, $uid,    $key1, $key2, …)
statlogsValuetEvent  ( ‘stat_name’, $value, $key1, $key2, …)

$stats = statlogsStatData($params)

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

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

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

คำถามที่พบบ่อยเกี่ยวกับสถาปัตยกรรมและการทำงานของ VKontakte

หากจำเป็น เราสามารถเขียนถึงผู้รวบรวมบันทึกได้โดยตรง

คำถามที่พบบ่อยเกี่ยวกับสถาปัตยกรรมและการทำงานของ VKontakte

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

ถัดไป นักสะสมบันทึกจะรวมสถิติเข้าด้วยกัน เหมียวDB - นี่คือฐานข้อมูลของเรา ซึ่งสามารถจัดเก็บหน่วยวัดได้เช่นกัน

คำถามที่พบบ่อยเกี่ยวกับสถาปัตยกรรมและการทำงานของ VKontakte

จากนั้นเราสามารถทำการเลือกไบนารี่ "ใกล้ SQL" จากโค้ดได้

คำถามที่พบบ่อยเกี่ยวกับสถาปัตยกรรมและการทำงานของ VKontakte

การทดลอง

ในช่วงฤดูร้อนปี 2018 เรามีแฮ็กกาธอนภายใน และมีแนวคิดเกิดขึ้นเพื่อพยายามแทนที่ส่วนสีแดงของไดอะแกรมด้วยสิ่งที่สามารถจัดเก็บหน่วยวัดใน ClickHouse เรามีบันทึกใน ClickHouse - ทำไมไม่ลองล่ะ?

คำถามที่พบบ่อยเกี่ยวกับสถาปัตยกรรมและการทำงานของ VKontakte

เรามีโครงการที่เขียนบันทึกผ่าน KittyHouse

คำถามที่พบบ่อยเกี่ยวกับสถาปัตยกรรมและการทำงานของ VKontakte

เราตัดสินใจแล้ว เพิ่ม "*House" อีกอันลงในไดอะแกรมซึ่งจะได้รับหน่วยวัดในรูปแบบตามที่โค้ดของเราเขียนผ่าน UDP จากนั้น *House นี้จะเปลี่ยนพวกมันให้กลายเป็นส่วนแทรก เหมือนท่อนไม้ ซึ่ง KittyHouse เข้าใจ เขาสามารถส่งบันทึกเหล่านี้ไปยัง ClickHouse ได้อย่างสมบูรณ์แบบ ซึ่งควรจะสามารถอ่านได้

คำถามที่พบบ่อยเกี่ยวกับสถาปัตยกรรมและการทำงานของ VKontakte

รูปแบบที่มีฐานข้อมูล memcache, stats-daemon และ logs-collectors จะถูกแทนที่ด้วยฐานข้อมูลนี้

คำถามที่พบบ่อยเกี่ยวกับสถาปัตยกรรมและการทำงานของ VKontakte

รูปแบบที่มีฐานข้อมูล memcache, stats-daemon และ logs-collectors จะถูกแทนที่ด้วยฐานข้อมูลนี้

  • มีการจัดส่งจากโค้ดที่นี่ ซึ่งเขียนขึ้นในเครื่องใน StatsHouse
  • StatsHouse เขียนการวัด UDP ซึ่งแปลงเป็นส่วนแทรก SQL แล้วเป็น KittenHouse เป็นกลุ่ม
  • KittyHouse ส่งพวกมันไปที่ ClickHouse
  • หากเราต้องการอ่าน เราก็อ่านได้โดยข้าม StatsHouse - โดยตรงจาก ClickHouse โดยใช้ SQL ปกติ

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

โครงการนี้ ไม่ประหยัดเหล็ก. จำเป็นต้องใช้เซิร์ฟเวอร์น้อยลง ไม่จำเป็นต้องใช้ stats-daemons และ logs-collector ในเครื่อง แต่ ClickHouse ต้องการเซิร์ฟเวอร์ที่ใหญ่กว่าเซิร์ฟเวอร์ในรูปแบบปัจจุบัน จำเป็นต้องใช้เซิร์ฟเวอร์น้อยลง แต่ต้องมีราคาแพงกว่าและมีประสิทธิภาพมากกว่า.

ปรับใช้

ก่อนอื่น มาดูการติดตั้ง PHP กันก่อน เรากำลังพัฒนาใน คอมไพล์: ใช้ GitLab и TeamCity สำหรับการปรับใช้ สาขาการพัฒนาจะผสานเข้ากับสาขาหลัก จากสาขาหลักสำหรับการทดสอบจะรวมเข้าเป็นการแสดงระยะ และจากการแสดงละครเป็นการใช้งานจริง

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

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

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

  • สาขา git master;
  • ไบนารีเข้า หญิงที่เข้าสังคมครั้งแรก;
  • เวอร์ชันนี้เขียนเป็น binlog copyfast;
  • จำลองแบบไปยังเซิร์ฟเวอร์
  • เซิร์ฟเวอร์ดึง .dep ใหม่ออกมา
  • dpkg -i;
  • การเปิดตัวเวอร์ชันใหม่อย่างสง่างาม

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

ลิงค์ที่เป็นประโยชน์

Alexey Akulovich เป็นหนึ่งในผู้ที่ช่วยเหลือในฐานะส่วนหนึ่งของคณะกรรมการโครงการ PHP รัสเซีย ในวันที่ 17 พฤษภาคม จะกลายเป็นงานที่ใหญ่ที่สุดสำหรับนักพัฒนา PHP ในช่วงเวลาที่ผ่านมา ดูสิว่าเรามีพีซีเจ๋งๆ อะไรสักอย่าง ลำโพง (สองคนกำลังพัฒนาแกน PHP!) - ดูเหมือนเป็นสิ่งที่คุณไม่ควรพลาดหากคุณเขียน PHP

ที่มา: will.com

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