Kho Tài Nguyên Và Nâng Cấp Hệ Thống Phát Hành - nói dối e blog

Kho Tài Nguyên Và Nâng Cấp Hệ Thống Phát Hành

Vào cuối năm ngoái, tôi đã thiết kế kiến trúc kho tài nguyên cho engine 3D của chúng tôi.
Sau đó giao cho một thành viên trong nhóm phát triển triển khai, hệ thống này đã được sử dụng trong nửa năm qua. Gần đây, qua việc nghiệm thu nội bộ phiên bản nhỏ của engine, tôi nhận thấy vẫn còn nhiều điểm cần cải tiến. Hiện tại, hệ thống quản lý tập tin tài nguyên bị trộn lẫn với chức năng cập nhật tài nguyên trực tuyến trong giai đoạn phát triển, trong khi phần mạng vẫn tồn tại một số lỗi nhỏ, thỉnh thoảng gây treo chương trình. Việc định vị các lỗi này tốn nhiều công sức, tôi quyết định tái thiết kế lại mô-đun này, kết hợp luôn các ý tưởng cải tiến mới.

Trong thời gian qua, tôi đã suy nghĩ lại về cách thiết kế kho tài nguyên sao cho tối ưu. Khi càng đi sâu vào chi tiết, tôi càng nhận thấy đây chính là vấn đề mà Git đã giải quyết thành công. Một tính năng quan trọng của engine chúng tôi là khả năng phát triển trên PC nhưng chạy và gỡ lỗi trên thiết bị di động. Việc đồng bộ tài nguyên lên thiết bị là nhu cầu lặp đi lặp lại, và nguyên lý này rất giống với cơ chế hoạt động của Git. Thật vậy, cấu trúc dữ liệu trên hệ thống tệp tin cục bộ mà chúng tôi xây dựng lần này cũng tương tự như cách tổ chức kho dữ liệu của Git.

Trong lần tái thiết kế này, chúng tôi loại bỏ sự khác biệt trong cách xử lý thư mục và tập tin. Thay vào đó, mọi thứ đều được chia thành các khối dữ liệu có tên là mã băm (hash) của chính nội dung đó. Kho tài nguyên giờ đây đơn giản là một cơ sở dữ liệu key-value, với tên tập tin chính là giá trị SHA1 của nội dung, được lưu trong thư mục kho. Để tránh việc một thư mục chứa quá nhiều tập tin (điều này gây bất tiện cho đa số hệ thống tệp tin), dữ liệu được phân tán vào tối đa 256 thư mục con thông qua băm giá trị nội dung.

Một tập tin nguyên bản giữ nguyên nội dung gốc, trong khi thư mục chứa thông tin chỉ mục được xây dựng riêng. Tôi sử dụng định dạng văn bản để lưu trữ thông tin này: mỗi dòng mô tả một đối tượng với các thông tin: loại (dành cho thư mục là d, tập tin là f), mã băm, và tên. Ví dụ về cấu trúc chỉ mục một thư mục như sau:

1
2
d 10a34637ad661d98ba3344717656fcc76209c2f8 f0
f da39a3ee5e6b4b0d3255bfef95601890afd80709 f0_1.txt

Điều này cho thấy thư mục này chứa một thư mục con tên f0 và tập tin f0_1.txt. Bất kỳ thay đổi nào trong tập tin con đều làm thay đổi mã băm của chỉ mục thư mục chứa nó, dẫn đến thay đổi mã băm của các thư mục cha. Nói cách khác, mọi chỉnh sửa nhỏ nhất trong kho tài nguyên đều lan truyền lên chỉ mục gốc.

Về giao diện lập trình, tôi chỉ cung cấp các chức năng cơ bản: truy vấn dữ liệu qua mã băm, cập nhật con trỏ chỉ mục gốc (một giá trị mã băm), tìm mã băm của đối tượng từ đường dẫn văn bản. Nhờ các con trỏ gốc khác nhau, nhiều phiên bản lịch sử có thể tồn tại trong cùng một kho, đồng thời tối đa hóa việc tái sử dụng dữ liệu chung giữa các phiên bản. Ở phía máy chủ/PC Editor, chúng tôi chỉ cần cung cấp chức năng xây dựng lại chỉ mục bằng cách duyệt đệ quy từ gốc, tạo ra các tập tin chỉ mục cho từng thư mục.

Khác với Git, chúng tôi không bắt buộc sao chép dữ liệu từ hệ thống tệp tin cục bộ (khu vực làm việc của Git) vào kho. Thay vào đó, chúng tôi tạo các tập tin tham chiếu với định dạng tên *.hash.ref, cho biết giá trị mã băm này không chứa dữ liệu thực mà trỏ đến tập tin bên ngoài. Nội dung của tập tin tham chiếu bao gồm đường dẫn, mã băm, và dấu thời gian của tập tin gốc. Vì nhiều tập tin có thể có nội dung trùng nhau, một tập tin tham chiếu có thể trỏ đến nhiều đường dẫn khác nhau, mỗi đường dẫn được ghi trên một dòng riêng biệt. Khi cần phục hồi dữ liệu, hệ thống sẽ lần lượt kiểm tra các đường dẫn cho đến khi tìm thấy bản còn hiệu lực.

Trong quá trình xây dựng lại chỉ mục nhanh, nếu gặp tập tin tham chiếu, hệ thống chỉ so sánh dấu thời gian. Nếu thời gian không đổi, không cần tính lại mã băm, tiết kiệm thời gian xử lý.

Khi chạy theo kiến trúc client-server, trên thiết bị di động trước tiên sẽ tạo một kho gương (mirror) rỗng, đồng bộ kho tài nguyên từ PC. Quy trình hoạt động như sau:

  1. Khi khởi động, máy khách gửi yêu cầu lấy mã băm chỉ mục gốc từ máy chủ, sau đó đặt giá trị này làm gốc trong kho gương cục bộ.
  2. Mỗi khi yêu cầu một tập tin, máy khách sẽ truy ngược từ gốc để tìm chỉ mục tương ứng. Nếu dữ liệu đã có trong kho gương, hệ thống sử dụng trực tiếp. Ngược lại, yêu cầu sẽ được gởi lên máy chủ để lấy các khối dữ liệu thiếu.

Giao diện lập trình cho phép mở một tài nguyên bằng cách trả về trực tiếp tập tin hoặc mã băm thiếu. Khi nhận được mã băm, mô-đun mạng sẽ yêu cầu dữ liệu tương ứng. Sau khi nhận được, không cần biết nội dung cụ thể, hệ thống chỉ cần ghi vào kho gương và lặp lại quy trình yêu cầu ban đầu cho đến khi mở được tài nguyên.

Điểm tinh tế của phương pháp này là không cần quản lý phiên bản bằng số hiệu, vẫn có thể xử lý hoàn hảo các vấn đề đa phiên bản. Quá trình đồng bộ chỉ yêu cầu bắt buộc một bước duy nhất là đồng bộ mã băm gốc. Nếu thiết bị có nhiều phiên bản khác nhau (ví dụ khi chuyển đổi giữa các máy của lập trình viên khác nhau), sau khi đồng bộ gốc, không cần bất kỳ truyền tải mạng nào nữa. Quy trình này nhanh hơn cả việc chuyển phiên bản trong Git, bởi chúng tôi không có khái niệm khu vực làm việc, không cần sao chép tập tin

0%