1.1 ชาร์ดดิ้งคืออะไร?
หากคุณใช้ Google อย่างต่อเนื่อง ปรากฎว่ามีเส้นขอบที่ค่อนข้างเบลอระหว่างการแบ่งพาร์ติชันและการแบ่งส่วนที่เรียกว่า ทุกคนเรียกอะไรก็ได้ตามใจต้องการ บางคนแยกความแตกต่างระหว่างการแบ่งพาร์ติชันในแนวนอนและการแบ่งส่วนย่อย คนอื่นบอกว่าการแบ่งส่วนเป็นการแบ่งพาร์ติชันในแนวนอนบางประเภท
ฉันไม่พบมาตรฐานคำศัพท์เดียวที่จะได้รับการอนุมัติจากบรรพบุรุษผู้ก่อตั้งและได้รับการรับรองโดย ISO ความเชื่อมั่นภายในส่วนบุคคลเป็นเช่นนี้: การแบ่งพาร์ติชันโดยเฉลี่ยคือการ "ตัดฐานออกเป็นชิ้น ๆ " ด้วยวิธีที่ไม่ได้ตั้งใจ
- การแบ่งพาร์ติชันในแนวตั้ง - ตามคอลัมน์ ตัวอย่างเช่น มีตารางขนาดยักษ์ที่มีข้อมูลสองพันล้านรายการใน 60 คอลัมน์ แทนที่จะเก็บตารางขนาดยักษ์ไว้เพียงตารางเดียว เราเก็บตารางขนาดยักษ์อย่างน้อย 60 ตาราง แต่ละรายการมีข้อมูล 2 พันล้านรายการ และนี่ไม่ใช่ฐานคอลัมน์ แต่เป็นการแบ่งพาร์ติชันตามแนวตั้ง (เป็นตัวอย่างของคำศัพท์เฉพาะ)
- การแบ่งพาร์ติชันในแนวนอน - เราตัดทีละบรรทัดอาจอยู่ในเซิร์ฟเวอร์
ช่วงเวลาที่น่าอึดอัดคือความแตกต่างเล็กน้อยระหว่างการแบ่งพาร์ติชันในแนวนอนและการแบ่งส่วนย่อย ฉันสามารถหั่นเป็นชิ้นๆ ได้ แต่ฉันไม่สามารถบอกคุณได้แน่ชัดว่ามันคืออะไร มีความรู้สึกว่าการแบ่งส่วนย่อยและการแบ่งพาร์ติชันในแนวนอนเป็นเรื่องเดียวกัน
โดยทั่วไป Shardingคือเมื่อตารางขนาดใหญ่ในแง่ของฐานข้อมูลหรือการรวบรวมเอกสาร วัตถุ หากคุณไม่มีฐานข้อมูลแต่มีที่เก็บเอกสาร จะถูกตัดออกโดยวัตถุ นั่นคือจากวัตถุ 2 พันล้านชิ้น ไม่ว่าจะมีขนาดใดก็ตามจะถูกเลือก วัตถุภายในวัตถุแต่ละชิ้นไม่ได้ถูกตัดออกเป็นชิ้น ๆ เราไม่ได้จัดวางเป็นคอลัมน์แยกกัน กล่าวคือเราจัดวางเป็นชุด ๆ ในที่ต่าง ๆ
มีความแตกต่างทางคำศัพท์เล็กน้อย ตัวอย่างเช่น นักพัฒนา Postgres สามารถพูดได้ว่าการแบ่งพาร์ติชันในแนวนอนคือการที่ตารางทั้งหมดซึ่งแบ่งตารางหลักอยู่ในสคีมาเดียวกัน และเมื่ออยู่บนเครื่องต่างๆ การแบ่งส่วนนี้จะถูกแบ่งไว้แล้ว
ในความหมายทั่วไป หากไม่เชื่อมโยงกับคำศัพท์ของฐานข้อมูลเฉพาะและระบบการจัดการข้อมูลเฉพาะ มีความรู้สึกว่าการชาร์ดดิ้งเป็นเพียงการแบ่งส่วนบรรทัดต่อบรรทัด / เอกสารต่อเอกสารและอื่น ๆ - นั่นคือทั้งหมด
ฉันเน้นทั่วไป ในแง่ที่ว่าเรากำลังทำทั้งหมดนี้ ไม่ใช่แค่เพื่อตัดเอกสาร 2 พันล้านรายการออกเป็น 20 ตาราง ซึ่งแต่ละตารางจะสามารถจัดการได้มากขึ้น แต่เพื่อแจกจ่ายผ่านคอร์จำนวนมาก ดิสก์จำนวนมาก หรือเซิร์ฟเวอร์จริงหรือเซิร์ฟเวอร์เสมือนที่แตกต่างกันจำนวนมาก
1.2 การแบ่งส่วนที่แบ่งแยกไม่ได้
เป็นที่เข้าใจกันว่าเราทำเพื่อให้แต่ละชาร์ด - ข้อมูลแต่ละส่วน - ถูกจำลองซ้ำหลายครั้ง แต่จริงๆ ไม่
INSERT INTO docs00
SELECT * FROM documents WHERE (id%16)=0
...
INSERT INTO docs15
SELECT * FROM documents WHERE (id%16)=15
ในความเป็นจริง หากคุณทำการแบ่งส่วนข้อมูลดังกล่าว และจากตาราง SQL ขนาดยักษ์หนึ่งตารางบน MySQL บนแล็ปท็อปตัวเก่งของคุณ คุณจะสร้างตารางขนาดเล็กได้ 16 ตาราง โดยไม่เกินแล็ปท็อปเครื่องเดียว ไม่ใช่สคีมาเดียว ไม่ใช่ฐานข้อมูลเดียว ฯลฯ . และอื่น ๆ - แค่นั้นแหละ คุณมีชาร์ดดิ้งแล้ว
ส่งผลให้ต่อไปนี้:
- แบนด์วิธเพิ่มขึ้น
- เวลาในการตอบสนองไม่เปลี่ยนแปลง กล่าวคือ ในกรณีนี้ พนักงานหรือผู้บริโภคแต่ละคนได้รับของตัวเอง คำขอที่แตกต่างกันจะได้รับบริการในเวลาเดียวกัน
- หรือทั้งสองอย่าง และอีกอย่าง และมีความพร้อมใช้งานสูง (การจำลองแบบ)
ทำไมต้องแบนด์วิธ? บางครั้งเราอาจมีปริมาณข้อมูลที่ไม่พอดี - ไม่ชัดเจนว่าอยู่ที่ไหน แต่ไม่พอดี - ใน 1 {เคอร์เนล | ดิสก์ | เซิร์ฟเวอร์ | ...}. มีทรัพยากรไม่เพียงพอ นั่นคือทั้งหมด เพื่อที่จะทำงานกับชุดข้อมูลขนาดใหญ่นี้ คุณต้องตัดมันออก
ทำไมต้องแฝง? ในหนึ่งคอร์ การสแกนตารางที่มี 2 พันล้านแถวช้ากว่าการสแกน 20 ตารางบน 20 คอร์ถึง 20 เท่า โดยทำแบบคู่ขนานกัน ข้อมูลได้รับการประมวลผลช้าเกินไปในทรัพยากรเดียว
ทำไมถึงมีความพร้อมใช้งานสูง หรือเราตัดข้อมูลเพื่อทำทั้งสองอย่างพร้อมกัน และทำสำเนาหลายชุดพร้อมกันในแต่ละชาร์ด - การจำลองแบบทำให้มีความพร้อมใช้งานสูง
1.3 ตัวอย่างง่ายๆ "วิธีการทำด้วยมือ"
การแบ่งกลุ่มตามเงื่อนไขสามารถตัดออกได้โดยใช้ตารางทดสอบ test.documents สำหรับเอกสาร 32 ฉบับ และสร้างตารางทดสอบ 16 ตารางจากตารางนี้ แต่ละเอกสารประมาณ 2 เอกสาร test.docs00, 01, 02, ..., 15
INSERT INTO docs00
SELECT * FROM documents WHERE (id%16)=0
...
INSERT INTO docs15
SELECT * FROM documents WHERE (id%16)=15
ทำไม? เนื่องจากเบื้องต้นเราไม่ทราบว่ามีการแจกจ่าย id อย่างไรหากรวมตั้งแต่ 1 ถึง 32 ก็จะมีเอกสาร 2 ฉบับพอดีมิฉะนั้นจะไม่ใช่
เราทำที่นี่ทำไม หลังจากที่เราทำตารางได้ 16 ตาราง เราสามารถ "คว้า" 16 รายการที่เราต้องการได้ ไม่ว่าเราจะตีอะไรก็ตาม เราสามารถขนานทรัพยากรเหล่านี้ได้ ตัวอย่างเช่น ถ้ามีพื้นที่ว่างในดิสก์ไม่เพียงพอ การแยกย่อยตารางเหล่านี้ในดิสก์แยกกันก็สมเหตุสมผล
น่าเสียดายที่ทั้งหมดนี้ไม่ฟรี ฉันสงสัยว่าในกรณีของมาตรฐาน SQL แบบบัญญัติ (ฉันไม่ได้อ่านมาตรฐาน SQL ซ้ำเป็นเวลานาน บางทีมันอาจจะไม่ได้รับการอัปเดตเป็นเวลานาน) ไม่มีไวยากรณ์ที่เป็นมาตรฐานอย่างเป็นทางการสำหรับการพูดกับเซิร์ฟเวอร์ SQL ใด ๆ : "เซิร์ฟเวอร์ SQL ที่รัก สร้าง 32 ชาร์ดให้ฉันและแบ่งเป็น 4 ดิสก์ แต่ในการใช้งานแต่ละครั้ง มักจะมีไวยากรณ์เฉพาะสำหรับการทำสิ่งเดียวกันโดยพื้นฐาน PostgreSQL มีกลไกสำหรับการแบ่งพาร์ติชัน MySQL มี MariaDB Oracle อาจทำทั้งหมดนี้มานานแล้ว
อย่างไรก็ตาม หากเราทำด้วยมือโดยไม่มีการสนับสนุนฐานข้อมูลและอยู่ในกรอบของมาตรฐาน เราจะจ่ายเงินแบบมีเงื่อนไขด้วยความซับซ้อนของการเข้าถึงข้อมูล . เมื่อมี SELECT * FROM เอกสาร WHERE id=123 ตอนนี้ 16 x SELECT * FROM docsXX และเป็นการดีถ้าเราพยายามรับการบันทึกด้วยคีย์ น่าสนใจกว่ามากหากเราพยายามบันทึกช่วงแรกๆ ตอนนี้ (หากเราเน้นว่าเป็นคนโง่และยังคงอยู่ในกรอบของมาตรฐาน) ผลลัพธ์ของ 16 SELECT * FROM เหล่านี้จะต้องรวมกันในแอปพลิเคชัน
การเปลี่ยนแปลงด้านประสิทธิภาพใดที่คุณคาดหวังได้
- โดยสัญชาตญาณ - เชิงเส้น
- ในทางทฤษฎี - sublinear เพราะกฎหมายของอัมดาห์ล
- ในทางปฏิบัติ อาจจะเกือบจะเป็นเส้นตรง อาจจะไม่ใช่ก็ได้
ในความเป็นจริงคำตอบที่ถูกต้องไม่เป็นที่รู้จัก ด้วยการประยุกต์ใช้เทคนิคการแบ่งย่อยอย่างชาญฉลาด คุณสามารถบรรลุการลดระดับเชิงเส้นในประสิทธิภาพของแอปพลิเคชันของคุณ และแม้แต่ DBA ก็ยังมาพร้อมกับโป๊กเกอร์ที่ร้อนแรง
มาดูกันว่าสิ่งนี้จะสำเร็จได้อย่างไร เป็นที่ชัดเจนว่าแค่ตั้งค่าเป็น PostgreSQL shards=16 แล้วมันก็ดับเอง มันไม่น่าสนใจ ลองคิดดูว่าเราจะทำให้แน่ใจว่าเราชะลอการแตกย่อยลง 16 เท่าคูณ 32 ได้อย่างไร สิ่งนี้น่าสนใจจากมุมมองของวิธีที่จะไม่ทำเช่นนี้
ความพยายามของเราในการเพิ่มความเร็วหรือลดความเร็วลงมักจะเป็นแบบคลาสสิกเสมอ - กฎหมายอัมดาห์ลแบบเก่าที่ดีซึ่งกล่าวว่าไม่มีคำขอใด ๆ ที่ขนานกันอย่างสมบูรณ์ มีบางส่วนที่สอดคล้องกันเสมอ
1.4 กฎหมายอัมดาห์ล
มีส่วนที่ต่อเนื่องกันเสมอ
มีส่วนหนึ่งของการดำเนินการคิวรีที่ขนานกันอยู่เสมอ และมีส่วนที่ไม่ได้ขนานกันอยู่เสมอ แม้ว่าคุณจะคิดว่าเป็นการสืบค้นแบบคู่ขนานที่สมบูรณ์แบบ แต่อย่างน้อยคอลเลกชันของแถวผลลัพธ์ที่คุณจะส่งไปยังไคลเอนต์จากแถวที่ได้รับจากแต่ละชาร์ดจะอยู่ที่นั่นเสมอ และจะเป็นลำดับเสมอ
มีส่วนที่สอดคล้องกันอยู่เสมอ อาจมีขนาดเล็กมองไม่เห็นอย่างสมบูรณ์เมื่อเทียบกับพื้นหลังทั่วไปอาจมีขนาดมหึมาและส่งผลต่อการขนานกันอย่างมาก แต่ก็มีอยู่เสมอ
นอกจากนี้ อิทธิพลของมันยังเปลี่ยนแปลงและสามารถเติบโตได้อย่างมาก เช่น ถ้าเราตัดโต๊ะ - มาเพิ่มเงินเดิมพันกันเถอะ - จาก 64 ระเบียนเป็น 16 ตารางจาก 4 ระเบียน ส่วนนี้จะเปลี่ยนไป แน่นอนว่าเมื่อพิจารณาจากข้อมูลจำนวนมหาศาล เรากำลังทำงานบนโทรศัพท์มือถือและโปรเซสเซอร์ 2 MHz 86 และเรามีไฟล์ไม่เพียงพอที่สามารถเปิดพร้อมกันได้ เห็นได้ชัดว่าเราเปิดไฟล์ทีละไฟล์ด้วยอินพุตดังกล่าว
- มันคือ Total = Serial + Parallel โดยที่ ตัวอย่างเช่น ขนานคืองานทั้งหมดภายในฐานข้อมูล และอนุกรมกำลังส่งผลลัพธ์ไปยังไคลเอนต์
- กลายเป็นTotal2 = Serial + Parallel/N + Xserial ตัวอย่างเช่น เมื่อ ORDER BY โดยรวม Xserial>0
ด้วยตัวอย่างง่ายๆ นี้ ฉันกำลังพยายามแสดงให้เห็นว่า Xserial บางตัวปรากฏขึ้น นอกเหนือจากข้อเท็จจริงที่ว่ามีส่วนที่ต่อเนื่องกันเสมอ และความจริงที่ว่าเรากำลังพยายามทำงานกับข้อมูลแบบขนาน ยังมีส่วนเพิ่มเติมเพื่อให้การแบ่งส่วนข้อมูลนี้ เราอาจต้อง:
- ค้นหา 16 ตารางเหล่านี้ในพจนานุกรมภายในของฐานข้อมูล
- เปิดไฟล์;
- จัดสรรหน่วยความจำ
- ยกเลิกการจัดสรรหน่วยความจำ
- รวมผล;
- ซิงโครไนซ์ระหว่างคอร์
เอฟเฟกต์ไม่ซิงค์บางส่วนยังคงปรากฏขึ้น อาจไม่มีนัยสำคัญและใช้เวลาหนึ่งในพันล้านของเวลาทั้งหมด แต่มักไม่เป็นศูนย์และอยู่ที่นั่นเสมอ ด้วยความช่วยเหลือของพวกเขา เราอาจสูญเสียประสิทธิภาพไปอย่างมากหลังจากการแบ่งส่วนย่อย
![](https://cdn.codegym.cc/images/article/271eab10-2784-46cd-bc06-65a0aa0211c7/1024.jpeg)
นี่เป็นภาพมาตรฐานเกี่ยวกับกฎของอัมดาห์ล สิ่งสำคัญที่นี่คือเส้น ซึ่งควรจะเป็นเส้นตรงและเป็นเชิงเส้น แต่เนื่องจากกราฟจากอินเทอร์เน็ตไม่สามารถอ่านได้ ฉันจึงสร้างตารางที่มองเห็นได้มากขึ้นด้วยตัวเลข
สมมติว่าเรามีบางส่วนของการประมวลผลคำขอที่ใช้เวลาเพียง 5%: serial = 0.05 = 1 / 20
ตามสัญชาตญาณ ดูเหมือนว่าด้วยส่วนที่ต่อเนื่องกันซึ่งใช้เวลาเพียง 1/20 ของการประมวลผลคำขอ หากเราประมวลผลคำขอแบบขนานสำหรับ 20 คอร์ มันจะกลายเป็นประมาณ 20 คอร์ ในกรณีที่เลวร้ายที่สุด 18 เร็วกว่าเท่าตัว
อันที่จริงคณิตศาสตร์เป็นสิ่งที่ไร้หัวใจ :
ผนัง = 0.05 + 0.95/num_cores, เร่งความเร็ว = 1 / (0.05 + 0.95/num_cores)
ปรากฎว่าหากคุณคำนวณอย่างรอบคอบด้วยส่วนที่ต่อเนื่องกัน 5% การเร่งความเร็วจะเป็น 10 เท่า (10.3) ซึ่งเท่ากับ 51% เมื่อเทียบกับอุดมคติทางทฤษฎี
8 คอร์ | = 5.9 | = 74% |
10 คอร์ | = 6.9 | = 69% |
20 คอร์ | = 10.3 | = 51% |
40 คอร์ | = 13.6 | = 34% |
128 คอร์ | = 17.4 | = 14% |
เมื่อใช้ 20 คอร์ (20 ดิสก์ถ้าคุณต้องการ) สำหรับงานที่เคยทำงานเราจะไม่ได้รับการเร่งความเร็วเกิน 20 เท่าในทางทฤษฎี แต่ในทางปฏิบัติ - น้อยกว่ามาก ยิ่งไปกว่านั้น เมื่อจำนวนคู่ขนานเพิ่มขึ้น ความไร้ประสิทธิภาพก็เพิ่มขึ้นอย่างมาก
เมื่อเหลืองานต่อเนื่องเพียง 1% และ 99% ถูกต่อขนานกัน ค่าเร่งความเร็วจะดีขึ้นเล็กน้อย:
8 คอร์ | = 7.5 | = 93% |
16 คอร์ | = 13.9 | = 87% |
32 คอร์ | = 24.4 | = 76% |
64 คอร์ | = 39.3 | = 61% |
สำหรับการสืบค้นทางเทอร์โมนิวเคลียร์อย่างสมบูรณ์แบบ ซึ่งโดยปกติจะใช้เวลาหลายชั่วโมงจึงจะเสร็จสมบูรณ์ และงานเตรียมการและการประกอบผลลัพธ์ใช้เวลาน้อยมาก (อนุกรม = 0.001) เราจะเห็นประสิทธิภาพที่ดีอยู่แล้ว:
8 คอร์ | = 7.94 | = 99% |
16 คอร์ | = 15.76 | = 99% |
32 คอร์ | = 31.04 | = 97% |
64 คอร์ | = 60.20 | = 94% |
โปรดทราบว่าเราจะไม่เห็น 100% . ในกรณีที่ดีเป็นพิเศษ คุณสามารถดูได้ เช่น 99.999% แต่ไม่ใช่ 100%