18 คะแนน โดย xguru 2024-02-05 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • Apple ใช้ Cassandra และ FoundationDB สำหรับ iCloud และ CloudKit
  • ฐานข้อมูลเหล่านี้จัดเก็บฐานข้อมูลได้หลายพันล้านรายการภายใต้สถาปัตยกรรมมัลติเทนเนนซีระดับสุดขั้ว

บทเรียนจากโลกจริงที่ใช้ได้เสมอ

  • ทั้ง Meta และ Apple ต่างใช้ การประมวลผลแบบอะซิงโครนัส เพื่อให้ฟีเจอร์สำหรับผู้ใช้ทำงานได้อย่างราบรื่น
  • ทั้งสองบริษัทใช้สถาปัตยกรรมแบบ stateless เพื่อแก้ปัญหาด้านการขยายระบบ
  • แยกทรัพยากรเชิงตรรกะเพื่อให้ได้ความน่าเชื่อถือและความพร้อมใช้งาน
  • จัดการความต้องการที่หลากหลายให้เรียบง่าย
  • สร้างชั้น abstraction เพื่อปรับปรุงประสบการณ์ของนักพัฒนา
  • รู้จักผู้ใช้และกำหนดแต่ละเลเยอร์, API และการออกแบบตามนั้น

Cassandra

  • Cassandra เป็นระบบจัดการฐานข้อมูล NoSQL แบบคอลัมน์กว้าง
  • เดิมพัฒนาขึ้นที่ Facebook เพื่อใช้กับฟีเจอร์ค้นหาใน inbox ของ Facebook
    • ที่น่าสนใจคือ Meta เองได้แทนที่การใช้งาน Cassandra ส่วนใหญ่ด้วย ZippyDB
  • iCloud ใช้ Cassandra บางส่วน และ Apple ดำเนินการดีพลอย Cassandra ที่ใหญ่ที่สุดแห่งหนึ่งของโลก
    • มากกว่า 300,000 อินสแตนซ์/โหนด
    • ข้อมูลหลายร้อยเพตะไบต์
    • มากกว่า 2 เพตะไบต์ต่อคลัสเตอร์
    • คิวรีหลายล้านครั้งต่อวินาที
    • แอปพลิเคชันหลายพันรายการ
  • Cassandra ยังถูกพัฒนาและปรับปรุงอย่างต่อเนื่องภายใน Apple
  • อย่างไรก็ตาม CloudKit + Cassandra ชนข้อจำกัดด้านการขยายระบบ จึงหันมาใช้ FoundationDB

FoundationDB

  • Apple ใช้งาน FoundationDB อย่างเปิดเผย และเข้าซื้อกิจการในปี 2015
  • FoundationDB เป็นที่เก็บคีย์-ค่าแบบทรานแซกชันกระจายตัวโอเพนซอร์สที่ออกแบบมาสำหรับจัดการข้อมูลขนาดใหญ่
    • เหมาะทั้งกับเวิร์กโหลดการอ่าน/เขียนและเวิร์กโหลดที่เน้นการเขียนหนัก
  • Apple ใช้ FoundationDB Record Layer อย่างกว้างขวางใน CloudKit
  • FoundationDB Record Layer มี Java API สำหรับการจัดเก็บข้อมูลแบบมีโครงสร้าง
  • Record Layer รองรับมัลติเทนเนนซีระดับสุดขั้ว

ทำไม FoundationDB จึงใช้ Record Layer

  • FoundationDB จัดการงานด้านระบบกระจายและการควบคุมภาวะพร้อมกัน
  • Record Layer ทำหน้าที่เสมือนฐานข้อมูลเชิงสัมพันธ์ที่ทำให้ FoundationDB ใช้งานง่ายขึ้น
  • CloudKit อยู่ในชั้นบนสุดและมอบฟังก์ชันกับ API สำหรับนักพัฒนาแอปพลิเคชัน
  • ผ่าน Record Layer ทำให้ Apple รองรับมัลติเทนเนนซีขนาดใหญ่ได้
    • ใช้กับมัลติเทนเนนซีระดับสุดขั้วที่ให้ record store แยกอิสระแก่ผู้ใช้แต่ละคนของแต่ละแอปพลิเคชัน
    • โฮสต์ฐานข้อมูลอิสระหลายพันล้านรายการที่แชร์สคีมาหลายพันแบบ

