Caching Without Marshal Part 1: Marshal from the Inside Out
Bài tóm tắt Shopify 2022 3. Quy mô lớn Độ khó: Trung bình
Shopify · 2022 · 3. Quy mô lớn · Độ khó: Trung bình — bài gốc
Phần 1 của hai phần; phần 2 Shopify 2022 kể cách migrate sang MessagePack. Phần lớn bài này mổ xẻ định dạng Marshal; wiki giữ phần sự cố và lý do.
Bối cảnh
- Mọi loại cache của Rails (trang, partial, query, low-level) dùng chung
read/writetrênRails.cache, và mọi backend (monolith lõi của Shopify dùng Memcached) đều serialize bằngMarshal.dump/Marshal.load. Hướng dẫn Rails nói cache "chứa được mọi loại thông tin". - Sự cố: một kỹ sư refactor vài class quanh beta flag trong monolith; PR được duyệt, qua mọi test. Lên production thì một loạt exception kích hoạt sự cố, phải rollback ngay. Theo bài, code đổi không sai; vấn đề là việc code đã đổi: beta flag được cache, mà Marshal ghi tên class cùng dữ liệu. Code mới ghi object với class mới vào cache, code cũ (còn chạy trong lúc deploy) đọc và chết vì class không tồn tại.
Thay đổi chính
- Hai cách giảm rủi ro đều bị loại: cache ít thứ hơn (mất lợi ích của cache), hoặc đổi code ít hơn (trái với mục tiêu làm code sạch).
- Chọn sửa gốc: thay Marshal bằng định dạng mình kiểm soát được và không cache được object tuỳ ý: MessagePack (gọn hơn, kiểu chặt hơn).
- Phần còn lại của bài giải thích Marshal "mã hoá cả vũ trụ": đệ quy qua object và tham chiếu, ghi tên class, biến instance (kể cả trên String/Array/Hash qua
TYPE_IVAR), tham chiếu vòng (TYPE_LINK), lớp con của kiểu lõi (TYPE_UCLASS). Một record Post đơn giản thành payload khoảng 1.600 byte, tên bài xuất hiện ba lần. Đây là những thứ sẽ vỡ khi bỏ Marshal và phải tự làm lại.
Vì sao
- Trong lúc deploy luôn có hai phiên bản code cùng đọc ghi một cache; định dạng gắn chặt với cấu trúc class biến mọi refactor thành rủi ro tương thích (Cache và invalidation, Deploy và release an toàn).
Bài học cho SWE
- Dữ liệu dùng chung giữa các phiên bản (cache, queue) phải tương thích cả hai chiều trong lúc deploy, giống schema DB.
- Định dạng serialize "tiện" (Marshal, pickle, Java serialization) ghi chi tiết nội bộ vào dữ liệu; đổi chi tiết đó là phá dữ liệu.
- CI không bắt được lỗi chỉ xuất hiện khi hai phiên bản chạy cùng lúc.
Liên quan
#Rails cache#Marshal#Serialization#Memcached#Deploy incident#Mixed versions#Class name in payload#MessagePack
Được nhắc tới trong
Công ty (1)
Bài tóm tắt (4)