18 điểm bởi xguru 2024-02-05 | 1 bình luận | Chia sẻ qua WhatsApp
  • Apple sử dụng Cassandra và FoundationDB cho iCloud và CloudKit
  • Các cơ sở dữ liệu này lưu trữ hàng tỷ cơ sở dữ liệu trong một kiến trúc multi-tenancy cực đoan

Những bài học thực tế có giá trị vượt thời gian

  • Cả Meta và Apple đều sử dụng xử lý bất đồng bộ để giúp các tính năng người dùng hoạt động mượt mà
  • Cả hai công ty đều sử dụng kiến trúc stateless để giải quyết các vấn đề về khả năng mở rộng
  • Cô lập tài nguyên ở mức logic để đảm bảo độ tin cậy và tính sẵn sàng
  • Xử lý nhiều yêu cầu khác nhau theo cách đơn giản
  • Xây dựng các lớp trừu tượng để cải thiện trải nghiệm của nhà phát triển
  • Hiểu người dùng và quyết định từng lớp, API và thiết kế dựa trên điều đó

Cassandra

  • Cassandra là một hệ quản trị cơ sở dữ liệu NoSQL dạng cột phân tán quy mô lớn
  • Ban đầu được phát triển tại Facebook cho tính năng tìm kiếm trong hộp thư Facebook
    • Điều thú vị là bản thân Meta hiện đã thay thế phần lớn việc sử dụng Cassandra bằng ZippyDB ZippyDB
  • iCloud sử dụng một phần Cassandra, và Apple đang vận hành một trong những triển khai Cassandra lớn nhất thế giới
    • Hơn 300.000 instance/node
    • Hàng trăm petabyte dữ liệu
    • Hơn 2 petabyte mỗi cụm
    • Hàng triệu truy vấn mỗi giây
    • Hàng nghìn ứng dụng
  • Cassandra vẫn đang được Apple tích cực cải tiến
  • Tuy nhiên, CloudKit + Cassandra đã chạm tới giới hạn mở rộng và vì thế Apple đã áp dụng FoundationDB

FoundationDB

  • Apple công khai sử dụng FoundationDB và đã mua lại nó vào năm 2015
  • FoundationDB là một kho khóa-giá trị giao dịch phân tán mã nguồn mở được thiết kế để xử lý dữ liệu quy mô lớn
    • Phù hợp cho cả workload đọc/ghi lẫn workload thiên về ghi
  • Apple sử dụng rộng rãi FoundationDB Record Layer trong CloudKit
  • FoundationDB Record Layer cung cấp Java API cho việc lưu trữ dữ liệu có cấu trúc
  • Record Layer hỗ trợ multi-tenancy ở mức cực đoan

Vì sao dùng Record Layer trên FoundationDB

  • FoundationDB xử lý các tác vụ về hệ thống phân tán và kiểm soát đồng thời.
  • Record Layer đóng vai trò như một cơ sở dữ liệu quan hệ giúp FoundationDB dễ sử dụng hơn.
  • CloudKit nằm ở lớp trên cùng, cung cấp các tính năng và API cho nhà phát triển ứng dụng.
  • Thông qua Record Layer, Apple hỗ trợ multi-tenancy ở quy mô lớn
    • Được dùng cho mô hình multi-tenancy cực đoan, nơi mỗi người dùng của mỗi ứng dụng có một kho bản ghi độc lập
    • Lưu trữ hàng tỷ cơ sở dữ liệu độc lập dùng chung hàng nghìn schema