CloudKit ใช้ FoundationDB และ Record Layer อย่างไร

  • ใน CloudKit แอปพลิเคชันถูกแสดงเป็น 'logical container' ที่เป็นไปตามสคีมาที่กำหนดไว้
    • สคีมานี้สรุปประเภทเรคอร์ด ฟิลด์ และดัชนีที่จำเป็นสำหรับการค้นคืนข้อมูลและการคิวรีอย่างมีประสิทธิภาพ
    • แอปพลิเคชันสามารถจัดข้อมูลเป็น 'โซน' ภายใน CloudKit เพื่อจัดกลุ่มเรคอร์ดเชิงตรรกะและซิงก์กับอุปกรณ์ไคลเอนต์ได้ตามต้องการ
  • ผู้ใช้แต่ละคนจะได้รับ subspace เฉพาะภายใน FoundationDB และจะมีการสร้าง record store สำหรับแต่ละแอปพลิเคชันที่ผู้ใช้นั้นโต้ตอบด้วย
    • โดยพื้นฐานแล้ว CloudKit จัดการฐานข้อมูลเชิงตรรกะจำนวนมหาศาล เท่ากับจำนวนผู้ใช้คูณจำนวนแอปพลิเคชัน
    • แต่ละฐานข้อมูลมีชุดเรคอร์ด ดัชนี และเมทาดาทาของตัวเอง จนรวมกันเป็นฐานข้อมูลหลายพันล้านรายการ
  • เมื่อ CloudKit รับคำขอจากอุปกรณ์ไคลเอนต์ ระบบจะส่งคำขอนั้นไปยังโปรเซสบริการ CloudKit ที่พร้อมใช้งานผ่านการทำโหลดบาลานซ์
    • โปรเซสนั้นจะโต้ตอบกับ record store ของ Record Layer ที่เกี่ยวข้องเพื่อประมวลผลคำขอ
  • CloudKit แปลงสคีมาแอปพลิเคชันที่กำหนดไว้เป็นคำนิยามเมทาดาทาภายใน Record Layer ซึ่งเก็บไว้ใน metadata store แยกต่างหาก
    • เมทาดาทานี้ถูกเสริมด้วย system field เฉพาะของ CloudKit ที่ติดตามเวลาในการสร้างและแก้ไขเรคอร์ด รวมถึงโซนที่เก็บเรคอร์ดนั้น
    • เพื่อให้เข้าถึงเรคอร์ดภายในแต่ละโซนได้อย่างมีประสิทธิภาพ คีย์หลักจะถูกเติมชื่อโซนนำหน้าไว้
    • นอกจากดัชนีที่ผู้ใช้กำหนดแล้ว CloudKit ยังดูแล 'system index' สำหรับงานภายใน เช่น การจัดการโควตาสโตเรจ โดยติดตามขนาดของเรคอร์ดแยกตามประเภท

การใช้ FoundationDB ร่วมกับ Record Layer ช่วยแก้ปัญหาสำคัญ 4 ข้อของ Apple ที่ Cassandra เพียงอย่างเดียวแก้ไม่ได้

