Đây là lỗi tôi đã thấy hai lần, trong hai engine khác nhau. Một lần xuất chạy lúc 10:00 và ghi lại dấu thời gian sửa đổi cuối cao nhất mà nó thấy. Một giao dịch bắt đầu lúc 09:58 vẫn mở, commit lúc 10:03 và mang dấu thời gian từ lúc nó bắt đầu. Lần xuất tiếp theo chỉ yêu cầu các hàng mới hơn 10:00 và không bao giờ thấy nó. Kích thước truyền tải rất tốt còn dữ liệu thì sai.

Lần theo lần xuất đã làm mất một hàng

Lần theo thứ tự sự kiện, không phải SQL. Ứng dụng ghi thời gian sửa đổi của hàng khi giao dịch bắt đầu, không phải khi commit. Bộ xuất đọc dấu nước đồng hồ treo tường trong khi giao dịch đó vẫn mở. Sau đó giao dịch commit với thời gian sửa đổi cũ hơn dấu nước đã lưu. Lô tiếp theo của người tiêu thụ bắt đầu sau dấu nước, nên hàng nằm sau con trỏ và sẽ không bao giờ được chọn lại.

Không có gì ghi lỗi, vì không có gì thất bại. Đó là điều khiến loại lỗi này đắt: luồng delta nhanh, số lượng hàng trông hợp lý, và hàng bị thiếu nổi lên nhiều tuần sau như một phiếu đối soát mà không ai tái tạo được.

Số thứ tự có cùng dạng khuyết điểm vì lý do khác. ID đơn điệu cho bạn biết thứ tự cấp phát giá trị, không phải thứ tự commit của giao dịch. Một giao dịch lấy số thấp có thể commit sau giao dịch lấy số cao, nên con trỏ dựa trên thứ tự cấp phát cũng có thể để lại lỗ hổng.

Năm lời hứa mà luồng phải đưa ra

Trước khi chọn phương thức truyền, hãy yêu cầu hệ thống nguồn một hợp đồng năm điều khoản. Nếu thiếu bất kỳ điều khoản nào, bạn có một suy đoán chứ không phải luồng thay đổi.

  • Độ phủ: chèn, cập nhật và xóa, mỗi loại với khóa ổn định cần thiết để áp dụng.
  • Ranh giới: giá trị con trỏ có nghĩa gì và một lô nhất quán chứa những gì.
  • Nhất quán: cách đọc các bảng liên quan mà không trộn các trạng thái nguồn không tương thích.
  • Lưu trữ: người tiêu thụ bị ngắt kết nối có thể tiếp tục từ vị trí đã lưu trong bao lâu.
  • Khởi tạo lại: một ảnh chụp đầy đủ được hỗ trợ khi vị trí đó không còn hợp lệ.

Một cơ chế được hỗ trợ có thể đáp ứng cả năm. Tài liệu của SQL Server về theo dõi thay đổi là một ví dụ công bố cụ thể: nó định nghĩa phiên bản hợp lệ tối thiểu, ghi lại việc xóa cũng như thay đổi, và mô tả một giao dịch ảnh chụp bao trùm việc xác thực, ghi nhận phiên bản và các truy vấn thay đổi liên quan. Đó là ví dụ về điều cần đòi hỏi từ nguồn, không phải cú pháp để dán vào engine khác.

Thiết kế điểm kiểm tra như một phần của đường ống

Vị trí đã lưu của người tiêu thụ chính là máy trạng thái thực sự, nên hãy viết nó như vậy. Con trỏ chỉ được tiến lên thông qua quy trình đã áp dụng lô và đã commit giao dịch đích.

cursor  = durable_checkpoint()          # last fully applied position
batch   = extract(cursor, upper_bound)  # one consistent batch
apply(batch)                            # idempotent at the target
commit()
checkpoint(batch.upper_bound)           # only now

Nếu việc giao hàng thất bại giữa chừng, hãy đối soát chính lô đó thay vì phát minh vị trí nguồn mới. Trích xuất lại với cận trên mới hơn là con đường khiến việc áp dụng một phần thành lỗ hổng vĩnh viễn. Quy tắc gương cũng đúng ở phía bên kia: áp dụng idempotent tại đích ngăn bản trùng và không làm gì cho thay đổi mà việc trích xuất chưa bao giờ thấy.

Việc xóa cần bản ghi, không phải suy luận

So sánh các hàng còn tồn tại không thể cho người tiêu thụ biết khóa nào đã biến mất. Một nguồn không bao giờ ghi việc xóa để lại hai lựa chọn không hoàn hảo: giữ lịch sử khóa đủ lâu để so sánh, hoặc chạy đối soát đầy đủ rõ ràng theo lịch. Cả hai đều là quyết định thiết kế có chi phí, và không cái nào tồn tại nếu không ai sở hữu.

Lưu trữ cũng là loại quyết định đó. Mỗi luồng thay đổi được hỗ trợ đều có một cửa sổ; hãy khai báo nó trong hợp đồng và cảnh báo khi điểm kiểm tra của người tiêu thụ đến gần. Người tiêu thụ thức dậy sau hai tuần gián đoạn nên đọc lỗi rõ ràng "cần khởi tạo lại" thay vì âm thầm nhận một lô một phần.

Sau đó đo xem delta có đáng giá không

Quay lại so sánh từng khóa và hash đôi khi là đúng, và đáng để biết chi phí. Bạn vẫn truyền thông tin về từng hàng, hash không cho bạn ảnh chụp nhất quán giữa các bảng, và một sơ đồ hash mang theo câu hỏi riêng về biểu diễn và xung đột. Ít byte hơn với ranh giới có thể kiểm chứng là mục tiêu; ít byte hơn mà âm thầm đánh rơi một thay đổi đã commit thì không phải delta.

Cột sửa đổi cuối là một gợi ý. Một con trỏ sống sót qua commit muộn, việc xóa và gián đoạn dài là một hợp đồng.

Bài viết liên quan