Cách CloudKit sử dụng FoundationDB và Record Layer

  • Trong CloudKit, ứng dụng được biểu diễn như các “logical container” tuân theo schema đã định nghĩa
    • Schema này mô tả ngắn gọn các loại bản ghi, trường và chỉ mục cần thiết để truy xuất và truy vấn dữ liệu hiệu quả
    • Ứng dụng có thể tổ chức dữ liệu thành các “zone” trong CloudKit để nhóm bản ghi một cách logic và có thể đồng bộ tùy chọn với thiết bị khách
  • Mỗi người dùng được gán một subspace riêng trong FoundationDB, và một kho bản ghi được tạo cho từng ứng dụng mà người dùng tương tác
    • Về cơ bản, CloudKit quản lý một số lượng khổng lồ cơ sở dữ liệu logic bằng số người dùng nhân với số ứng dụng
    • Mỗi cơ sở dữ liệu chứa bộ bản ghi, chỉ mục và metadata riêng, nâng tổng số lên tới hàng tỷ cơ sở dữ liệu
  • Khi CloudKit nhận yêu cầu từ thiết bị khách, nó dùng cân bằng tải để chuyển yêu cầu này tới một tiến trình dịch vụ CloudKit khả dụng
    • Tiến trình đó xử lý yêu cầu bằng cách tương tác với record store tương ứng trong Record Layer
  • CloudKit chuyển schema ứng dụng đã định nghĩa thành các định nghĩa metadata trong Record Layer, được lưu trong một kho metadata riêng biệt
    • Metadata này được bổ sung bằng các trường hệ thống riêng của CloudKit để theo dõi thời điểm tạo, sửa bản ghi và zone nơi bản ghi được lưu
    • Khóa chính được gắn tiền tố bằng tên zone để có thể truy cập hiệu quả các bản ghi trong từng zone
    • Cùng với các chỉ mục do người dùng định nghĩa, CloudKit còn duy trì các “system index” cho mục đích nội bộ, như theo dõi kích thước bản ghi theo từng loại để quản lý hạn ngạch lưu trữ

Việc dùng FoundationDB cùng Record Layer giúp giải quyết 4 vấn đề lớn của Apple mà chỉ Cassandra thì không thể xử lý

1. Giải quyết bài toán tìm kiếm toàn văn được cá nhân hóa

  • FoundationDB hỗ trợ tìm kiếm toàn văn được cá nhân hóa để người dùng có thể truy cập nhanh dữ liệu của mình
  • Bằng cách tận dụng thứ tự khóa của FoundationDB, hệ thống có thể tìm nhanh phần đầu văn bản (so khớp tiền tố), đồng thời cũng thực hiện được các tìm kiếm phức tạp hơn mà không có thêm overhead, như tìm kiếm lân cận và tìm kiếm cụm từ
  • Trong nhiều hệ thống tìm kiếm truyền thống, thường phải chạy thêm các tiến trình nền để cập nhật chỉ mục tìm kiếm, nhưng hệ thống của Apple xử lý mọi thứ theo thời gian thực nên chỉ mục được cập nhật ngay khi dữ liệu thay đổi, không cần thêm bước bổ sung