1. แก้ปัญหาการค้นหาแบบ full-text ที่ปรับให้เหมาะกับแต่ละบุคคล

  • FoundationDB รองรับการค้นหาแบบ full-text ที่ปรับให้เหมาะกับผู้ใช้แต่ละคน เพื่อให้ผู้ใช้เข้าถึงข้อมูลของตนเองได้อย่างรวดเร็ว
  • ด้วยการใช้ลำดับคีย์ของ FoundationDB ระบบจึงค้นหาจุดเริ่มต้นของข้อความได้อย่างรวดเร็ว (การจับคู่แบบ prefix) และยังทำการค้นหาที่ซับซ้อนขึ้นได้โดยไม่มีโอเวอร์เฮดเพิ่มเติม เช่น การค้นหาแบบ proximity และ phrase search ที่ต้องหาคำซึ่งอยู่ใกล้กันหรืออยู่ในลำดับที่กำหนด
  • ในระบบค้นหาแบบเดิมมักต้องรันโปรเซสเพิ่มเติมเบื้องหลังเพื่อทำให้ดัชนีค้นหาทันสมัยอยู่เสมอ แต่ระบบของ Apple จัดการทุกอย่างแบบเรียลไทม์ ดังนั้นเมื่อข้อมูลเปลี่ยน ดัชนีค้นหาก็อัปเดตทันทีโดยไม่ต้องมีขั้นตอนเพิ่ม

2. แก้ปัญหาโซนที่มีความพร้อมกันสูง

  • CloudKit ใช้ FoundationDB เพื่อจัดการอัปเดตจำนวนมากที่เกิดขึ้นพร้อมกันได้อย่างราบรื่น
  • ก่อนหน้านี้เมื่อใช้ Cassandra นั้น CloudKit พึ่งพาดัชนีพิเศษที่ติดตามการเปลี่ยนแปลงของแต่ละโซนเพื่อซิงก์ข้อมูลข้ามหลายอุปกรณ์
    • เมื่ออุปกรณ์ต้องอัปเดตข้อมูล ก็จะตรวจสอบดัชนีนี้เพื่อดูว่ามีอะไรใหม่
    • แต่ข้อเสียคือหากมีการอัปเดตหลายรายการพร้อมกัน อาจเกิดความขัดแย้งได้
  • เมื่อใช้ FoundationDB CloudKit จะใช้ดัชนีชนิดพิเศษที่ติดตามลำดับที่แน่นอนของแต่ละการเปลี่ยนแปลงโดยไม่ก่อให้เกิดความขัดแย้ง
    • ทำได้โดยกำหนด 'เวอร์ชัน' ที่ไม่ซ้ำกันให้กับทุกการเปลี่ยนแปลง และเมื่อจำเป็นต้องซิงก์ CloudKit จะตรวจสอบเวอร์ชันเหล่านี้เพื่อดูว่าอุปกรณ์พลาดอัปเดตใดไปบ้าง
  • หาก CloudKit ต้องย้ายข้อมูลระหว่างคลัสเตอร์สตอเรจหลายชุดเพื่อกระจายภาระให้สม่ำเสมอขึ้น สถานการณ์จะซับซ้อนขึ้นเพราะหมายเลขเวอร์ชันของแต่ละคลัสเตอร์ไม่ตรงกัน
    • เพื่อแก้ปัญหานี้ CloudKit จะกำหนด 'จำนวนครั้งที่ย้าย' ให้กับข้อมูลของผู้ใช้แต่ละคน (เรียกว่า 'incarnation') ซึ่งจะเพิ่มขึ้นทุกครั้งที่ข้อมูลถูกส่งไปยังคลัสเตอร์ใหม่
    • การอัปเดตเรคอร์ดแต่ละครั้งจะมีหมายเลข 'incarnation' ปัจจุบันของผู้ใช้อยู่ด้วย ดังนั้นแม้หลังย้ายแล้ว CloudKit ก็ยังตรวจสอบทั้ง incarnation และหมายเลขเวอร์ชันเพื่อหาลำดับอัปเดตที่ถูกต้องได้
  • เมื่อต้องเปลี่ยนไปใช้ระบบใหม่ CloudKit ต้องเผชิญปัญหาในการจัดการข้อมูลเก่าที่ไม่มีหมายเลขเวอร์ชันเหล่านี้
    • แต่ระบบก็แก้ปัญหาอย่างชาญฉลาดด้วยฟังก์ชันพิเศษที่จัดเรียงการอัปเดตเก่าจากระบบเดิมให้อยู่ก่อนการอัปเดตของระบบใหม่
    • ทำให้ไม่ต้องแก้แอปให้ซับซ้อนหรือคงโค้ดเก่าไว้
    • โดยพิจารณาทั้งค่า incarnation, เวอร์ชัน และตัวนับการอัปเดตแบบเก่าเพื่อรักษาลำดับประวัติที่ถูกต้อง

