Bản sao lưu của bạn đang âm thầm hồi sinh những người dùng bạn đã xóa
Mọi bản sao lưu tăng dần đều dựa trên cùng một giả định thầm lặng: muốn sao lưu những gì đã thay đổi, hãy tìm những dòng đã thay đổi. Trên một kho key-value như Azure Table Storage hay DynamoDB, "những gì đã thay đổi" nghĩa là "những dòng có timestamp sửa đổi mới hơn watermark lần trước của tôi." Quét bảng, vơ mọi thứ mới hơn, ghi ra. Nhanh, rẻ, đúng.
Đúng với thao tác ghi. Giờ hãy xóa một dòng.
Dòng đó không được gắn cờ "đã xóa". Nó không nhận timestamp mới hơn. Nó không chuyển vào thùng rác. Nó chỉ đơn giản ngừng tồn tại. Các kho này không có delete marker và không có change feed cho thao tác xóa, nên một dòng bị xóa không để lại đúng thứ gì cả. Bản sao lưu tăng dần của bạn, vốn tìm thay đổi bằng cách quét các timestamp mới hơn, quét lướt qua khoảng trống nơi dòng đó từng nằm và không thấy gì. Chẳng có gì để thấy. Thao tác xóa là vô hình.
Nghĩa là bản sao lưu của bạn vẫn chứa dòng đó. Và đây là chỗ một câu chuyện mất dữ liệu biến thành một câu chuyện bảo mật.
Hãy nghĩ xem một thao tác xóa thường mang nghĩa gì trong một hệ thống xác thực. Bạn không xóa người dùng đó cho vui. Bạn cho một nhân viên nghỉ việc. Bạn gỡ một tài khoản có mật khẩu xuất hiện trong một kho dữ liệu rò rỉ. Bạn thu hồi một OAuth grant sau khi token bị lộ. Bạn rút quyền của một admin đúng ngày họ rời đi. Từng cái một đều là quyết định bảo mật, và không cái nào sống sót qua một bản sao lưu không nhìn thấy thao tác xóa.
Rồi bạn khôi phục. Có thể từ một thảm họa thật, có thể chỉ để dựng một bản clone cho staging. Bản sao lưu làm đúng điều bạn yêu cầu: nó đặt lại mọi dòng nó biết. Nhân viên đã nghỉ lại thành người dùng. Mật khẩu bị lộ lại hợp lệ. Grant đã thu hồi lại chạy được. Admin đã bị gỡ lại có quyền admin. Bản khôi phục của bạn không làm mất dữ liệu. Nó đảo ngược các quyết định bảo mật của bạn, trong im lặng, và trao cho bạn một hệ thống trông khỏe mạnh nhưng đang âm thầm bị xâm phạm. Một bản sao lưu quên mất thao tác xóa còn tệ hơn không có bản sao lưu nào, bởi vì bạn tin nó.
Cách sửa là ngừng coi thao tác xóa như sự vắng mặt của một dòng và bắt đầu coi nó như một sự kiện. Xóa cũng là dữ liệu.
Vì vậy chúng tôi cho thao tác xóa một bảng riêng. Mọi thao tác xóa trong hệ thống đều đi qua một ITombstoneWriter được inject, ghi lại một tombstone: khóa của dòng, và thời điểm nó chết. Không tồn tại đường code nào xóa một dòng mà không để lại tombstone, bởi thao tác xóa và tombstone là một thao tác duy nhất. Một bản sao lưu tăng dần khi đó gồm hai phần được chụp tại cùng một watermark: các upsert (dòng có timestamp mới hơn) và các tombstone (các thao tác xóa kể từ watermark trước). Khôi phục phát lại cả hai theo thứ tự thời gian, nên một thao tác xóa được áp dụng y như một thao tác ghi, và một khóa từng bị xóa rồi sau đó được tạo lại sẽ chốt theo cái nào xảy ra sau cùng. Khoảng trống rốt cuộc cũng có hồ sơ đính kèm.
Toàn bộ mẹo chỉ có vậy, và nó nhỏ. Lý do nó quan trọng thì không.
Hình hài của vấn đề này sống lâu hơn Table Storage và DynamoDB. Bất kỳ hệ thống nào mô hình hóa thao tác xóa thành "dòng đó biến mất" đều không thể sao lưu, sao chép, hay đồng bộ các thao tác xóa, bởi chẳng có gì để mang theo. Nó lộ ra trong những lần phát lại sự kiện ngây thơ chỉ phát lại create và update. Nó lộ ra trong các cache hết hạn nhưng không bao giờ bị vô hiệu hóa. Nó lộ ra trong các read replica trôi dạt vì thao tác xóa không bao giờ được lan truyền. Và nó nguy hiểm nhất đúng ở nơi thao tác xóa là cách bạn thực thi bảo mật, mà trong một hệ thống định danh thì đó là mọi nơi: thu hồi, offboarding, xoay vòng khóa, khóa tài khoản. Nếu câu chuyện bền vững dữ liệu của bạn chỉ theo dõi những thứ đang tồn tại, nó sẽ trung thành bảo tồn những thứ bạn đã dày công làm cho không còn tồn tại.
Vậy hãy tự kiểm tra bản sao lưu của bạn bằng một câu hỏi: nếu tôi xóa một người dùng ngay bây giờ, tạo một bản sao lưu, rồi khôi phục nó, người dùng đó có biến mất không? Nếu câu trả lời thành thật là "tôi không chắc", bản sao lưu của bạn là một cỗ máy thời gian chĩa nhầm hướng. Nó không bảo vệ bạn khỏi sai lầm của bạn. Nó hồi sinh chúng: mật khẩu bạn đã thay, nhân viên bạn đã cho nghỉ, token bạn đã thu hồi.
Xóa cũng là dữ liệu. Hãy sao lưu chúng đúng như vậy.
Nếu bạn muốn bản sao lưu của mình tôn trọng thao tác xóa mà không phải tự tay chứng minh điều đó, thì đó chính là việc của một nền tảng. Authagonal ghi tombstone cho mọi thao tác xóa, nên một lần khôi phục không bao giờ mang trở lại một thông tin xác thực đã bị thu hồi.