2. Giải quyết bài toán zone có mức đồng thời cao

  • CloudKit dùng FoundationDB để xử lý trơn tru rất nhiều cập nhật diễn ra đồng thời
  • Trước đây khi dùng Cassandra, CloudKit phụ thuộc vào một chỉ mục đặc biệt theo dõi thay đổi của từng zone để đồng bộ dữ liệu giữa nhiều thiết bị
    • Khi thiết bị cần cập nhật dữ liệu, nó kiểm tra chỉ mục này để xem nội dung mới
    • Nhưng nếu nhiều cập nhật xảy ra cùng lúc thì có thể phát sinh xung đột
  • Với FoundationDB, CloudKit sử dụng một loại chỉ mục đặc biệt có thể theo dõi chính xác thứ tự của từng thay đổi mà không gây xung đột
    • Điều này được thực hiện bằng cách gán một “version” duy nhất cho mỗi thay đổi, và khi cần đồng bộ, CloudKit kiểm tra các version này để biết thiết bị đã bỏ lỡ những cập nhật nào
  • Khi CloudKit cần di chuyển dữ liệu giữa nhiều cụm lưu trữ để phân phối tải đồng đều hơn, tình huống trở nên phức tạp vì số version của mỗi cụm không khớp nhau
    • Để giải quyết việc này, CloudKit gán cho dữ liệu của mỗi người dùng một “số lần di chuyển” (gọi là “incarnation/hóa thân”), và con số này tăng lên mỗi khi dữ liệu được chuyển sang cụm mới
    • Mỗi lần cập nhật bản ghi đều chứa số “hóa thân” hiện tại của người dùng, nên ngay cả sau khi di chuyển, CloudKit vẫn có thể xác định đúng thứ tự cập nhật bằng cách kiểm tra cả hóa thân lẫn version
  • Khi chuyển sang hệ thống mới, CloudKit phải xử lý dữ liệu cũ không có các số version này
    • Tuy nhiên, họ đã khéo léo vượt qua vấn đề bằng một tính năng đặc biệt cho phép sắp các cập nhật cũ từ hệ thống trước đứng trước các cập nhật của hệ thống mới
    • Nhờ vậy, không cần thay đổi ứng dụng theo cách phức tạp hay giữ lại mã cũ
    • Để duy trì đúng thứ tự lịch sử, hệ thống xét tới giá trị hóa thân, version và bộ đếm cập nhật cũ

3. Giải quyết bài toán truy vấn độ trễ cao

  • FoundationDB được thiết kế cho mức đồng thời cao hơn là độ trễ thấp. Nghĩa là nó tập trung vào khả năng xử lý nhiều tác vụ cùng lúc thay vì tối ưu tốc độ của từng tác vụ riêng lẻ
  • Để tận dụng tối đa thiết kế này, Record Layer thực hiện nhiều tác vụ theo cách “bất đồng bộ”
    • Đưa các tác vụ sẽ hoàn thành trong tương lai vào hàng đợi và cho phép xử lý các việc khác trong lúc chờ
    • Cách tiếp cận này giúp che đi độ trễ có thể phát sinh trong quá trình đó
  • Tuy nhiên, công cụ mà FoundationDB dùng để giao tiếp với cơ sở dữ liệu được thiết kế chỉ dùng một luồng cho networking, nghĩa là chỉ xử lý một việc tại một thời điểm
    • Ở các phiên bản trước, cấu hình này gây tắc nghẽn vì mọi tác vụ đều phải xếp hàng chờ trên luồng mạng đó
    • Vì Record Layer cũng sử dụng cách tiếp cận một luồng này nên đã tạo ra nút thắt cổ chai
  • Để cải thiện, Apple đã giảm khối lượng công việc của luồng mạng này
    • Giờ đây hệ thống có thể làm việc với cơ sở dữ liệu ở nhiều khía cạnh cùng lúc mà không hình thành hàng đợi, nên các tác vụ phức tạp chạy nhanh hơn
    • Điều này giúp che giấu độ trễ hoặc cảm giác chậm đi vì hệ thống không phải chờ một tác vụ hoàn tất rồi mới bắt đầu việc khác

4. Giải quyết bài toán transaction xung đột

  • Trong FoundationDB, “xung đột transaction” xảy ra khi một transaction đọc một khóa cụ thể trong khi một transaction khác đồng thời sửa khóa đó
    • FoundationDB cung cấp cơ chế kiểm soát chính xác tập khóa có thể gây ra xung đột khi đọc hoặc ghi, nhờ đó có thể quản lý các xung đột này một cách tinh vi
  • Một cách phổ biến để tránh xung đột không cần thiết là dùng một kiểu đọc đặc biệt không gây xung đột, gọi là đọc “snapshot”, trên nhiều khóa khác nhau
    • Nếu trong quá trình đọc này phát hiện ra khóa quan trọng, transaction chỉ đánh dấu khóa cụ thể có khả năng xung đột thay vì đánh dấu toàn bộ phạm vi
    • Cách này giúp transaction chỉ bị ảnh hưởng bởi những thay đổi thực sự quan trọng với kết quả của nó
  • Record Layer sử dụng chiến lược này để quản lý hiệu quả một cấu trúc gọi là skip list, vốn là một phần của hệ thống chỉ mục xếp hạng
    • Tuy nhiên, việc tự thiết lập thủ công các phạm vi xung đột này có thể khá phức tạp và dễ dẫn đến các lỗi khó phát hiện, đặc biệt khi trộn lẫn với logic chính của ứng dụng
    • Vì vậy, trong các hệ thống xây dựng trên FoundationDB, tốt hơn nên tạo ra các công cụ cấp cao hơn như custom index để xử lý các mẫu này
    • Cách tiếp cận này giúp tránh tình huống trách nhiệm nới lỏng các quy tắc xung đột bị đẩy xuống từng ứng dụng khách, điều có thể dẫn đến sai sót và thiếu nhất quán

