+8

Haystack - Cách facebook lưu trữ hàng tỷ bức ảnh

Thời buổi hiện nay, chắc hẳn ai chúng ta cũng có ít nhất 1 tài khoản facebook. Một chức năng cơ bản nhất của nó là cho phép tải lên hình ảnh. Trong bài viết chúng ta sẽ cùng đi tìm hiểu cách mà facebook lưu trữ đống ảnh khổng lồ đó.

Mở đầu

Năm 2009 số lượng ảnh người dùng tải lên Facebook là 15 triệu. Ở thời điểm đó mỗi bức ảnh được tải lên họ sẽ tạo ra các kích thước khác nhau và lưu trữ tương đương với 60 tỷ bức ảnh và 1.5PB dung lượng lưu trữ. Con số này vẫn tiếp tục tăng trưởng 220 triệu mỗi tuần tương ứng khoảng 25TB tiêu thụ. Lúc cao điểm có thể lên tới 550.000 bức ảnh mỗi giây. Những con số này đặt ra một thách thức cho cơ sở hạ tầng lưu trữ ảnh của Facebook.

NFS photo infrastructure (Cơ sở hạ tầng ảnh NFS)

Cơ sở hạ tầng cũ của họ gồm một số tầng:

  • Tầng upload nhận ảnh tải lên của người dùng và lưu xuống tầng lưu trữ NFS.
  • Tầng phụ vụ các yêu cầu HTTP của ảnh và phục vụ chúng từ tầng lưu trữ NFS.
  • Tầng lưu trữ NFS được xây dựng trên các thiết bị lưu trữ thương mại.

Vì mỗi ảnh được lưu trữ trong tệp riêng của nó, do đó sinh ra một lượng metadata khổng lồ trên tầng lưu trữ. Lượng dữ liệu metadata vượt quá khả năng lưu vào bộ nhớ đệm của tầng lưu trữ NFS, dẫn nhiều nhiều thao tác I/O cho mỗi yêu cầu đọc hoặc tải lên ảnh. Toàn bộ cơ sở hạ tầng tầng bị ảnh hưởng do chi phí metadata cao của tầng lưu trữ NFS. Đây là một trong những lý do tại sao Facebook phải phụ thuộc vào CDN để phục vụ ảnh.

Hai giải pháp tối ưu tạm thời được đưa ra để giảm thiểu vấn đề:

  • Cache: Tầng máy chủ lưu các ảnh profile nhỏ vào bộ nhớ đệm.
  • NFS file handle cache: Được triển khai trên tầng dịch vụ ảnh mục đích loại bỏ một số chi phí metadata của tầng lưu trữ NFS.

Đấy chỉ là những cách xử lý tạm thời họ cần một cơ sở hạ tầng mới đáp ứng được những con số khổng lồ phía trên.

Haystack Photo Infrastructure (Cơ sở hạ tầng ảnh Haystack)

Cơ sở hạ tầng ảnh mới hợp nhất tầng phục vụ ảnh và tầng lưu trữ thành một tầng vật lý. Nó triển khai một máy chủ ảnh dựa trên yêu cầu HTTP lưu trữ ảnh trong object store chung có tên là Haystack.

Yêu cầu chính là loại bỏ mọi chi phí metadata dư thừa cho các hoạt động đọc ảnh, sao cho mỗi thao tác đọc I/O chỉ đọc dữ liệu ảnh thực tế (thay vì hệ thống tệp metadata).

Haystack có thể chia thành các lớp như sau:

  • HTTP server
  • Photo Store
  • Haystack Object Store
  • Filesystem
  • Storage

Filesystem

Haystack object stores được triển khai trên các tệp được lưu trữ trong một hệ thống tệp duy nhất được tạo trên ổ đĩa 10TB. Các yêu cầu đọc ảnh dẫn đến các cuộc gọi hệ thống read() ở offsets đã biết trong các tệp này, nhưng để thực hiện các lần đọc, hệ thống tệp trước tiên phải định vị dữ liệu trên ổ đĩa vật lý thực tế (sẽ nói cụ thể ở phía dưới). Và họ chọn hệ thống tệp XFS.

XFS filesystem, nó tên là XFS luôn chứ không phải viết tắt của từ gì cả, là một journaling filesystem 64 bit với hiệu năng cao. XFS đã xuất hiện ở các Linux kernel vào năm 2001, cho tới tháng 06/2014 nó đã được hỗ trợ bởi hầu hết các Linux distribution, một vài trong số đó sử dụng XFS như là filesystem mặc định.