3. แก้ปัญหาคิวรีที่มี latency สูง

  • FoundationDB ถูกออกแบบมาเพื่อรองรับ concurrency สูงมากกว่าการมี latency ต่ำ กล่าวคือเน้นให้ระบบรับงานจำนวนมากพร้อมกันได้ แทนที่จะโฟกัสความเร็วของงานเดี่ยว
  • เพื่อใช้ประโยชน์จากการออกแบบนี้ให้เต็มที่ Record Layer จึงทำงานจำนวนมากแบบ 'อะซิงโครนัส'
    • โดยนำงานที่จะเสร็จในภายหลังเข้าไปไว้ในคิว และใช้เวลาระหว่างนั้นทำงานอื่นต่อได้
    • แนวทางนี้ช่วยกลบ latency ที่อาจเกิดขึ้นระหว่างงานเหล่านี้
  • อย่างไรก็ตาม เครื่องมือที่ FoundationDB ใช้สื่อสารกับฐานข้อมูลถูกออกแบบให้ใช้เธรดเดียวสำหรับงานเครือข่าย จึงทำงานได้ทีละอย่าง
    • ในเวอร์ชันก่อนหน้า การตั้งค่านี้ทำให้เกิดคอขวด เพราะทุกงานต้องรอคิวบน network thread นี้
    • เนื่องจาก Record Layer ใช้แนวทางเธรดเดียวนี้อยู่ จึงเกิดปัญหาคอขวด
  • เพื่อปรับปรุง Apple จึงลดภาระงานของ network thread นี้
    • ตอนนี้ระบบสามารถทำงานกับฐานข้อมูลพร้อมกันได้หลายด้านโดยไม่เกิดคิวสะสม ทำให้งานที่ซับซ้อนเร็วขึ้น
    • วิธีนี้ช่วยซ่อน latency หรือความช้าที่มองเห็นได้ เพราะระบบไม่ต้องรอให้งานหนึ่งเสร็จก่อนจึงเริ่มอีกงาน

4. แก้ปัญหาทรานแซกชันที่ขัดแย้งกัน

  • ใน FoundationDB 'transaction conflict' จะเกิดขึ้นเมื่อทรานแซกชันหนึ่งอ่านคีย์บางตัว ในขณะที่อีกทรานแซกชันแก้ไขคีย์เดียวกันพร้อมกัน
    • FoundationDB มีความสามารถในการควบคุมชุดคีย์ที่อาจก่อให้เกิดความขัดแย้งระหว่างการอ่านหรือเขียน ทำให้จัดการความขัดแย้งเหล่านี้ได้อย่างละเอียดแม่นยำ
  • วิธีทั่วไปในการหลีกเลี่ยงความขัดแย้งที่ไม่จำเป็น คือการใช้การอ่านชนิดพิเศษที่ไม่ก่อ conflict หรือ 'snapshot' read กับคีย์หลายตัว
    • หากการอ่านแบบนี้พบคีย์ที่สำคัญ ทรานแซกชันจะทำเครื่องหมายเฉพาะคีย์ที่อาจมีความขัดแย้ง แทนที่จะทำกับช่วงทั้งหมด
    • วิธีนี้ทำให้ทรานแซกชันได้รับผลกระทบเฉพาะจากการเปลี่ยนแปลงที่สำคัญต่อผลลัพธ์จริง ๆ
  • Record Layer ใช้กลยุทธ์นี้เพื่อจัดการโครงสร้างที่เรียกว่า skip list ซึ่งเป็นส่วนหนึ่งของระบบ rank index อย่างมีประสิทธิภาพ
    • อย่างไรก็ตาม การตั้งช่วง conflict เหล่านี้ด้วยตนเองอาจยุ่งยาก และโดยเฉพาะเมื่อปะปนกับลอจิกหลักของแอปพลิเคชัน ก็อาจนำไปสู่บั๊กที่ระบุได้ยาก
    • ดังนั้นในระบบที่สร้างบน FoundationDB จึงควรสร้างเครื่องมือระดับสูงกว่า เช่น custom index เพื่อจัดการรูปแบบเหล่านี้
    • แนวทางนี้ช่วยหลีกเลี่ยงการโยนภาระในการผ่อนคลายกฎ conflict ไปให้แอปพลิเคชันฝั่งไคลเอนต์แต่ละตัว ซึ่งอาจนำไปสู่ข้อผิดพลาดและความไม่สอดคล้องกันได้

1 ความคิดเห็น

 
xguru 2024-02-05

ความคิดเห็นจาก Hacker News

  • ผู้ใช้ Hacker News คนหนึ่งได้แบ่งปันมุมมองจากตอนที่ทำงานที่ Apple เกี่ยวกับความแตกต่างระหว่างฐานข้อมูลกับระบบไฟล์ โดยระบุว่าทั้งฐานข้อมูลและระบบไฟล์นั้นโดยพื้นฐานแล้วทำหน้าที่เดียวกัน และเป็นการปรับให้เหมาะกับการแก้ปัญหาเฉพาะด้าน ตัวอย่างเช่น iCloud แสดงให้เห็นวิธีนิยามระบบไฟล์บนพื้นฐานของฐานข้อมูล ผู้ใช้นี้ยังเล่าประสบการณ์การใช้ Cassandra เพื่อจัดเก็บวิดีโอด้วย

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

  • ผู้ใช้คนหนึ่งประเมินว่าฟีเจอร์ซิงก์ของ Apple Notes จัดการกับความขัดแย้งได้ดีกว่าแอปจดโน้ตที่อิง Markdown และบอกว่านี่คือเหตุผลที่ท้ายที่สุดย้ายมาใช้ Apple Notes

  • มีการกล่าวถึงโพสต์ก่อนหน้านี้เกี่ยวกับ FoundationDB ซึ่งรวมถึงลิงก์เกี่ยวกับ distributed key-value store ของ FoundationDB, record layer, การเข้าซื้อกิจการโดย Apple รวมถึงหลักการทำงานและคุณลักษณะของ FoundationDB

  • มีการกล่าวถึงแง่มุมที่น่าสนใจของสถาปัตยกรรมซอฟต์แวร์เดสก์ท็อปเนทีฟที่ค่อย ๆ ย้ายไปสู่การจัดเก็บบนคลาวด์และการทำงานร่วมกัน โดยการจัดการ schema change และ version migration ได้ดีเป็นสิ่งสำคัญ และสิ่งเหล่านี้เกิดขึ้นในวงกว้างโดยไม่ต้องมีผู้ดูแลเข้ามาแทรกแซง

  • ผู้ใช้คนหนึ่งหวังว่า iCloud จะสามารถเก็บข้อมูลสำรอง Time Machine ได้

  • เนื่องจาก FoundationDB มีพื้นฐานมาจาก SQLite จึงมีการตั้งคำถามว่าเอนจิน HCTree จะสามารถนำมาปรับใช้กับ FoundationDB ได้หรือไม่ โดย HCTree มีศักยภาพที่จะเพิ่มประสิทธิภาพการอ่าน/เขียนของ SQLite ได้ถึง 10 เท่า

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

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