1 bình luận

 
xguru 2024-02-05

Ý kiến trên Hacker News

  • Một người dùng Hacker News chia sẻ góc nhìn về sự khác biệt giữa cơ sở dữ liệu và hệ thống tệp từ thời gian làm việc tại Apple. Người này cho rằng cơ sở dữ liệu và hệ thống tệp về cơ bản thực hiện cùng một chức năng, và chỉ là các tối ưu hóa để giải quyết những bài toán cụ thể. Ví dụ, iCloud cho thấy cách định nghĩa một hệ thống tệp dựa trên cơ sở dữ liệu. Người này cũng chia sẻ kinh nghiệm dùng Cassandra để lưu trữ video.

  • Một người dùng khác nhắc đến kinh nghiệm xây dựng hệ thống catalog có tính giao dịch tại công ty cũ bằng FoundationDB và RecordLayer. Hệ thống này hoạt động rất hiệu quả, và việc sử dụng gRPC cùng Protobuf là điều tự nhiên. Tuy nhiên, người này chỉ ra nhược điểm là rào cản gia nhập để vận hành FoundationDB ở quy mô lớn khá cao.

  • Một người dùng đánh giá tính năng đồng bộ của Apple Notes xử lý xung đột tốt hơn các ứng dụng ghi chú dựa trên Markdown. Vì vậy, cuối cùng họ đã chuyển sang Apple Notes.

  • Các bài đăng trước đây về FoundationDB cũng được nhắc đến. Chúng bao gồm các liên kết về kho key-value phân tán của FoundationDB, Record Layer, thương vụ Apple mua lại công ty, cũng như nguyên lý hoạt động và các đặc điểm của FoundationDB.

  • Có ý kiến cho rằng kiến trúc của phần mềm desktop native đang dần chuyển sang lưu trữ và cộng tác dựa trên đám mây là một điểm rất thú vị. Việc xử lý tốt thay đổi schema và migration phiên bản là rất quan trọng, vì điều này diễn ra ở quy mô lớn mà không có sự can thiệp của quản trị viên.

  • Một người dùng mong iCloud có thể lưu các bản sao lưu Time Machine.

  • Vì FoundationDB dựa trên SQLite, có người đặt câu hỏi liệu engine HCTree có thể được áp dụng cho FoundationDB hay không. HCTree có tiềm năng cải thiện hiệu năng đọc/ghi của SQLite lên gấp 10 lần.

  • Có ý kiến phàn nàn về cách iCloud quản lý tệp của người dùng. Đôi khi việc iCloud tự động chuyển các tệp, ứng dụng và ảnh được dùng gần đây lên đám mây để giải phóng dung lượng lại gây ra vấn đề.

  • Một người dùng hồi tưởng về hệ thống báo cáo tên là Hyperion mà họ từng dùng khi làm việc tại một ngân hàng trong quá khứ. Hệ thống này tạo ra một cơ sở dữ liệu mới cho mỗi báo cáo; khi đó điều này có vẻ kỳ lạ, nhưng nhìn lại thì họ cho rằng đó là một cách làm đi trước thời đại.