Một đặc tính quan trọng của XFS đó là khả năng bảo đảm tốc độ truy xuất dữ liệu cho các ứng dụng (Guaranteed Rate I/O), cho phép các ứng dụng duy trì được tốc độ truy xuất dữ liệu trên disk, rất quan trọng đối với các hệ thống phân phối dịch vụ video có độ phân giải cao hoặc các ứng dụng xử lý thông tin vệ tinh đòi hỏi duy trì ổn định tốc độ thao tác dữ liệu.

Haystack Object Store

Haystack là một cấu trúc log đơn giản (append-only) nghĩa là chỉ cho phép chèn thêm vào. Object store sẽ chứa các needle nó đại diện cho các đối tượng được lưu trữ.

Haystack gồm 2 file: 1 file để lưu trữ needle và 1 file index.

8kb đầu tiên của haystack store sẽ là của superblock. Sau đó là các needle gồm các phần header, data và footer.

  1. Header Magic Number + Footer Magic Number: Giúp định vị needle tiếp theo trong quá trình phục hồi file index.
  2. Cookie: Giúp client bảo mật chống tấn công brute force.
  3. Key: Giành 64-bit lưu giữ key
  4. Alternate key: Giành 32-bit lưu trữ alternate key.
  5. Flags: Đánh giấu needle đã bị xóa hay chưa. Tại vì đã nói ở trên haystack chỉ chèn thêm nên muốn xóa thì ta dựa vào thằng này.
  6. Size: Kích thước của data.
  7. Data checksum: Kiểm tra checksum của needle.
  8. Padding: Tổng kích thước của needle được biểu diễn thành 8 bytes.

Một needle được xác định duy nhất bởi <Offset, Key, Alternate Key, Cookie> của nó, trong đó offset là vị trí của needle trong Haystack store. Haystack không đưa ra bất kỳ hạn chế nào đối với giá trị của các khóa và có thể có các khóa trùng lặp.

Các thành phần của file index:

Mỗi bản ghi trong file index tương ứng mỗi needle trong tệp lưu trữ haystack và thứ tự các bản ghi index phải khớp với thứ tự của needle liên kết trong tệp lưu trữ haystack. Tệp index cung cấp các metadata tối thiểu đề định vị 1 needle trong haystack store.

Lưu ý là tệp index không quan trọng. Vì nó có thể được xây dựng lại từ tệp lưu trữ haystack nếu cần. Mục đích của nó là tải nhanh needle vào bộ nhớ mà đỡ phải lặp qua cái file haystack siêu to kia một cách nhanh chóng, vì file index thường nhỏ hơn 1% kích thước file lưu trữ kia.

Thao tác viết vào Haystack

Khi tệp được tải lên, hệ thống sẽ tạo ra needle tương ứng và nối đồng bộ vào tệp haystack store. Sau khi được lưu thành công nó sẽ lưu các metadata cần thiết của needle vào file index. Vì tệp index không quan trọng nên các bản ghi sẽ được ghi bất đồng bộ làm tăng hiệu suất. Trong trường hợp xảy ra sự cố, quy trình hồi phục sẽ loại bỏ các needle lỗi. Haystack không cho phép ghi đè lên vị trí needle hiện có. Để cập nhật ta sẽ ghi chèn 1 needle mới với cùng 1 bộ <Key, Alternate Key, Cookie> với thằng needle cũ, Sau đó khi đọc nó sẽ lấy thằng có vị trí lớn nhất.

Thao tác đọc từ Haystack

Truyền các tham số <Offset, Key, Alternate Key, Cookie> Haystack sau đó sẽ thêm header, footer và đọc toàn bộ needle từ tệp. Thao tác đọc chỉ thành công khi các tham số, checksum đều khớp và flags biểu hiện tệp chưa xóa.

Thao tác xóa trong Haystack

Nó đánh giấu needle trong haystack là đã bị xóa bằng cách đặt bit "đã xóa" trong trường flags của needle. Tuy nhiên, bản ghi index được liên kết không được sửa theo bất kì cách nào nên ứng dụng có thể kết thúc bằng việc tham chiếu đến 1 needle đã xóa. Nếu thao tác đọc thấy cờ "đã xóa" và thao tác thành công với một lỗi thích hợp. Khoảng trống đã xóa của needle sẽ không được lấy lại theo bất kì cách nào.

Tham khảo

Needle in a haystack: efficient storage of billions of photos


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí