Datasheet - Người Kế Nhiệm Của Sharedata - nói dối e blog

Datasheet - Người Kế Nhiệm Của Sharedata

Trong hệ sinh thái Skynet, module sharedata đã trở thành “trái tim” cho việc chia sẻ bảng dữ liệu giữa hàng chục dịch vụ. Ý tưởng cốt lõi xuất phát từ thực tế: khi bạn có hàng trăm dịch vụ chạy song song, việc nạp cùng một bảng dữ liệu chỉ đọc vào từng dịch vụ riêng biệt không chỉ gây lãng phí bộ nhớ, mà còn tạo ra “cơn ác mộng” khi cần cập nhật nóng dữ liệu. Tuy nhiên, qua nhiều năm vận hành, một số giới hạn của sharedata đã lộ rõ, khiến chúng tôi phải xây dựng giải pháp thay thế - datasheet.

Câu chuyện về “bộ nhớ chia sẻ” trong mơ

Một trong những kỳ vọng lớn nhất khi thiết kế sharedata là tạo ra cơ chế chia sẻ thật sự vùng nhớ vật lý. Nhưng thực tế phũ phàng hơn nhiều! Khi bạn nhìn vào cấu trúc dữ liệu dạng cây (tree structure) trong Lua, việc đóng gói các nút con thành các userdata để truy cập bằng cú pháp quen thuộc của Lua buộc mỗi máy ảo Lua phải tạo bản sao riêng của các cấu trúc phụ trợ. Điều này dẫn đến việc không thể chia sẻ hoàn toàn vùng nhớ như mong đợi.

Còn nếu dùng lightuserdata? Câu chuyện lại chuyển sang một ngã rẽ khác:

  • Bạn sẽ phải đau đầu với việc chia sẻ metatable giữa các lightuserdata
  • Và gần như bó tay với yêu cầu cập nhật nóng (hot update) vì lightuserdata không mang theo trạng thái có thể thay đổi.

Bài toán tối ưu: Giữa tốc độ và bộ nhớ

Sharedata cố gắng giải quyết bài toán bằng cách áp dụng cơ chế cache thông minh, nhưng chính nó lại dẫn đến phức tạp hơn. Một dự án từng phải xây thêm lớp cache thứ hai để bù đắp cho hiệu năng truy cập chậm khi phải gọi hàm metatable. Chúng tôi thậm chí phải thêm hàm deepcopy để sao chép dữ liệu từ sharedata sang table thông thường khi cần truy cập nhanh.

datasheet - Cách tiếp cận mới mẻ

Giải pháp mới mang tên datasheet được xây dựng dựa trên nguyên tắc:

  1. Chuyển toàn bộ dữ liệu phức tạp sang vùng nhớ C
  2. Cho phép nhiều máy ảo Lua truy cập chia sẻ vùng nhớ này

Nhưng không phải bất kỳ dữ liệu nào cũng được chấp nhận. Datasheet áp dụng hai quy tắc nghiêm ngặt:

  • Khóa chỉ có thể là chuỗi hoặc số nguyên dương liên tục (kiểu mảng)
  • Không cho phép kiểu dữ liệu phức tạp làm khóa

Cơ chế “nở hoa” thông minh

Điểm đặc biệt nhất của datasheet là cơ chế khởi tạo lười biếng (lazy initialization):

  • Khi dịch vụ A truy cập một bảng con lần đầu, datasheet sẽ sao chép toàn bộ cấp độ 1 của bảng này vào bộ nhớ Lua
  • Nếu có bảng con lồng trong cấp độ 1, datasheet chỉ tạo một bảng trống với metatable để kích hoạt quá trình mở rộng khi cần

Kết quả? Khi bạn truy cập dữ liệu lần hai trở đi, hoàn toàn không có bất kỳ overhead nào từ metatable hay hàm gọi - nhanh như truy cập table thông thường!

Vòng đời dữ liệu được quản lý thông minh

Từ khâu xây dựng dữ liệu đến cập nhật nóng đều được thiết kế lại:

  • datasheet.builder phụ trách chuyển đổi dữ liệu Lua sang vùng nhớ C
  • Mỗi bảng con được đánh dấu bằng một ID duy nhất
  • Khi cập nhật nóng, hệ thống so sánh sự khác biệt giữa phiên bản cũ và mới, cố gắng giữ nguyên các ID không thay đổi
  • Các dịch vụ chỉ cần cập nhật con trỏ vùng nhớ C và xóa cache, toàn bộ dữ liệu sẽ tự động “trổ hoa” lại khi truy cập tiếp

Bản phát hành chính thức

Datasheet đã chính thức được merge vào nhánh master của Skynet với tư cách là module độc lập. Giao diện API giữ nhiều điểm tương thích với sharedata, giúp các dự án dễ dàng chuyển đổi. Trong tương lai gần, nó sẽ trở thành lựa chọn mặc định trong bản phát hành Skynet 1.1. Các bạn có thể thử nghiệm từ hôm nay và góp phần hoàn thiện giải pháp này!

0%